在我的游戏中,我有多个线程。一个线程向计算线程发送信号,该线程收到信号后,也渲染游戏。
主线程看起来像这样,我改编自我见过的其他一些游戏循环:
while(isRunning) {
long now = System.nanoTime();
float elapsed = (now - mStartTime) / 1000000000f;
mStartTime = now;
try {
Log.d("GameThread", "setElapsed = "+elapsed);
mController.setElapsedTime(elapsed);
// send signal to logic barrier to start logic-threads
BaseThread.LogicBarrier.await(); // 1/4
// logic done!
BaseThread.AfterLogicBarrier.await(); // 1/4
// render!
Log.d("GameThread", "RENDERING! -> localTime="+localTime+", Options.TIMESTEP="+Options.TIMESTEP+", interpol = "+(Options.TIMESTEP / localTime));
mController.render((localTime / Options.TIMESTEP));
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
// sleep maybe
diff = System.nanoTime() - mStartTime;
mController.fireGameDataChange(GameDataListener.FPS, (int) 1000000000/diff);
if (1000000000 * Options.TIMESTEP - (diff) > 1000000) {
try {
Thread.sleep(0, 999999);
} catch (InterruptedException ex) {
}
}
}
对于每个存在的 ViewObject,呈现函数如下所示:
mMatrix.reset();
mMatrix.setTranslate(view.getX() - view.getVelocityX() * interpolation), view.getY() + view.getVelocityY)) * interpolation));
mMatrix.preScale((1.0f * view.getWidth() / mBitmap.getWidth()), (1.0f * view.getHeight() / mBitmap.getHeight()));
mMatrix.postRotate(view.getRotation(), view.getX() + view.getWidth()/2f, view.getY() + view.getHeight()/2f);
mCanvas.drawBitmap(mBitmap, mMatrix, mBasicPaint);
这是逻辑线程中发生的事情:
while(isRunning) {
try {
BaseThread.LogicBarrier.await(); // 3/4
int numSubSteps = 0;
if (Options.SKIP_TICKS != 0) {
// fixed timestep with interpolation
localTime += mController.getElapsedTime();
Log.e("Environment", "localTime="+localTime+" >= "+Options.TIMESTEP+", from elapsed = "+mController.getElapsedTime());
if (localTime >= Options.TIMESTEP) {
//numSubSteps = (int) (localTime/Options.TIMESTEP);
numSubSteps = (int) (localTime/Options.TIMESTEP);
localTime -= numSubSteps * Options.TIMESTEP;
}
}
Log.e("EnvironmentThread", "localTime="+localTime+", numSub="+numSubSteps);
if (numSubSteps != 0) {
// clamp the number of substeps, to prevent simulation grinding spiralling down to a halt
int clampedSubSteps = (numSubSteps > Options.SKIP_TICKS) ? Options.SKIP_TICKS: numSubSteps;
for (int i = 0; i < clampedSubSteps; i++) {
// todo: update game logic -> in time step so no interpolation
mController.refresh(1);
}
}
BaseThread.AfterLogicBarrier.await(); // 3/4
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}
同步线程等的过程工作得很好,如果我将帧限制为 60,我每秒会获得 60 次刷新和尽可能多的渲染。但是有一个问题,我从昨天开始就试图解决这个问题——没有成功。
查看对象正在加速。它们没有加速度,它们只是从速度中获得收益。但是它们存在的时间越长,它们的速度就越快。有谁知道为什么会这样?渲染函数根本不应该干扰视图的位置/速度,因为它只使用 getter 方法来获取位图、当前位置和速度。
所以我的想法是,这是由于插值造成的,我会觉得这有点令人困惑,因为它不是反复出现的正弦式速度增加,而是在每个视图对象的生命周期内增加。
任何帮助,任何想法,将不胜感激。
这是逻辑线程和主线程的一些 LogCat 输出,显示了插值以及一切完成的时间:
08-29 17:09:57.603 26183-26207/com.example.pckg E/EnvironmentThread: localTime=0.017999122 >= 0.033333335, from elapsed = 0.017043
08-29 17:09:57.603 26183-26207/com.example.pckg E/EnvironmentThread: numSubSteps = 0.0
08-29 17:09:57.603 26183-26207/com.example.pckg E/EnvironmentThread: localTime=0.017999122, numSub=0
08-29 17:09:57.603 26183-26204/com.example.pckg D/GameThread: RENDERING! -> localTime=0.017999122, Options.TIMESTEP=0.033333335, interpol = 1.8519423
08-29 17:09:57.623 26183-26204/com.example.pckg D/GameThread: setElapsed = 0.017807
08-29 17:09:57.623 26183-26207/com.example.pckg E/EnvironmentThread: localTime=0.03580612 >= 0.033333335, from elapsed = 0.017807
08-29 17:09:57.623 26183-26207/com.example.pckg E/EnvironmentThread: numSubSteps = 0.0
08-29 17:09:57.623 26183-26207/com.example.pckg E/EnvironmentThread: localTime=0.0024727844, numSub=1
08-29 17:09:57.623 26183-26204/com.example.pckg D/GameThread: RENDERING! -> localTime=0.0024727844, Options.TIMESTEP=0.033333335, interpol = 13.480082
08-29 17:09:57.633 26183-26204/com.example.pckg D/GameThread: setElapsed = 0.013305
08-29 17:09:57.633 26183-26207/com.example.pckg E/EnvironmentThread: localTime=0.015777785 >= 0.033333335, from elapsed = 0.013305
08-29 17:09:57.633 26183-26207/com.example.pckg E/EnvironmentThread: numSubSteps = 0.0
08-29 17:09:57.633 26183-26207/com.example.pckg E/EnvironmentThread: localTime=0.015777785, numSub=0
08-29 17:09:57.633 26183-26204/com.example.pckg D/GameThread: RENDERING! -> localTime=0.015777785, Options.TIMESTEP=0.033333335, interpol = 2.1126752
08-29 17:09:57.653 26183-26204/com.example.pckg D/GameThread: setElapsed = 0.018212
08-29 17:09:57.653 26183-26207/com.example.pckg E/EnvironmentThread: localTime=0.033989787 >= 0.033333335, from elapsed = 0.018212
08-29 17:09:57.653 26183-26207/com.example.pckg E/EnvironmentThread: numSubSteps = 0.0
08-29 17:09:57.653 26183-26207/com.example.pckg E/EnvironmentThread: localTime=6.5645203E-4, numSub=1
08-29 17:09:57.653 26183-26204/com.example.pckg D/GameThread: RENDERING! -> localTime=6.5645203E-4, Options.TIMESTEP=0.033333335, interpol = 50.778023
08-29 17:09:57.673 26183-26204/com.example.pckg D/GameThread: setElapsed = 0.01754
08-29 17:09:57.673 26183-26207/com.example.pckg E/EnvironmentThread: localTime=0.018196452 >= 0.033333335, from elapsed = 0.01754
08-29 17:09:57.673 26183-26207/com.example.pckg E/EnvironmentThread: numSubSteps = 0.0
08-29 17:09:57.673 26183-26207/com.example.pckg E/EnvironmentThread: localTime=0.018196452, numSub=0
08-29 17:09:57.673 26183-26204/com.example.pckg D/GameThread: RENDERING! -> localTime=0.018196452, Options.TIMESTEP=0.033333335, interpol = 1.831859
08-29 17:09:57.683 26183-26204/com.example.pckg D/GameThread: setElapsed = 0.014516
08-29 17:09:57.683 26183-26207/com.example.pckg E/EnvironmentThread: localTime=0.032712452 >= 0.033333335, from elapsed = 0.014516
08-29 17:09:57.683 26183-26207/com.example.pckg E/EnvironmentThread: numSubSteps = 0.0
08-29 17:09:57.683 26183-26207/com.example.pckg E/EnvironmentThread: localTime=0.032712452, numSub=0
08-29 17:09:57.683 26183-26204/com.example.pckg D/GameThread: RENDERING! -> localTime=0.032712452, Options.TIMESTEP=0.033333335, interpol = 1.01898
08-29 17:09:57.703 26183-26204/com.example.pckg D/GameThread: setElapsed = 0.017108
08-29 17:09:57.703 26183-26207/com.example.pckg E/EnvironmentThread: localTime=0.049820453 >= 0.033333335, from elapsed = 0.017108
08-29 17:09:57.703 26183-26207/com.example.pckg E/EnvironmentThread: numSubSteps = 0.0
08-29 17:09:57.703 26183-26207/com.example.pckg E/EnvironmentThread: localTime=0.016487118, numSub=1
不幸的是,我的大脑现在落后了,我现在不明白我做错了什么。
编辑:
谢谢你推动我的大脑。添加更多调试语句后发现错误。没有数学错误,没有线程错误同步,而是在逻辑部分(refresh() 方法)中缺少一个简单的“List.clear()”,这导致列表永远不会被清除,从而导致相同的对象被移动每个计算框架更频繁 - 我什至没有在这里发布,因为我没想到错误会在那里。
还是谢谢你。