I've seen in some other simple 2D games that a "tick" method is used to sync game logic and graphics rendering. My main reason for using this is due to my collision detection malfunctioning, since the player entity will completely pass through solid objects unless I tap the controls almost pixel-by-pixel to collide the rectangles.
I figure a tick method will slow the games rapid updating enough to pick up these slight collision detections.
How do I create such a method? I've tried the code you can see below, however, it is causing the entire game to freeze:
The update method:
@Override
public void update(float deltaTime) {
List touchEvents = game.getInput().getTouchEvents();
long lastTime = 0;
long currentTime = 0;
if (state == GameState.Ready) {
updateReady(touchEvents);
}
while (state == GameState.Running) {
lastTime = currentTime;
currentTime = System.currentTimeMillis();
deltaTime = currentTime - lastTime;
player.update(touchEvents, deltaTime);
repaint(deltaTime);
}
if (state == GameState.Paused) {
updatePaused(touchEvents);
}
if (state == GameState.GameOver) {
updateGameOver(touchEvents);
}
}
The repaint method, which is updated while the regular paint method does nothing. I've tried the while loop with both, doesn't seem to stop freezing:
public void repaint(float deltaTime) {
Graphics g = game.getGraphics();
if(deltaTime >= 60) {
g.drawRect(0, 0, 805, 485, color.black);
map.loadMap(getXScroll(), getYScroll(), g, game);
map.loadEntities(getXScroll(), getYScroll(), g, game, map);
g.drawImage(Assets.bitSoldier, 448, 256);
g.drawImage(Assets.dpad, 0, 280);
// Secondly, draw the UI above the game elements.
if (state == GameState.Ready)
drawReadyUI();
if (state == GameState.Running)
drawRunningUI();
if (state == GameState.Paused)
drawPausedUI();
if (state == GameState.GameOver)
drawGameOverUI();
}
}
Answer
In general, there are two ways to make game logic "tick":
- Fixed time steps run a fixed number of times per second, for example 100 times or maybe even 1000 times.
- Dynamic time steps run the game logic whenever possible, considering the time passed since the last update.
Both approaches got their advantages and disadvantages, depending on what you're trying to achieve.
For movement and such, dynamic timesteps might be better, but for things such as animating pixel graphics, fixed timesteps might be more interesting. You can mix and match both as you like.
In general, as I mentioned in the comments, you should never let your program sleep in the game loop. This slows down the game without any reason and might even create stutter despite the computer being powerful enough to actually run the game without slowdowns.
Your generic game loop should look a bit like this (pseudo code):
function mainloop() {
double time_passed = 0;
double delta_time = 0;
while (running) { // keep running
// update game logic based on time passed
updateDynamicStep(delta_time);
// update game logic once for every tick passed
while (time_passed >= time_per_timestep) {
updateFixedStep();
time_passed -= time_per_timestep;
// You might limit the number of iterations here (like 10)
// to not get stuck due to processing taking too long (and time adding up)
}
// draw screen content
drawStuff(delta_time);
// update timing
delta_time = getTimePassedAndResetTimer();
time_passed += delta_time;
}
}
Doing it that way - no matter whether you use fixed time steps or not - has the advantage that your game will always run at the same speed, no matter whether you're running at 60 fps, 100 fps, 5000 fps, or only 15 fps.
The only reason to force sleeps could be to save battery (e.g. mobile games), but again I wouldn't sleep for fixed time, just sleep based on the time this iteration took and the time you planned for one frame. For example, if updating your game and drawing takes 10 ms and you plan on running at 60 frames per second, sleep for 5 ms (15ms total; perfect time would be 16.67ms, but you're leaving some space for other stuff like context switches and the like).
No comments:
Post a Comment