Java currentTimeMillis返回负值)

时间:2009-07-29 11:32:09

标签: java time

我正在用Java开发一个简单的2D游戏,一切正常。为了找到正确的FPS刷新/重绘/更新,我使用currentTimeMillis来查找差异。

问题是currentTimeMillis有时会返回负值,而Thread.sleep会抛出异常(java.lang.IllegalArgumentException:timeout值为负)

我做的是在我的游戏中放一段时间,而currentTimeMillis< = -1再次检查直到它结束,然后睡觉。

代码示例:

private void gameLoop(){
    // Find FPS
    long FPS = 40;
    long beginTime = System.currentTimeMillis();
    while(beginTime < -1){
        beginTime = System.currentTimeMillis();
    }
    while(!done){
        // Sleep
        try{ 
            beginTime += FPS;
            long currTime = System.currentTimeMillis();
            while(currTime < -1){
                currTime = System.currentTimeMillis();
            }
            difference = (beginTime - currTime);
                           // Should be (currTime - beginTime) 

            Thread.sleep(difference); 
        }catch (Exception e){ 
            e.printStackTrace();
        }
        // RENDER GAME
        renderGame();
    }
    JOptionPane.showMessageDialog(null, "Game Over\nYou Died.");
    System.exit(0);
}// end gameLoop()

当游戏开始时,这样可以正常工作,但有时我仍然会得到异常。有没有更好的办法?我仍然认为它返回一个负值很奇怪。

7 个答案:

答案 0 :(得分:11)

beginTime-currTime不是真正的问题吗?

difference = (beginTime - currTime);
Thread.sleep(difference); 

我注意到您将FPS(40)添加到beginTime。但如果currentTime大于beginTime+FPS,您就会遇到问题。

如果您正在尝试定期安排某些事情(我认为您是这样),请查看Timer,这样您就可以更简单/更可靠地执行此操作。

答案 1 :(得分:5)

imho以下指示:

difference = (beginTime - currTime);

应该是:

difference = (currTime - beginTime);

currTime始终大于beginTime,因此差异总是负数或至少为0.

答案 2 :(得分:1)

如果currentTimeMillis返回负值,那么JVM / OS出现问题或内存损坏等。

答案 3 :(得分:1)

您的代码中存在一个概念性问题:您可以在某个时刻添加帧速率(每秒帧数,FPS)。或者你真的想要添加40毫秒,但是你不应该将变量命名为FPS,因为这会导致误解。

假设FPS实际上是每秒帧数,那么您应该使用另一个值进行计算:

long milliSecondsPerFrame = 1000 / FPS;

System.getCurrentTimeInMillis()永远不会返回负值(或者至少不会在8月17日,08:12:55之前 - 在292.278.944年;)*)

因此,您可以安全地删除负currentTimeMillis()的检查,以便实时使用。

beginTime变量的名称导致另一个误解。这不是某种开始的时间戳。事实上,它是您期望下一帧更新的时间。所以你应该把它命名为不同的,也许是'nextFrameUpdateTime'。这表明,差异的计算实际上是

difference = nextFrameUpdateTime - currentTime;

是正确的,应该返回正值 - 只要你确定,你没有错过帧更新('你太迟了')。而且我认为,这就是问题所在:负差异只是表明,renderGame()方法花费的时间比secondPerFrame值多,所以在游戏中的某个时刻,你只是错过了更新,currentTime比建议的nextFrameUpdateTime更大,你有例外。

*)使用

进行测试
Date date = new Date(Long.MAX_VALUE);

答案 4 :(得分:0)

用于计算fps值我建议使用

System.nanoTime()

它更准确。缺点是它只能获得实际值,这在进行fps计算时根本不重要。

1毫秒由1000000纳秒组成。

currentTimeMillis的分辨率通常只有16ms。

答案 5 :(得分:0)

看起来效果更好。

private void gameLoop(){
    // Find FPS
    long nextFrameUpdateTime = System.currentTimeMillis();
    long milliSecondsPerFrame = 1000 / 60;
    while(!done){
        // Sleep
        try{ 
            long currentTime = System.currentTimeMillis();
            currentTime += milliSecondsPerFrame;

            difference = ( currentTime - nextFrameUpdateTime );
            Thread.sleep(difference); 

        }catch (Exception e){ e.printStackTrace(); }

        nextFrameUpdateTime = System.currentTimeMillis();
        renderGame();

    } // end While
    JOptionPane.showMessageDialog(null, "Game Over\nYou Died.");
    System.exit(0);
}// end gameLoop()

感谢大家的帮助。

答案 6 :(得分:-1)

如果您尝试设置特定的帧速率,请按以下步骤显示:

long msPerFrame = 1000 / 60;
long now = System.currentTimeMillis();
long next = now + msPerFrame;
while(!done)
{
    now = System.currentTimeMillis();
    if(now >= next)
    {
        next = now + msPerFrame;
        renderGame();
    }
    else
    {
        // no chance of negative, we know next > now
        long diff = next - now;
        try { Thread.sleep(diff); } catch(InterruptedException ex) { }
    }
}

这只是一个“足够接近”的固定利率游戏循环,应该给你基本的想法。我说得足够接近,因为如果renderGame()花费的时间比msPerFrame长,那么游戏就会放慢速度(就像屏幕上有太多的NES游戏一样)。

有更好的方法来运行游戏循环,例如使用帧速率独立运动,或使用跳帧来处理减速,但这是第一场比赛的好方法。