C++ / SDL动画速度

3

我正在做一款游戏,跟随在线教程。目前我已经在系统中添加了一些FPS,还有一个简单的动画,它使用精灵的部分,就像这样:

if( frameCount > 12 )
        frameCount = 0;

    //hero frames   
    SDL_Rect clip[ 13 ];

    clip[ 0 ].x = 0;
    clip[ 0 ].y = 0;
    clip[ 0 ].w = 44;
    clip[ 0 ].h = 39;

    clip[ 1 ].x = 51;
    clip[ 1 ].y = 0;
    clip[ 1 ].w = 44;
    clip[ 1 ].h = 39;

    clip[ 2 ].x = 102;
    clip[ 2 ].y = 0;
    clip[ 2 ].w = 44;
    clip[ 2 ].h = 39;
    ...
    ...
    SDL_BlitSurface( hero, &clip[ frameCount ], destination, &offset );
    frameCount++;

现在这个程序可以完美运行,while循环的每次迭代都会播放动画中的下一帧(顺便提一下,这个动画是角色类的一部分)。
我面临的问题是动画的速度。它以游戏当前的FPS为速度,这个FPS是60。我想单独控制玩家动画的速度,这样我就可以把它的速度降到合理的范围内。
有人能提供关于如何实现这一点的建议吗?
注:总共有13帧。
2个回答

8
你需要将刷新率(60 fps)与动画速率分开。在我看来,最好的解决方案是将动画速率绑定到实时时钟上。在SDL中,你可以使用SDL_Ticks()函数来测量毫秒分辨率的时间。
例如,考虑以下示例(不是可运行代码,只是一个草图):
void init() {
    animationRate = 12;
    animationLength = 13;
    startTime = SDL_Ticks();
}

void drawSprite() {
    int frameToDraw = ((SDL_Ticks() - startTime) * animationRate / 1000) % animationLength;
    SDL_BlitSurface( hero, &clip[ frameToDraw ], destination, &offset );
}

如果不清楚,frameToDraw变量的计算是通过计算动画开始播放后经过的时间。将其乘以动画速率,得到以动画速率为基础的绝对帧数。然后应用模运算符将此数字减少到动画长度范围内,这将给您所需的帧在该时间绘制。
如果您的刷新率低于动画速率,则精灵会跳过帧以保持所请求的动画速率。如果刷新率更快,则同一帧将被重复绘制,直到显示下一帧的时间到来。
希望这有所帮助。

它实际上被称为 SDL_GetTicks(),而不是 SDL_Ticks(),对吧? - hbobenicio

2

米格尔写的很好。你可以使用另一种方法,即使用计时器,在特定频率触发计时器,在该频率中递增精灵索引。

请注意,您应该始终将渲染和逻辑分开。


我同意,这个解决方案也可以工作,但是如果您的显示速率低于动画速率,它将使用更多的CPU,因为您仍然会以全速更新动画状态。 - Miguel Grinberg
我同意你的方法更快。但是这种方法更通用一些。例如,如果你想在某个时间段内跳过一个精灵变化或者做其他事情,你的公式会变得更加复杂。 - Shahbaz
我在解决方案中处理精灵更改的方式是通过使每个角色跟踪其状态。游戏逻辑触发状态更改,状态更改意味着动画可以停止,或更改为不同的帧集等。每个精灵都知道其可能的状态。实际上非常容易。 - Miguel Grinberg

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接