0

我需要通过特定方式在我的应用程序中组织渲染循环(这是有原因的)。

假设我有

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];
}

Graphics.update应该渲染一帧并延迟执行(不渲染)直到下一帧

@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

它以某种方式工作并且精灵正在移动。但是当我回家时 applicationWillResignActive 没有被调用,当我回到应用程序时出现黑屏,一段时间后应用程序崩溃。

这是我尝试移植的内容:https ://bitbucket.org/lukas/openrgss/src/7d9228cc281207fe00a99f63b507198ea2596ead/src/graphics.c (Graphics_update函数)

4

2 回答 2

2

您可以尝试使用 Core Animation DisplayLink 而不是 while 循环。这就是它通常在图形框架中完成的方式。currentRunLoop 每 1/60 秒调用一次更新方法。

如果使用 NSRunLoop,您应该删除更新中的睡眠调用。

CADisplayLink *displayLink;

// Set your update method
displayLink = [CADisplayLink displayLinkWithTarget:[Graphics class] 
                                          selector:@selector(update)];
// Set fps to device refresh rate (60)
[displayLink setFrameInterval:1.0f];

// Add your display link to current run loop
[displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];

// Stop updating
[displayLink invalidate];

最后一行停止执行,所以在完成循环之前不要调用它。

于 2013-01-03T10:32:37.770 回答
1

如果你使用 Sparrow,你应该这样处理它:

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 使用 SP_ENTER_FRAME_EVENT 为您管理游戏循环。每次需要再次渲染时都会调用它。大约每秒 30 次(尽管可以配置)。

于 2013-01-20T17:27:09.517 回答