同步重力和FPS

时间:2018-11-21 21:00:52

标签: java 2d-games gravity

我正在开发一个简单的游戏,但是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);
}

1 个答案:

答案 0 :(得分:0)

使用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();
}

或者,您可以在一个单独的线程中重画以解耦两个进程。但是,这不应掉以轻心,因为从单线程应用程序过渡到多线程应用程序会带来很多额外的复杂性。