Negative Millisecs()
BlitzMax Forums/BlitzMax Programming/Negative Millisecs()
| ||
I started to use millisecs as a timer that counter upwards. 1..2..3..4..5..6 and so on. Then I learnt that after some days, or on linux systems, the counter goes into the negative. How does it count when it comes to negative? Is it -9...-8...-7...-6...-5 ? or -7...-8...-9...-10...-11...-12? And when it laps? How does it start over? And to measure the time from A to B, is the correct way to do it like this: timer:Int = millisecs() ' ex time = 400 ' or time = -600 DoSomethingTedious() 'Returns 500ms later timeTaken = millisecs() - time ' Should be: timeTaken = 900 - 400 ----------> 500 ok! ' or negative : timeTaken = -1100 - (-600) --> -500 ok? ' Should I use abs() or am I doing something wrong? And when you want to get a time Ex. when 500ms have passed. startTime = millisecs() ' Ex1. StartTime = 800 ' Ex2. StartTime = -800 Loop If millisecs() - startTime => TimePassed Then DoSomething() 'Millisecs() - 800 'Ex. 900 - 800 = 100ms passed ' If 100ms => 500ms Then.. ok! 'For negative: ' Millisecs() + 800 ' Ex. -900 + 800 = 100ms ' If 100ms => 500ms Then.. ok! Seems to work, right? EndLoop Is this how millisecs() was intended to be used? Is there more to it? |
| ||
I would assume it wraps at the 2 billion mark back to minus two billion (then count up towards 0) if it's signed. Otherwise it would wrap from 4 billion odd to 0. You second comment 'For negative shows -900+800 = 100ms, this is wrong it will be -100ms. Anyway, after 100ms, it should go up to -700ms and then -700 --800 = 100 (because -- = +) :-) |
| ||
After 24 days of uptime or so, the integer value overflows and it goes negative -2,147,483,648 or whatever, and then begins counting back towards 0. I use a custom MilliSecs function that starts counting at 0 to solve the problem. |
| ||
wouldn't this solve the problem? Local startTime:Long = millisecs() .... Local timeRunning:Long = millisecs() - startTime (at least until 2038...) :-) |
| ||
There's no problems with it counting negative as the differences are still positive. The only problem is the instance when it wraps over, you may get a ridiculous value, but you can protect against that. |
| ||
If you like to use If MilliSecs() >= myTime + 100 there will be problems with it counting negative. Instead of changing all my instances of that, I just start from 0. |
| ||
I would avoid using Millisecs() for timing things directly in my game. I do the following: Current_Time = MilliSecs() Game_Start_Time = Current_Time Repeat SetClsColor 0, 0, 0 Cls Repeat Time_Old = Current_Time ' Store start time of last frame. Current_Time = MilliSecs() ' Get the current time. Use this instead of Millisecs() from here on if you need the time. Time_Delta = Current_Time - Time_Old ' Calculate how long last frame took to render, in milliseconds. Time_Delta_Sec# = Float(Time_Delta)/1000.0 ' Convert frame time to seconds. Until (Time_Delta > 0) And (Time_Delta < 250) ' Handle unnaturally long pauses between frames gracefully. FPS = 1000.0 / Float(Time_Delta) See that bit after Until? That handles both when the user tabs out of the app and back, and when millisecs wraps to 0. Also, when Millisecs() wraps to negative, it counts towards 0, so if Current_Time = -100 and Time_Old = -200, then Time_Delta = 100, which is correct. The last bit of the puzzle isn't in the code above. I have a Game_Time variable which I add Time_Delta to each frame while the game is not paused. While it is likely someone might leave their PC running for 23 days straight and you might have a negative Millisecs() to deal with, it's not so likely that they will leave your game running for that long, so you need not worry about your Game_Time timer overflowing. But if you are... Make it a long. A long will not overflow until around 160 million years have passed. :-) |
| ||
All you need to do is check if the millisecs is larger than a given value and then modulo it with that value and adjust whatever other parameters you have so your whole thing still works... or put the `total millisecs` from all the modulo'd millisecs into a Long. |
| ||
Thanks for all the great response. Okey so it counts from lowest negative to 0 to highest int, then it jumps to lowest negative and counts upwards towards 0 again. Brucey thanks, that was a nice idea. I'm going to use that one. Allows me to use A > B and B < A with current time instead of A - B > 0 and B - A > 0. Sswift, what I do not really understand is the Repeat-Until loop you have inside you main loop. Is this like a delay? Until (Time_Delta > 0) And (Time_Delta < 250) - Is not Time_Delta always be less than 0? With a FPS of 75 the frametime should be less than 13 ms. FrameTime = 1000/FPS. And this would be the total time for Graphics, Logic, AI, Effects and more. Or did you mean to draw/update everything then run some delay until time reached? AngelDaniel, How did you mean to use Mod with millisecs? How fast is mod? |
| ||
I'm pretty sure sswifts code means that if there is a big delay due to external influences OR the clock has wrapped round, then it will take another reading. Also Time delta is either 0 or greater normally as it's measure in MS: Time_Delta = Current_Time - Time_Old re: Mod considering you are only calling it ONCE per frame, I really wouldn't worry :-) |
| ||
Time_Delta should always be greater than 0, not less than 0, so with an FPS of 75 it will be 13. The reason I check to see if it is less than 0 is just in case the code is running so fast that it executed in less than a millisecond. That would cause stuff to crash when it divides by 0. And I check if it is greater than 250 because that's only gonna happen if the FPS drops below 4fps, like if the hard drive starts thrashing for a moment or the user tabs out of the game. Saves them from getting killed because everything went choppy for a moment and they missed something important. |
| ||
Ah so it works like a pause when the FPS drops very low, instead of lag in form of warping. Wait a minute, I think I confused myself. Yes, I agree Delta_Time, which is the same as frametime, is always greater or equal to 0. However your loop loops when it is greater than 0 or less than 250. Which means it will loop forever unless the logic suddendly takes less than a millisec to do? Or maybe I missunderstood where you put the UpdateEverything() function? |
| ||
It's not a while loop, it's a repeat until loop so as soon as Delta_Time goes over 1, it exits the look and this is where the logic would be updated and then the drawing would be done. |
| ||
Wave: No, it won't loop forever, because eventually one read of millisecs will be at the next millisecond when the other was at the previous. But I suppose it's possible it could loop a few times. Anyway I haven't ever noted it being an issue, even when the screen is blank and the FPS counter is stuck at 1000. |
| ||
FYI Mod is plenty fast, not sure why you'd worry. I use it thousands of time a loop, maybe tens of thousands. |
| ||
Sorry did not think about until = not while :) |