在我的游戏中,我有多个主题。一个线程将信号发送到计算线程,在此线程接收到信号后,它还会渲染游戏。
主线程看起来像这样,我改编自我见过的其他游戏循环:
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()”,这导致列表永远不会被清除,导致同一个对象被移动更常见的是每个计算框架 - 我甚至没有在这里发布,因为我没想到会出现错误。
谢谢你。
答案 0 :(得分:1)
写了更多的游戏循环,而不是你可以动摇,我觉得你的一切都错了。
你需要两个循环。一个循环就是你的game loop
。这步骤将游戏状态向前推进一次。事情发生变化,事情死亡,事物发生碰撞,事情改变方向等等。
第二个循环是你的render loop
。这只是采取游戏状态并吐出一个图像。
如果关闭渲染循环,屏幕会变黑,但游戏循环中游戏仍在进行。
如果关闭游戏循环,屏幕不会改变,直到您重新打开游戏循环,因为它会继续呈现相同(未更改)的状态。
现在,看起来你实际上没有游戏循环。你有一个渲染循环试图一次一点地模拟游戏循环,Admiral Ackbar有一两件事(实际上只有一个)可以说。
因此,制作一个完全独立于渲染循环的正确游戏循环,这个问题(以及其他十几个)将会消失。一般来说,添加新功能也会容易得多。
答案 1 :(得分:1)
我建议你看看LWJGL。 Minecraft就是基于此,它可以为您提供一些主题。
通常的“游戏循环”本身涉及一系列步骤,主要包括:
正如您现在所做的那样,您有两个线程要渲染,另一个要更新。如果更新线程变得疯狂,那么你的游戏将呈现无意义的东西,例如加速的精灵。
以一些现有的框架为例(比如,即将被弃用的XNA游戏工作室,其精神上的继任者MonoGame或PSM),他们在宏观层面处理游戏循环,拥有组件(a例如,Level
执行循环中包含的相同步骤。
有了这个说法,循环本身就“执行”每个元素(特别是 Update 和 Render ),在Level
上注入游戏循环对象
答案 2 :(得分:0)
也许这就是即时编译器???它通过将方法编译为本机代码使方法更快。但这种情况不会发生在同一方法的多次调用之前。
- &GT;关闭JIT编译器并检查行为。使用Oracle的Java SE,可以通过添加参数-Djava.compiler=NONE
查看http://artiomg.blogspot.de/2011/10/just-in-time-compiler-jit-in-hotspot.html