2

我正在构建一个非常强调物理的游戏。因此,我需要游戏以非常特定的间隔运行。当前代码:

public double period = .02; //this is the run interval in seconds

//main gameLoop
public void gameLoop(){
    long startTime;
    long sleep;

    while(running){
        startTime = System.nanoTime();

        Graphics2D g = s.getGraphics();
        operateEntities(g);
        g.dispose();
        s.update();
        //figure out how long it must sleep to take .02s altogether
        sleep = ((int)(period*1000) - (System.nanoTime() - startTime)*100000);
        try{
            if(sleep > 0){
                Thread.sleep(sleep);
            }else{
                System.err.println("Warning: program runtime exceeded period");
            }
        }catch(Exception ex){}

        gameTime += period;
    }
}

这没有按预期工作。目前,主线程正在执行而根本没有休眠,并且正在触发“警告:程序运行时间超过期限”警告。

以前我使用 System.currentTimeMillis(),但它对我的目的不够准确,所以我切换到 System.nanoTime()

增加周期实际上可以加快程序的速度,而减少它会减慢它的速度。

有简单的逻辑吗?我对 System.nanoTime() 的理解是否关闭?还是有更好的方法来运行方法操作实体,处置,并在特定的时间间隔更新?

编辑:为了记录,该程序完成时间不超过 0.02 秒。它已经过测试

4

2 回答 2

8

纳秒小于毫秒,因此,要转换 nanos -> millis,您必须除以 100000,而不是乘以它;

    //figure out how long it must sleep to take .02s altogether
    sleep = ((int)(period*1000) - (System.nanoTime() - startTime)*100000);

应该改为

    //figure out how long it must sleep to take .02s altogether
    sleep = ((int)(period*1000) - (System.nanoTime() - startTime)/100000);

您当前的代码正试图睡眠 200 毫秒减去一个大数字,使睡眠为负数,并为您提供“警告:程序运行时间超出期限”输出

于 2012-08-06T19:36:48.343 回答
2

分解你的代码有很多问题:

//Multiplies by 100,000 rather than divides.
sleep = ((int)(period*1000) - (System.nanoTime() - startTime)*100000);
//Note that sleep here is a very small number minus a very large number: probably negative.

try{
  if(sleep > 0){//If positive, sleep
    Thread.sleep(sleep);
  } else{//throws an error in all other cases.
    System.err.println("Warning: program runtime exceeded period");
  }
}catch(Exception ex){}//Empty exception handling poorly handles the thread.sleep() Exception requirement.

除非您使period值更大,否则此代码将始终出错。但是,即使除此之外,您的方法也不太可能产生您想要的结果:准确的计时。你的核心循环是什么:

  • 计算物理时间 0.02 秒。
  • 去睡觉。
  • 检查现在是什么时间。
  • 如果特定时间段(0.02 秒)已过,则继续,否则再次休眠。
  • 重复。

如果时间片足够小,这将是准确的。但是,线程不是那样工作的。您无法保证线程何时唤醒。它可能永远不会。可能在三秒钟内。它可能是即时的。无论您的时间段是多少,您都有可能会超调,而且您实际上永远不会完全按时完成。

您不需要依赖特定的增量周期,而是需要按实际过去的时间段来缩放所有物理场,而不是每次都依赖于持续经过的特定时间段。

  • 去睡觉。
  • 找出已经过去了多少时间。
  • 计算那个时间段的物理。
  • 重复。

您仍然需要一小段时间来休眠,但是这样可以消除线程调度程序引入的错误。

于 2012-08-06T19:43:59.213 回答