Search code examples
iossparrow-framework

Rendering loop in a game


I need to organize rendering loop in my app by a specific way (there is a reasons).

Let's say I have

Sprite *sprite = [[Sprite alloc] initWithContentsOfFile:@"sprite.png"]; // some sprite

while (true) {
    [Graphics update];
    sprite.x = (sprite.x + 1) % 1024 // moving sprite by one pixel each frame
    [Input update];
    [self update];
}

There Graphics.update should render one frame and delay execution (not rendering) until next frame

@interface Graphics () {
    static BOOL _frozen;
    static int _count;
    static int _frameCount;
    static float _frameRate;
    static double _lastFrameTimestamp;
}

@end

@implementation Graphics

+ (void)initialize {
    _frozen = NO
    _count = 0
    _frameCount = 0
    _frameRate = 30.0
    _lastFrameTimestamp = CACurrentMediaTime()
}

+ (void)freeze {
    _frozen = YES;
}

+ (void)update {
    if _frozen
      return
    end

    Video.nextFrame // some OpenGL ES magic to render next frame

    _count++

    now = CACurrentMediaTime()
    waitTill = _lastFrameTimestamp + _count * (1.0 / _frameRate)

    if now <= waitTill
      sleep(waitTill - now)
    else
      _count = 0
      _lastFrameTimestamp = CACurrentMediaTime()
    end

    _frameCount++
}

@end

Somehow it works and sprite is moving. But when I go to home applicationWillResignActive isn't called and when I go back to app there is black screen and after some time app crashes.

Here is the thing I try to port: https://bitbucket.org/lukas/openrgss/src/7d9228cc281207fe00a99f63b507198ea2596ead/src/graphics.c (Graphics_update function)


Solution

  • If you are using Sparrow, this is how you should be handling it:

    SPSprite *sprite = [[SPSprite alloc] initWithContentsOfFile:@"sprite.png"]; // some sprite
    
    [self addEventListener:@selector(enterFrame:) atObject:self forType:SP_EVENT_TYPE_ENTER_FRAME];
    
    -(void)enterFrame:(SPEnterFrameEvent*)e {
        [Graphics update];
        sprite.x += 1; // moving sprite by one pixel each frame
        [Input update];
        [self update];
    }
    

    Sparrow manages the game loop for you using an SP_ENTER_FRAME_EVENT. It will be called every time it's time to render again. Roughly 30 times per second (though it can be configured).