我在Android中运行JNI的C ++游戏。由于场景复杂性,帧速率从大约20-45fps变化。任何高于30fps的东西对于游戏都是愚蠢的;它只是燃烧电池。我想将帧速率限制为30 fps。
API中是否隐藏了“capFramerate()”方法?有任何可靠的方法吗?
答案 0 :(得分:38)
Mark的解决方案几乎是好的,但并不完全正确。问题是交换本身需要相当长的时间(特别是如果视频驱动程序是缓存指令)。因此,您必须考虑到这一点,否则您将以低于预期的帧速率结束。 事情应该是:
一开始的某个地方(比如构造函数):
startTime = System.currentTimeMillis();
然后在渲染循环中:
public void onDrawFrame(GL10 gl)
{
endTime = System.currentTimeMillis();
dt = endTime - startTime;
if (dt < 33)
Thread.Sleep(33 - dt);
startTime = System.currentTimeMillis();
UpdateGame(dt);
RenderGame(gl);
}
这样你就会考虑交换缓冲区所需的时间和绘制帧的时间。
答案 1 :(得分:9)
使用GLSurfaceView时,在Renderer的onDrawFrame中执行绘图,该绘图由GLSurfaceView在单独的线程中处理。只需确保每次调用onDrawFrame都需要(1000 / [帧])毫秒,在你的情况下需要33毫秒。
要执行此操作:(在onDrawFrame中)
就是这样。
答案 2 :(得分:2)
Fili's answer对我来说很好看,很遗憾地将我的Android设备上的FPS限制为25 FPS,尽管我要求30。我发现Thread.sleep()
工作不够准确并且睡眠时间比它长应该。
我从LWJGL项目中找到了这个实现来完成这项工作: https://github.com/LWJGL/lwjgl/blob/master/src/java/org/lwjgl/opengl/Sync.java
答案 3 :(得分:0)
Fili的解决方案对某些人来说是失败的,所以我怀疑它一直在下一次vsync之后而不是之前就已经睡了。我还觉得将睡眠移动到函数的末尾会产生更好的结果,因为它可以在下一个vsync之前填充当前帧,而不是尝试补偿前一个。 Thread.sleep()是不准确的,但幸运的是我们只需要精确到最近的vsync周期为1/60秒。 LWJGL代码tyrondis在这种情况下发布了一个似乎过于复杂的链接,它可能是为了在vsync被禁用或不可用时设计的,在这个问题的上下文中不应该这样。
我会尝试这样的事情:
private long lastTick = System.currentTimeMillis();
public void onDrawFrame(GL10 gl)
{
UpdateGame(dt);
RenderGame(gl);
// Subtract 10 from the desired period of 33ms to make generous
// allowance for overhead and inaccuracy; vsync will take up the slack
long nextTick = lastTick + 23;
long now;
while ((now = System.currentTimeMillis()) < nextTick)
Thread.sleep(nextTick - now);
lastTick = now;
}
答案 4 :(得分:-3)
您也可以尝试从onSurfaceCreated()中减少线程优先级:
Process.setThreadPriority(Process.THREAD_PRIORITY_LESS_FAVORABLE);