繁体   English   中英

Java的currentTimeMillis返回负值

[英]Java's currentTimeMillis returns negative value(s)

我正在用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()

当游戏开始时,这很好,但有时我仍然得到例外。 有没有更好的办法? 我仍然认为它返回负值是很奇怪的。

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

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

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

如果你试图定期安排一些事情(我认为你是这样),请查看Timer ,这样你就可以更简单/可靠地完成这项工作。

imho以下指示:

difference = (beginTime - currTime);

应该:

difference = (currTime - beginTime);

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

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

您的代码中存在一个概念性问题:您可以在某个时刻添加帧速率(每秒帧数,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);

为了计算fps值,我建议使用

System.nanoTime()

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

1毫秒由1000000纳秒组成。

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

看起来这样效果更好。

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()

谢谢大家的帮助。

如果您正在尝试设置特定的帧速率,那么它应该是这样的:

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游戏)。

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM