简体   繁体   English

Java的currentTimeMillis返回负值

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

I'm developing a simple 2D game in Java, everything works fine. 我正在用Java开发一个简单的2D游戏,一切正常。 To find the correct FPS refresh/redraw/update, I used currentTimeMillis to find the difference. 为了找到正确的FPS刷新/重绘/更新,我使用currentTimeMillis来查找差异。

The problem is that currentTimeMillis sometimes returns negative values, and the Thread.sleep will throw exception (java.lang.IllegalArgumentException: timeout value is negative) 问题是currentTimeMillis有时会返回负值,而Thread.sleep会抛出异常(java.lang.IllegalArgumentException:timeout值为负)

What I did was to put a while in my game and while currentTimeMillis <= -1 check again until its over, then sleep. 我做的是在我的游戏中放一段时间,而currentTimeMillis <= -1再次检查直到它结束,然后睡觉。

Code sample: 代码示例:

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

When the game starts, this works fine, but sometimes I still get the Exception. 当游戏开始时,这很好,但有时我仍然得到例外。 Is there a better way? 有没有更好的办法? I still think it´s strange that it´s returning a negative value. 我仍然认为它返回负值是很奇怪的。

Isn't the real problem that beginTime-currTime is negative ? beginTime-currTime不是真正的问题吗?

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

I note that you add FPS (40) to beginTime . 我注意到,您添加FPS (40) beginTime But if currentTime is greater than beginTime+FPS , you're going to have problems. 但如果currentTime大于beginTime+FPS ,那么你就会遇到问题。

If you're trying to schedule something at regular intervals (which I think you are), check out Timer , which will allow you to do this more simply/reliably. 如果你试图定期安排一些事情(我认为你是这样),请查看Timer ,这样你就可以更简单/可靠地完成这项工作。

imho the following instruction: imho以下指示:

difference = (beginTime - currTime);

should be: 应该:

difference = (currTime - beginTime);

currTime is always greater than beginTime, so difference is always negative or at least 0. currTime总是大于beginTime,因此差异总是负数或至少为0。

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

There is a conceptual problem in your code: at one point you add a framerate (Frames per second, FPS) to a time. 您的代码中存在一个概念性问题:您可以在某个时刻添加帧速率(每秒帧数,FPS)。 Or you really want to add 40 milliseconds, but then you shouldn't name the variable FPS because this will lead to misunderstandings. 或者您真的想要添加40毫秒,但是您不应该将变量命名为FPS,因为这会导致误解。

Assuming FPS is really frames per second, then you should use another value for your calculation: 假设FPS实际上是每秒帧数,那么您应该使用另一个值进行计算:

long milliSecondsPerFrame = 1000 / FPS;

System.getCurrentTimeInMillis() will never return negative values (or at least not before Aug, 17, 08:12:55 - in the year 292.278.944 ;) ) *) System.getCurrentTimeInMillis()永远不会返回负值(或至少不会在8月17日,08:12:55之前 - 在292.278.944年;)*)

So you can safely remove the checks for negative currentTimeMillis() for real time usages. 因此,您可以安全地删除负currentTimeMillis()的检查以获取实时使用情况。

The name of the beginTime variable leads to another misunderstanding. beginTime变量的名称导致另一个误解。 This is not the timestamp of some kind of beginning. 这不是某种开始的时间戳。 In fact its the time when you expect the next frame update. 事实上,它是您期望下一帧更新的时间。 So you should name it different, maybe 'nextFrameUpdateTime'. 所以你应该把它命名为不同的,也许是'nextFrameUpdateTime'。 That would make clear, that the calculation of the difference is actually 这表明,差异的计算实际上就是这样

difference = nextFrameUpdateTime - currentTime;

is correct and should return a positive value - as long as your sure, that you didn't miss a frame update ('you're too late'). 是正确的,应该返回一个正值 - 只要你确定,你没有错过帧更新('你太迟了')。 And I think, that's the problem: a negative difference just indicates, that the renderGame() method took more time than the secondPerFrame value, so at some point during your game you just missed an update, the currentTime is bigger then the proposed nextFrameUpdateTime and you have the exception. 而且我认为,这就是问题所在:负差异只是表明,renderGame()方法花费的时间比secondPerFrame值多,所以在游戏中的某个时刻,你只是错过了更新,currentTime比建议的nextFrameUpdateTime更大,你有例外。

*) Tested with *)经过测试

Date date = new Date(Long.MAX_VALUE);

for calculation of fps values i would recommend using 为了计算fps值,我建议使用

System.nanoTime()

it is way more accurate. 它更准确。 the drawback is it gets you only realtive values, which does not matter at all when doing fps calcuation. 缺点是它只能获得实际值,这在进行fps计算时根本不重要。

1 millisecond consists of 1000000 nanoseconds. 1毫秒由1000000纳秒组成。

the resolution of currentTimeMillis is usually only 16ms. currentTimeMillis的分辨率通常只有16ms。

It seems like this worked better. 看起来这样效果更好。

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

Thank you for your help everyone. 谢谢大家的帮助。

If you're trying to set a specific frame rate, here's what it should look like: 如果您正在尝试设置特定的帧速率,那么它应该是这样的:

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) { }
    }
}

This is just a "close enough" fixed rate game loop, and should give you the basic idea. 这只是一个“足够接近”的固定速率游戏循环,应该给你基本的想法。 I say close enough because if renderGame() takes longer than msPerFrame, the game will slow down (like NES games when there was too much on the screen). 我说得足够接近因为如果renderGame()花费的时间比msPerFrame长,那么游戏就会变慢(比如屏幕上有太多的NES游戏)。

There's better ways to run a game loop, like using frame rate independent motion, or using frame skipping to handle slowdowns, but this is a good way to do it for a first game. 有更好的方法来运行游戏循环,例如使用帧速率独立运动,或使用跳帧来处理减速,但这是第一个游戏的好方法。

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

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