Search code examples
loopscocos2d-iphonegame-loop

Cocos2D Game Loop Clarifications


NOTE: I am not a native English speaker. Please excuse any grammar mistakes.

I developed a simple game where there's a shooter on the left and enemies coming from the right.. Very simple.

The project is almost finished, it works perfectly, but now i have some doubts about the game loop management.

I scheduled the enemies appearing from the right giving the scheduler a interval, and it's ok, but i managed the movement of enemies from right to left with a simple ccMoveTo action, and i repeat: it works perfectly. The problem is that i read something about "render the sprites in every frame" delegating this operation to a scheduled method that runs one time per frame..

Better: i read about to not use an Action to move sprites, but re-render them frame by frame simulating the movement in a scheduled method called with the 1/60 frequency, (the fps frequency) and i read that this implementation could prevent some differences of stability in different hardware systems..

What i ask is:

  • is that the right way to proceed?
  • is that an old "design pattern" that is obsolete with Cocos2D? (and this would mean that using the ccMoveTo actions is completely perfect)
  • or are both implementations correct at the same level?

EDIT:

-the same technique should be used for the animations too?


Solution

  • First of all, if it "works perfectly" and your game is almost finished, don't change your game. If you change things now you run the risk of creating subtle changes to your gameplay, your game will take longer to finish, and at the end the players probably won't even notice the difference. You can try a different approach next time, but for your current game as long as all is well, leave it as is.

    I believe what you've read was what I too would say: don't use CCMoveTo/CCMoveBy for (complex) movement of gameplay objects. CCMove actions are ok if the movement is very simple, or one-shot from A to B. But even then an update loop updating the position is just as simple to implement.

    The problem with CCMove actions is their behavior when you want to change the direction and/or speed. In that case you'd have to create a new move action. If you do this frequently, you'll add a lot more alloc/dealloc cycles into your game than would be necessary. Secondly, CCMove actions take one frame of inactivity before they have any effect. That means if you create a new CCMove action every frame, that game object would effectively be stuck and not moving at all. If you change it less frequently, you'd still notice a short pause every time the object changes speed or direction. Neither is desirable.

    The alternative is not as complex as you make it sound. Yes, you need to schedule an update in a moving game object, like so:

    [self scheduleUpdate];
    

    Then implement the update method where you update the node's position:

    -(void) update:(ccTime)delta
    {
        self.position = CGPointMake(self.position.x + 1, self.position.y);
    }
    

    More flexible movement typically uses a velocity vector (CGPoint, typically instance variable) which determines speed and direction of the movement:

    -(void) update:(ccTime)delta
    {
        self.position = ccpAdd(self.position, self.velocity);
    }
    

    Now you can get a lot more dandy with how you add velocity to position, and how to update velocity itself. For example you could cap the velocity to make sure your objects never move faster than x pixels per second. You could also add a simulated gravity by reducing velocity.y every frame. And a lot more. The basic principle remains the same.

    The only truly different alternative is where you take the delta time between updates into account. This ensures that the node travels the same distance over time regardless of framerate. Meaning if the framerate drops from 60 to 20 fps, the node will still travel the same distance but will move several pixels more per frame to make up for the lost time. Without factoring in delta time the node would simply slow down as framerate drops.

    Integrating delta time is a simple multiplication:

    -(void) update:(ccTime)delta
    {
        self.position = ccpAdd(self.position, ccpMult(self.velocity, delta));
    }
    

    However, most games should not use time delta. It can lead to rather unpredictable results, including huge jumps in the game world simulation should the device be busy for a tenth of a second or more, for example if it receives an email or SMS.

    Most games should rather slow down then trying to make up for "lost" time. The problem is that during that time the player can't react any faster (to the contrary), so that advancing the game world simulation faster than normal is unfair to players and can lead to premature loss of limbs or life.