同步重力和 FPS

Sync Gravity and FPS

我正在开发一款简单的游戏,但我遇到了 FPS 和重力方面的问题。 所以我需要同步 FPS 和重力,因为 FPS 越高玩家下落得越快。如何同步它们?

我更新播放器的代码:

            while (true) {
            try {
                Thread.sleep(1000 / GameMain.maxFPS); //Max Fps Limiter
                GameMain.activeEntities.forEach((ent) -> { //Revalidade All Entities and Positions
                    ent.onTick(); 
                });
                gamePanel.repaint(); //Repaint Frame, Update Positions
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

我更新重力的代码:

@Override
public void onTick() {
    this.velocity = this.velocity.add(0, gravityForce()/*<- I'm using 9.807 divided by 60*/);
    if (this.velocity.y > maxSpeed)
    {
        this.velocity.y = maxSpeed;
    }
    this.getPosition().y = this.getPosition().y + (this.velocity.y);
}

使用 Thread.sleep 会出现问题,因为 Thread.sleep 不能保证线程正好休眠 1000 毫秒,但线程至少会休眠 1000 毫秒。此外,无论何时涉及到线程,都会存在依赖于实际系统的行为差异,因为线程调度逻辑不是应用程序或 JVM 的功能,而是底层硬件的功能。

我的建议:要么将绘制逻辑与重新计算逻辑分离,要么让它 运行 自由而不用 Thread.sleep 阻塞线程。从那里开始,为了获得良好的运动,我们应该记住,位置的变化不仅是速度因素,也是时间因素。因此,我们需要通过System.currentTimeMillis()System.nanoTime().

等机制来计算不同并条机之间的时间间隔。

从那里,您可以通过将它们的速度乘以重新计算后经过的时间量来重新计算位置。

粗略实施:

double c = 1 / 60; // Some constant factor to bound motion over time
long previousCycleTime = System.currentTimeMillis();
while(somePredicate()) { // Logical cycle
   long t = System.currentTimeMillis() - previousCycleTime;
   gameObjects.forEach( o -> {
     // t -> time passage
     // dx -> change on the x axis
     // c -> some constant factor to bound movement to the 'virtual space'
     o.x += o.dx * t * c; 
     o.y += o.dy * t * c;
   }
   redraw();
}

或者,您可以在单独的线程中重新绘制以分离两个进程。但这不应掉以轻心,因为从单线程应用程序过渡到多线程应用程序会引入大量额外的复杂性。