oyed
oyed

Reputation: 570

Java Paint Component Refresh Rate?

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.

Upvotes: 2

Views: 1198

Answers (4)

Ozzy
Ozzy

Reputation: 8312

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.

Upvotes: 3

mholzmann
mholzmann

Reputation: 1314

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.

Upvotes: 1

Ozzy
Ozzy

Reputation: 8312

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.

Upvotes: 0

Adam Miller
Adam Miller

Reputation: 1783

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.

Upvotes: 1

Related Questions