How to thread in a game

As of right now, I have two threads in my side scrolling marioish game. One is the actual game (Using java.util.Timer and Timer Task). The other is a javax.Timer for the graphics. Its the best solution I have found so far, but there has to be a better way, since the program flickers a few times every 10 seconds.I'm afraid that putting the actual game logic and the graphics in the same thread will actually make the game paint at bad times. I was thinking that I could combine the two threads into a timerTask and paint the offscreen image(I"m double buffering obviously) at the very last moment possible before the next Iteration starts. Could I "pause" until that iteration is almost done and then paint the image. Does anyone know how long it takes to paint a 1024 by 768 BufferedImage(Type_Int_RGB)? Thanks

[820 byte] By [WookieRebela] at [2007-10-2 4:27:29]
# 1
You'll want to double buffer and also keep your timmer, logic, and graphics threads seperate.
morgalra at 2007-7-15 23:56:24 > top of Java-index,Other Topics,Java Game Development...
# 2
I"m confused am I not supposed to have two threads. One graphics and one game logic. What timer thread?
WookieRebela at 2007-7-15 23:56:24 > top of Java-index,Other Topics,Java Game Development...
# 3
> I"m confused am I not supposed to have two threads.Why not? Who is imposing your design requirements?
morgalra at 2007-7-15 23:56:24 > top of Java-index,Other Topics,Java Game Development...
# 4

Threading just introduces problems, in a game there is no need to have more than one thread unless you are networking or playing music or something.

Why can't you integrate the painting and logic code into the one thread? By having two, how do you pause in the logic thread until the graphics thread paints the updated world? It is way easier to have the thread do the logic, then paint it straight away. Then pause for a while if you want or get straight into the next update.

If you are using a timer so that the time between updates is constant, there is no need. You can measure the time intervals between updates using System.nanoTime() and then use this to update the world according to the time that's elapsed. That's what I found is the best solution.

Also, when you paint, are you using 'active' painting or are you calling repaint()? - repaint isn't good for games.

Threads have overhead too so the less the better.

CommanderKeitha at 2007-7-15 23:56:24 > top of Java-index,Other Topics,Java Game Development...
# 5

First, I use two threads because I thought that would make it so that the screen has a constant fps instead of speeding up or slowing down at different points in the game when a variable amount of game logic has to be processed.

Second, why is repainting bad? I never heard that before. How else do I get the graphics object to paint on. Thanks.

WookieRebela at 2007-7-15 23:56:24 > top of Java-index,Other Topics,Java Game Development...
# 6

To get the graphics object to paint on use

Graphics2D g2D = (Graphics2D)theComponent.getGraphics();

//... draw stuff, which will be painted directly to the component and perhaps the screen, beware of any double buffering

or for BufferStrategy:

BufferStrategy strategy = theWindow.createBufferStrategy(2);

Graphics2D g2D = (Graphics2D)strategy.getDrawGraphics();

//... draw stuff

strategy.show();

This is better than repainting since it doesn't rely on the AWT thread to paint the stuff, you do it in your logic thread. When you call repaint it doesn't actually do anything, it just sets a flag that tells the AWT to paint when it feels like it. This is bad since there is likely to be a delay between when the world is ready and the actual painting. What can even happen is that you can do two updates before the AWT paints anything. Also, the double-threading can be bad because to avoid having the logic thread and the graphics thread manipulating the same object at the same time you'll probably need synchronization, which is slow.

Try doing that active rendering in the one thread and don't worry about achieving a constant frame rate because that's inefficient if you want to get the most out of the processor. Let your game objects have speeds in pixels/second and make then have a method update(int millis) which takes an argument of how many milliseconds (or nanos) elapsed since the last update. This will mean that your game can cope with a variable framerate but the objects will appear to move at a constant rate.

For example:

public void run(){

timeLastUpdated = System.nanoTime();

while(shouldRun){

long currentTime = System.nanoTime();

long timeSinceLastUpdate = (currentTime - timeLastUpdated);

scenario.update((float)(timeSinceLastUpdate/1000000000f));

// scenario is the game world, the

// float passed into the method is a time in seconds

// paint the world here

Thread.yield();// let any other threads have a go.

// You can also do Thread.sleep() here too,

// any delay doesn't matter because it will be accounted for by the timeElapsed

timeLastUpdated = currentTime;

}

}

say scenario is just a tank, it could have a speed of 40 pixels/second, so to find how far it has moved after 0.5 seconds have elapsed, just multiply 0.5*40 and that's the distance.

Don't use System.currentMillis() because it has crappy accuracy on windows, always use the nanosecond time.

I hope that's useful.

See you,

Keith

CommanderKeitha at 2007-7-15 23:56:24 > top of Java-index,Other Topics,Java Game Development...
# 7

If I do it so each object moves a certain number of pixels per 100 milliseconds (e.g., 50 pixels per 100 milliseconds ) what do I do when the game logic finishes in 51 milliseconds and it is ready to paint. What should I do? To accompany your method, would It be wise to insert a loop into the code so the thread waits until it gets to a multiple of 100 milliseconds? Right now each object's location is an integer point. Should I change it so it is a double point? Thanks.

WookieRebela at 2007-7-15 23:56:24 > top of Java-index,Other Topics,Java Game Development...
# 8

No sweat,

You should use floats instead of ints for position. Apparently floats are faster than doubles. Use pixels per second as units for speed. You don't have to wait for multiples because if the logic took 51ms instead of 1000 ms (1 second, the unit of speed) then you move the positions by 51/1000 multiplied by the speed (say, 40 pixels per second, so distance moved in this frame will be 40*51/1000 pixels).

Here's a method I use in my game objects. Its all 2D. body, currentBody and bodyAfterAllMoves are just instances of my custom shape class, you can use the equivalent GeneralPath class for these. Just pay attention to how the total distances are calculated, the x and y calculations just break this total distance into the x and y components according the the orientation of the object.

timeElapsed is in seconds and maxSpeed is in pixels/second. direction is 0 for stationary, 1 for forward and -1 for backward.

public void doMove(float timeElapsed){

if (direction != 0){

float bodyDistance = (float)body.points[1distance(body.points[2]);//

distance = direction*timeElapsed*maxSpeed;

distance /= bodyDistance;

float xDist = -(body.points[1].x - body.points[2].x)*distance;

float yDist = -(body.points[1].y - body.points[2].y)*distance;

bodyAfterAllMoves.translate(xDist,yDist);

}

if (turnDirection != 0){

turnAngle = turnDirection*timeElapsed*maxTurnSpeed;

bodyAfterAllMoves.rotate(turnAngle, bodyAfterAllMoves.getCentre());

}

currentBody = bodyAfterAllMoves;

}

// this is the rectangle that is the shape of the object (its meant to be a tank), its initialised in the constructor. points[0] and [1] are the front face of the tank.

Point2D.Float[] points = new Point2D.Float[4];

points[0] = new Point2D.Float(25f,0);

points[1] = new Point2D.Float(0,0);

points[2] = new Point2D.Float(0, -50f);

points[3] = new Point2D.Float(25f,-50f);

body = new KPolygon(points);

CommanderKeitha at 2007-7-15 23:56:24 > top of Java-index,Other Topics,Java Game Development...