I am developing a small Game in Java, and I'm rewriting the Player Movement system to not be Grid-Based. It is a 2D side-scroller, and what I'm trying to achieve is basic Player Movement, so that when the user presses, and holds, the right Key the Player moves right, and the same for the Left Key. The problem I am having is that the Paint Component in another Class draws the image of the Player on the screen, with positions X and Y stored in a Settings Class. Then a KeyListener Class gets when the user is pressing Right, and adds to the X value (And the same for Left, but minuses 1 every time). This creates a slowly moving Character on the screen, and what I want to do is have him move faster without adding more than 1px each time as it would seem like he was skipping pixels (I've already tried).
I was wondering if there was a better way to go about this, as the code I'm using is bare-minimum, and my outcome would be a smoothly moving Player.
KeyListener Snippet:
public void keyPressed(KeyEvent arg0) {
int key = arg0.getKeyCode();
if(key == 39) { // Right Key
Settings.player_pos_x++;
}else if(key == 37) { // Left Key
Settings.player_pos_x--;
}
main.Game.redo();
}
Drawing User on-screen:
g.drawImage(player_image, Settings.player_pos_x, Settings.player_pos_y, this);
Any help is appreciated, if you need any more information or code please feel free to ask.
Let's try again :)
Double buffering
Quote: http://msdn.microsoft.com/en-us/library/b367a457.aspx
Flicker is a common problem when programming graphics. Graphics operations that require
multiple complex painting operations can cause the rendered images to appear to flicker
or have an otherwise unacceptable appearance.
When double buffering is enabled, all paint operations are first rendered to a memory
buffer instead of the drawing surface on the screen. After all paint operations are
completed, the memory buffer is copied directly to the drawing surface associated with
it. Because only one graphics operation is performed on the screen, the image
flickering associated with complex painting operations is eliminated.
Quote: http://docs.oracle.com/javase/tutorial/extra/fullscreen/doublebuf.html
Suppose you had to draw an entire picture on the screen, pixel by pixel or line by
line. If you were to draw such a thing directly to the screen (using, say,
Graphics.drawLine), you would probably notice with much disappointment that it takes
a bit of time. You will probably even notice visible artifacts of how your picture is
drawn. Rather than watching things being drawn in this fashion and at this pace, most
programmers use a technique called double-buffering.
Perhaps you could write the app to iterate multiple redraws to the right, each only 1 or 2 pixels per keyboard input received. This way, you're kind of artificially setting how fast you want it to move. Otherwise, you'd be limited to how the user has their keyboard iteration speed set up.
Also, java's jPanel is not exactly the place to look for video game efficiency. Just saying; you might want to look to something like openGL for that.
At best, you could optimize it to have a transition buffer outside of the jpanel drawing logic, with the same draw functionality as a jPanel, this way you write to the buffer, then copy the whole buffer during a writeImage call... I don't know if you're already doing that, but I think it avoids flicker or something... read about it a long time ago, it's called double buffering.
While double buffering will probably help you should first address how you are calculating the distance you move each time.
Change in distance (dx) can be defined as the velocity(v) times the change in time(dt), dx = v * dt. From what I can see you are omitting dt (change in time). You should calculate the time difference from the last time the character was moved and multiply that by your velocity. This way if your distance processing code is executed 10 time or 100 times in 10 seconds the character will always move the same distance.
The code will look something like this:
int currentTime = System.nanoTime();
int deltaTime = currentTime - previousTime;
Settings.player_pos_x += velX * deltaTime;
previousTime = currentTime;
With this code you will probably need to significantly increase velX. Typically I would have a constant that I would multiply by the velocity so they are smaller numbers.
Additionally if you want better movement and physics look into JBox2D although it's probably over kill for you right now. Their documentation might also help to understand basic physics.
In order to answer your question about the speed, most games i've seen store a global int for the velocity in each plane (x and y planes), then apply the velocity to the current position rather than simply incrementing it as you have done above.
public int velX = 2;
public int velY = 2;
public void keyPressed(KeyEvent arg0) {
int key = arg0.getKeyCode();
if(key == 39) { // Right Key
Settings.player_pos_x += velX;
}else if(key == 37) { // Left Key
Settings.player_pos_x -= velX;
}
main.Game.redo();
}
Once you have that set up, try adding operations which may increase the velocity (i.e. holding the key down for a long time, or something else);
Also, try to implement a jump operation, where the players Y position goes up, and try to add a gravity field to make it come back down.
Related
I'm trying to make a game for J2ME something like the game Zuma, the structure of classes that you need to know is as follow :
-Level class which holds info about a level such as a vector of points (class I made called Point, the path that the balls will follow), vector of balls (class I made called Ball) to hold different balls object, speed (the speed of the balls in that specific level).. (There're more fields but nothing that you need to worry about)
-Frog class (just so you'd know it exists) if you're not familiar wit the game zuma it serves as a controllable turret that can shoot balls.). (No need to worry about the fields in that class)
-MyGameCanvas which obviously extends GameCanvas and implement runnable, holds instance of frog and a level (the currently played level).. (There're more fields but nothing that you need to worry about). The run method serve as a listener for user input if user pressed right rotate the frog (essentially a sprite) by X amount if pressed left rotate by -X amount, pressed OK shoot a ball. Beside taking care of input the thread calls a render method which renders what going on, on the screen and updates balls position from the balls vector (by using the current level instance) using the vector of points (from the level instance aswell), now the problem is that I wanted each level to have different speed, by speed I mean that balls will "roll" (=move) on screen slower, so I can do it with just using the speed value in the Thread.sleep method and increase the sleep time because the run method is taking input from user making the frog movements and input reaction to be slowed down aswell, I thought maybe doing each ball a seperate thread but thats not really good in my opinion because there'll be alot of threads + when I update each ball location on the screen I actually use the WHOLE ball vector from the level instance for things like if a ball need to gove backwards if there's a gap between the ball and the one behind him, or when to render the ball depending if the ball after him is already rendered and on the "track" (the points vector), so I don't really know how I should do it, any advices guidance would be highly appriciated ! Thanks in advance and hopefully you could understand what I wrote.. Also I don't think I need to give code examples really because I don't wanna use what I want to CHANGE what I wrote so it wouldn't really help providing the run/render methods, all you need to know is the structure of the classes I gave you and the fields they have that I told you about.
Various developers use various methods for controlling the speed of sprite-movement.
JavaME is one of the many platforms that requires you to also consider different resolutions and CPU speed. So it's never as simple as just incrementing the x value 1 pixel in each cycle of the main game loop.
Assuming 2 devices with different screen resolution, but otherwise running the same speed. Incremending x value by 1 in the cycle of the game loop, would obviously result in the sprite reaching the end of the screen faster on the small resolution.
Assuming 2 device with the same screen resolkution, but with different CPU's. Incrementing x value by 1 in the cycle of the game loop, would obviously result in the sprite reaching the end of the screen faster on the device with the fastest CPU.
Here is one way of working around that:
Create a variable, call it itemWait (where "item" is the name of the object you want to control the speed for).
The itemWait variable holds a value that tells the game loop how long should pass before next movement.
For example, say that the sprite should wait 40 milliseconds for each pixel it moves. The code would look somewhat like this:
// Variables defined outside the game loop
long lastTime, thisTime;
int cyclems;
int itemTime; // Replace "item" with the name of the object, like e.g. ballTime.
int itemWait = 40; // Wait 40 ms for each movement
int itemPixelsToMove = 1;
while (running == true) { // Game loop
lastTime = thisTime; // Set lastTime to the time-stamp of the previous cycle
thisTime = System.currentTimeMillis(); // Get the current time-stamp
cyclems = (int) (thisTime - lastTime); // How long did it take to execute previous loop
itemTime += cyclems; // How long has passed since last move
while (itemTime > itemWait) { // If it's time to move
itemTime -= itemWait;
moveItem(itemPixelsToMove);
}
// Do other game logic
// Draw everything
// Handle input, unless you handle it with keyPressed()
}
Using that method, the code doesn't care how fast the device is. And if you want to port the game to a different screen resolution, you can simply change either itemPixelsToMove or itemWait.
For example, say you set itemWait = 40; for 240x320 resolutions. Then you would set it to 40/240*480 = 80 for 480x640 resolutions. (This requires of course, that you also scale the graphics).
We've used this approach in www.PirateDiamonds.com - in case you're curious. The same code runs on whatever screen resolution you want.
I am making a simple game that requires to do something similar as in the fruit-ninja game. I am now trying to make the objects fly from the bottom to the screen to the right in a curve, like this (but from a random position instead of the middle):
Because I have so little knowledge in mathematics I am stuck on this for quite some time now. How should I calculate this?
I got it to work in a very simplistic and nasty way, but the object had a static speed, instead of nice smoothing, and even I didn't know what I had just made.
Use initial speed, the launch angle, and the acceleration due to gravity in the kinematics equations.
According to Newtons first law of motion, an object moves with a constant speed in a constant direction unless an external force acts on it. That means each object has a position (represented in X and Y coordinate) which is changed by a vector (represented by speed in x-direction and y-direction) each game-frame. When you get that running, you are already halfway there.
for (GameObject object: gameObjects) {
object.position.x += object.vector.x;
object.position.y += object.vector.y;
}
But in this case, you have a force which affects the objects: Gravity. Gravity is a constant acceleration into the Y-direction. That means the vector is changed every frame by the gravity:
for (GameObject object: gameObjects) {
object.vector.y -= GRAVITY;
object.position.x += object.vector.x;
object.position.y += object.vector.y;
}
Ok so I have a ArrayList which contains all the tiles that need to be drawn to the screen and I have the player that is moved with the arrow keys, but I am unsure how I could implement collision detection with this, Would it be efficient to check if the current tile is filled and if so stop, This is my first time creating a game from scratch so any help is greatly appreciated!
EDIT:
The tiles are 32x32 images which are held in a ArrayList basically if you guys can help me with the y-axis collision i should be fine with the rest.
Tile class contains x, y, and the tile type
EDIT2:I havent tried anything yet, I don't really know where to start but basically i need some sort of Collision on tile, e.g While player is moving if collide on tile do something but i dont know how to check if i have collided or not
Below I have an example of a bouncing ball, which will test for the end of the JPanel, and do something
//x = X-Axis Location //This tests for a collision of the JPanel on the left side or the right side
public boolean isLeavingSideToSide(JPanel jp)
{
if( x <=0 || x+ width >= jp.getWidth())
{
BounceEvent be = new BounceEvent(this);
notifyListeners(be);
return true;
}
else
return false;
}
BounceEvent is created to allow for the notifyListener, which calls the bounced method.
public void notifyListeners(BounceEvent be)
{
for(BounceListener bl : listeners)
{
bl.bounced(be);
}
}
My Bounced method changes the color of the ball (Does some action)
public void bounced(BounceEvent be) {
Ball b = be.getBall();
Color c = b.getColor();
int x = 256;
int newColor1 = (int) (Math.random() * x);
int newColor2 = (int) (Math.random() * x);
int newColor3 = (int) (Math.random() * x);
b.setColor(new Color(newColor1,newColor2,newColor3));
}
Hopefully this will help you get started.
Collision detection isn't matter for beginners, nor can it be fully explained in a Stackoverflow post; if you're still struggling with arrays, try to make simple games, where collision is detected by calculating the distance between objects like circles.
There are many ways to handle collision detection, but you have to be more specific:
what kind of tile-based game are you planning to develop?
I strongly suggest you to read this article, by Katy Coe, which gives a summary of a few implementations. The following methods are explained in the aforementioned blog.
The simplest and most intuitive method is the Pixel Colour Approach, where players can move on tiles with a specific color value, but it can be used only with a limited color palette. The Mask Approach is essentially the same as PCA, but it hides black and white layers behind custom graphics; the latter is computationally expensive and not generally recommended.
The Grid-Based Approach is probably what you're looking for. Each element of the map corresponds to a tile of the grid (described by a 2D array). The player moves in a discrete space, although animation might fake fluid movements.
The Pixel Tile Method describes collisions by sorrounding characters with n control points; this approach let the developer use non-squared characters in a tiled world.
The Bounding Box Method is a simpler implementation of PTM, where the player is wrapped in a rectangle. The program checks whether any of the four corners of the rectangle intersect with any wall.
Discrete Collision Detection, or its improved version, Speculative Contacts, are used in more complex games and you surely don't need those now.
Don't try to learn all at once, start with the simplest implementation you can think of.
Otherwise, you would soon get discouraged and would not appreciate the pro/cons of each technique.
I've recently found this great tutorial about tile-based games with Macromedia Flash, but you can easily apply those techniques using your language of choice. READ IT!
If you want an alternative to Katy's articles, Rodrigo Monteiro comes in help.
I'm currently working on a simple 2D top-down shooter in which you maneuver your character around a map. The graphics are still very much in the "testing" phase (solid colors and rectangles). The drawing process is as follows:
I have the map (this is basically just walls or free space) stored as an integer array which is then looped through and painted onto my JPanel.
Once the map is drawn, I go through each "entity" on the map (powerups, other characters) and place them.
Finally, I draw the user's character
I experimented with different methods, and finally decided that the user's character would stay in the center of the screen with the map moving around it.
Currently, it works but it seems slow. I only have 4 walls, 2 entities, and the user's character being drawn and it's at 90FPS, spiking around 60-70 quite often. This would be acceptable if the game were finished, however I still have fancier graphics, many more entities, walls, bullets, etc. to be rendered onto the map. I've tried increasing the speed of my gameLoop, which can get it as high as 230 FPS, but even then when I move into areas with entities or walls it spikes down to 50-70.
I've tried limiting what is drawn to only what is visible but the results were overall negligible and even negative.
The current paintComponent() method looks something like this:
public void painComponent(Graphics g) {
for(int x = 0; x < Map.size.getWidth() ; x++) {
for(int y = 0; y < Map.size.getHeight(); y++) {
if(mapArray[y][x] == WALL) {
g.setColor(Color.BLACK);
g.fillRect(x, y, wallSize, wallSize);
}
}
}
for(int i = 0; i < map.countEntities(); i++) {
Entity obj = map.getEntity(i);
g.setColor(Color.WHITE);
g.fillRect(obj.getCoords().x, obj.getCoords().y, obj.getSize().width, obj.getSize().height);
}
Robot bot = map.getPlayerBot();
g.setColor(Color.BLACK);
g.fillRect(bot.getCoords().x, bot.getCoords().y, bot.getSize().width, bot.getSize().height);
}
Do any of you gurus out there have any tips to speed this up a bit?
Beyond the answers mentioned in the following links:
Java 2D Drawing Optimal Performance,
Java2D Performance Issues,
Java 2D game graphics
and How to display many SVGs in Java with high performance
A common and simple trick to improve 2D performance is to draw all the static objects ('background') into a buffered image, then when drawing the next image you just offset the pixels of your background image from the previous screen accordingly, then you need only draw the pixels around at most two edges of the screen rather than the entire screen, this only really matters when you're drawing a lot of image layers to the screen.
Beyond all of that make sure you have double buffering enabled so that the drawing doesn't try and draw to the actual screen while you're still drawing the next image.
Seph's answer was taken into consideration and implemented, but it did not increase the speed. Apparently, the image being drawn was not the problem at all. The problem was the timer that I was using to call the update methods. I was using an instance of the Timer class which seems to be very unreliable, especially at small intervals such as these. Upon removing the timer and calling my update methods based on the system clock, I was able to reach and maintain incredibly high FPS.
I'm programming a 2D tile based game in Java like Bomberman (my first game).
I use a 2D array to represent the map where I keep track of walls, walkable spaces, etc. By now I was able to make the player move smoothly swaping sprites depending on the direction key he presses (but not interacting with the background/map, it can walk randomly and get out of the screen).
My problem comes when I want to keep track of the player's position in the array. Logically the character always belongs to only one tile but graphically it can be between two tiles. How can I solve this issue?
I already tried this:
currentTileArrayX = x / tileWidth;
currentTileArrayY = y / tileHeight;
Where x and y are the top-left coordinates of the sprite.
But everything became very buggy because the player's sprites aren't the same size as the tiles.
I had another option in mind that would solve the previous problem: When the player presses a direciton key, move the character to the next tile like an animation. This wouldn't let the player stop in the middle of two tiles... But what if he interrupts it with another key press? How can I stop user's action while the animation is executing? I think this is the easiest solution but I don't know how to implement it.
I already tried to find the solution in other questions but I had no luck. I hope you can help me.
Thanks a lot.
Aaaaaaaaaaaaaaah! Encountering the 'discrete space problem' :) Your logic map is discrete but your UI movements are in the continuous space. I don't the user can actually be in both tiles "at the same time" - visually yes, but never 'internally'. Now you are getting the position of the player and that can be "anywhere" within the tile or "on the boundary" of 2 tiles so to speak...
You have two solutions to this problem, IMO:
Use simple rounding: If the player position is < tile-boundary just keep him on the previous tile. If Greater on the next. Now the problem of boundary - you can use a heuristic, since you shouldn't trust the accuracy of the floating point comparisons (i.e, comparing to 0 is not a good thing to do). So you can try something like this if(currentPosition - boundary <= 0.000000001) then assume it's the next tile else stay on the same one.
Well #Jay beat me to it. So the second one is to actually have a
movement speed defined and move the character that many steps per
'click'/'button press' - but you say you have the problem of key
pressed in "between". I'm guessing if you code is designed like this
then it shouldn't be a problem:
update()
{
calculate(); //update all datastructures/calculations
draw(); //update the visual representation based on calculations
}
update() is a.k.a, gameLoop. I think this should solve your problem...
I'd try to keep the logic part (tile the player belongs to) and the visualization part (animation between tiles) as seperate as possible. My approach would be to have a logical location (tile the player is set on) and a movement speed (which essentially means an amount of time the player isn't allowed to move on to the next tile after moving to a tile). Then the animation from one tile to another would mean that your sprite is always moving towards the screen coordinates of your tile - the time this takes could easily be determined by the movement speed (one full tile movement should take as long as the player has to rest on the current tile).
The only special case would be this "turning around", where you would allow the player to return to the tile he came from at any time, taking only (timeToRecoverOnTile - (timeToRecoverOnTile - timeSinceMovementStarted)).
I once did basically the same thing in AS3, but the concept transfers to Java. I decided to create two main values to help keep track of movement, a Point containing the player's x/y value (by tile), and a direction Point for the movement's direction. Here's some pseudo-code:
if(direction.x == 0 && direction.x == 0) {
if (up) direction.y = -1;
else if (down) direction.y = 1;
else if (left) direction.x = -1;
else if (right) direction.x = 1;
} else {
player.x += direction.x;
player.y += direction.y;
distance--;
if(distance == 0) {
direction.x = direction.y = 0;
distance = tileWidth;
}
}
Obviously, you'd have to tweak that to fit your needs, but that's the basics. Also, tileWidth can be replaced with an integer literal that simply is equal to the width of a single tile.