7
\$\begingroup\$

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<TouchEvent> 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();
        }
    }
\$\endgroup\$
5
  • \$\begingroup\$ Related: gamedev.stackexchange.com/questions/1589/… and gafferongames.com/game-physics/fix-your-timestep \$\endgroup\$ Commented Jun 7, 2013 at 2:44
  • \$\begingroup\$ You're sleeping for 100 ms between simulations, I'd recommend from personal experience that the maximal you should sleep for is 40ms. \$\endgroup\$
    – Shaun Wild
    Commented Jun 7, 2013 at 3:39
  • 1
    \$\begingroup\$ Ideally, you shouldn't sleep at all - update your logic as often as possible (smaller time steps also lower the chance of such ghosting). Assume you're intentionally sleeping for 40ms, your rendering/updating takes 10ms - you're at 50 ms per cycle, which might essentially limit you to 20 frames per second without any significant reason. \$\endgroup\$
    – Mario
    Commented Jun 7, 2013 at 11:53
  • \$\begingroup\$ This is a well-known field, with two IMNSHO best discussions on it being by Robert Nystrom in his "Game Programming Patterns" book (see gameprogrammingpatterns.com/game-loop.html) and Glenn Fiedler (gafferongames.com/post/fix_your_timestep). \$\endgroup\$ Commented Oct 30, 2017 at 9:52
  • \$\begingroup\$ Between the answers/related links/books and being a more experienced game dev, it's clear I and others have the resources now to do this correctly. Thanks for the help! \$\endgroup\$
    – A13X
    Commented Oct 31, 2017 at 17:28

1 Answer 1

12
\$\begingroup\$

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).

\$\endgroup\$
9
  • \$\begingroup\$ I especially liked the bit about mobile games since I'm designing an android app game. However, I'm not the best at deciphering pseudo-code-where would the variable time_per_timestep derive from? \$\endgroup\$
    – A13X
    Commented Jun 7, 2013 at 21:24
  • \$\begingroup\$ That's something you define, essentially it depends on your timer resolution, i.e. it's the time between update calls. For example, let's assume the timer represents milliseconds and you want 100 updates per second, you'd use time_per_timestep = 1000.0 / 100;. \$\endgroup\$
    – Mario
    Commented Jun 8, 2013 at 8:55
  • \$\begingroup\$ Here's another predicament...the while loop seems to freeze the game and it doesn't repaint the screen or allow any interaction. Perhaps it has to do with the mobile platform and the way I am using the Activity or something that its blocking out important processes always running during the app? \$\endgroup\$
    – A13X
    Commented Jun 9, 2013 at 0:01
  • 2
    \$\begingroup\$ You misunderstood the framework calling update() and repaint(). These essentially work already in such a way I described in my example (these are essentially updateDynamicStep() and drawStuff()). You're essentially trying to nest a main loop in a main loop, which won't work. You have to leave update() for the framework to redraw and accept events. \$\endgroup\$
    – Mario
    Commented Jun 9, 2013 at 9:04
  • 1
    \$\begingroup\$ In theory, variable timesteps are all fine and dandy. However in practice, both Robert Nystrom in his seminal book "Game Programming Patterns" (gameprogrammingpatterns.com/game-loop.html) and Glenn Fiedler Himself (gafferongames.com/post/fix_your_timestep) warn about instability and significant risks of variable time steps (semi-fixed time steps is a different story though). \$\endgroup\$ Commented Oct 30, 2017 at 9:50

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .