Dan*_*ore 3 java multithreading android game-loop
我使用下面的代码作为一个简单 Android 游戏的游戏循环。它运行得很好,但游戏中时不时会出现一些小问题。一切都冻结了一秒钟,然后向前跳得比应有的更远。我对游戏循环进行了大量阅读,但在实现平滑循环方面仍然遇到了一些麻烦。插值可以解决这个问题吗?我怎样才能使运动变得平滑?
private final static int MAX_FPS = 30;
private final static int MAX_FRAME_SKIPS = 5;
private final static int FRAME_PERIOD = 1000 / MAX_FPS;
protected Void doInBackground(Void... params) {
Log.d("MainTask", "starting game task");
Canvas canvas;
long begin; // the time when the cycle began
long delta; // the time it took for the cycle to execute
int sleep; // ms to sleep if ahead
int skipped; // number of frames being skipped
sleep = 0;
while (running) {
canvas = null;
try {
canvas = surfaceHolder.lockCanvas();
synchronized (surfaceHolder) {
begin = System.currentTimeMillis();
skipped = 0;
gamePanel.update();
gamePanel.draw(canvas);
delta = System.currentTimeMillis() - begin;
sleep = (int)(FRAME_PERIOD - delta);
if (sleep > 0) {
try {
Thread.sleep(sleep);
} catch(InterruptedException e) {}
}
while (sleep < 0 && skipped < MAX_FRAME_SKIPS) {
gamePanel.update();
sleep += FRAME_PERIOD;
skipped++;
}
}
} finally {
if (canvas != null) surfaceHolder.unlockCanvasAndPost(canvas);
}
}
Log.d("MainTask", "the task is complete");
return null;
}
Run Code Online (Sandbox Code Playgroud)
实际上,您已经正确地完成了此循环的大部分操作。不过,我可以看到一些潜在的陷阱
您没有将帧时间传递给更新方法。这意味着您的更新方法必须假定一定的帧时间。这可能是您跳跃的原因。如果您接近机器的最大性能,您将不会获得恒定的帧速率,您就是不会。这基本上并不重要。如果你错过了一帧,你的大脑就会填补缺失的帧,看起来不错。绝对重要的是可变的物体速度。在这种情况下,可变的帧速率将导致对象的速度可变。您的更新方法应该是:
long previousFrameTime=System.currentTimeMillis();
while (running){
.....
.....
long currentTime=System.currentTimeMillis();
long frameTime=currentTime-previousFrameTime
previousFrameTime=currentTime
gamePanel.update(frameTime/1000.0); //I personally like my frametimes in seconds, hence /1000.0, but thats up to you
.....
.....
}
Run Code Online (Sandbox Code Playgroud)
frametime在确定移动距离时,更新中的所有移动都应考虑到这一点
要说明这一点的重要性,请参阅以下两张图。一个具有假定的帧速率,另一个具有测量的帧速率。点代表实际渲染的帧,线代表观看者大脑中发生的插值。


您持有 Canvas 锁的时间也比必要的时间长得多。在整个更新方法和睡眠过程中,您都锁定了画布。这会降低性能。在开始渲染之前获取锁定并在完成后立即释放它
gamePanel.update();
canvas = surfaceHolder.lockCanvas();
gamePanel.draw(canvas);
surfaceHolder.unlockCanvasAndPost(canvas);
Run Code Online (Sandbox Code Playgroud)| 归档时间: |
|
| 查看次数: |
3145 次 |
| 最近记录: |