problem calculating time
Blitz3D Forums/Blitz3D Programming/problem calculating time
| ||
Hi! Imagine a 2d square area, divide it in 4 quadrant and let a player move in the area for 1 minute. How is the best way to calculate the time the player spent in each quadrant when the time is out? I can’t get good results. Here is the code I’m using in the main loop: The results (Latency#, TimeIResult#,…) I get using this code are wrong. The latency# should be 60.0 but I always obtain bigger results (like 60.012) . The sum of the 4 TimeXResult# gives the same number (i.e. 60.012). Is it a conversion type problem? Or the lost of precision is due to the mathematic operations? Any suggestions to do it better? I need “millisec” precision. Thanks a lot FiNegirO |
| ||
hi, i tested this out and it looks like some commands, i think the ones related to drawing, eat up a few milliseconds, in particular i found flip was the most noticable, also cls with text occasionally caused a small timing error. Maybe if you give the timer job to a dll it would allow you to have this accuracy. Here is the code i used. Graphics3D 640,480,0,2 iniTime=MilliSecs() While Not KeyHit(1) tempTime=MilliSecs()-iniTime If MilliSecs()>=iniTime+1000 ;1 second test If once=0 once=1 Latency#=(MilliSecs()-iniTime)/1000.0 testTime=MilliSecs()-iniTime testFloat#=1000/1000.0 EndIf EndIf ;If once=1 Cls Text 0,0,"Latency="+Latency+" testFloat="+testFloat Text 0,12,"testTime="+testTime+" iniTime="+iniTime+" tempTime="+tempTime ;EndIf If once=1 Then Flip Wend |
| ||
Edit: The alternative would be checking the time more often. Here is my version, it does exactly the same: /edit |
| ||
i think now what i posted above isn't quite correct, as the error margin of 1 sec and 60 sec is the same. so it must be more like flip, etc. causes a read error/delay with the current millisecs. the solution then shouldn't need a dll, but just not calling flip on the loop before you get millisecs. |
| ||
Thanks muk and bram32. I tried your code and I get the same errors as in mine. bram32, do your code works for you? I modified it just to display the errors between Total time and Total sum. I can't explain the results: Total sum is usually more then the wanted time and Total time is more than Total sum! Here is the code (thanks bram32): Graphics 800, 600, 0, 2 SetBuffer BackBuffer() Dim time#(4) .up For i = 0 To 3 time#(i) = 0.0 Next init = True Repeat ;calculate time passed now# = MilliSecs() If init Then prev# = now#: inittime# = now: init = False elapsed# = now# - prev# prev# = now# ;select quadrant mx = MouseX() my = MouseY() quad = (mx > 400) + (my > 300) * 2 ;set time for selected quadrant time(quad) = time(quad) + elapsed ;graphical output Cls ;draw grid Line 400, 0, 400, 600 Line 0, 300, 800, 300 ;print out times For i = 0 To 3 Text i Mod 2 * 400 + 200, i / 2 * 300 + 150, time#(i) / 1000.0 Next ;measure total time passed tot1# = ((time(0) + time(1) + time(2) + time(3)) / 1000.0) tot2# = (MilliSecs() - inittime#) / 1000.0 ;debug output Text 0, 0, "You're in quadrant: " + quad Text 0, 20, "Total sum times: " + tot1# Text 0, 40, "Total time millisecs: " + tot2# Flip ;limit to 60 secs If tot2# >= 3.0 Then Err1# = tot2# - 3.0 Err2# = tot2# - tot1# Text 0, 60, "Error1 (Total time - 3 sec.): " + Err1# Text 0, 80, "Error2 (Tot time - Tot sum): " + Err2# Flip Exit EndIf Until KeyHit(1) Text 400, 290, "Press space to retry", True, True Text 400, 310, "Any other key to exit", True, True Flip Key = WaitKey() If Key = 32 Then Goto up End The other strange thing is, as muk said, the error/delay is the same for 1 sec, 60 sec or more. I'm not sure to understand your solution muk. I need to flip continuously because of the graphics. How should I wait to get millisecs without flipping? FiNegirO |
| ||
Floats behave a bit strange:x# = 0 For i = 1 To 1000 x# = x# + 0.0001 Next Print x WaitKey() End They are only as exact as they need to be. In the code above, it is precise until 0.0001 digits. All the stuff after that is just "rubbish". I believe it has something to do that inside the CPU floats are just integers as well. Then in the graphical routine, it takes time to render each frame. So if you check the Millisecs() once a loop, it will not check every millisecond. Say the program renders at 30 FPS, then the loop repeats at 30FPS, so the "exit timer" checks at 30FPS, too. There is a deviation of one frame allways. The only thing you can do about this is check the exit timer more often. |
| ||
Thanks for the clarification! But I don’t understand how could I check the exit timer more often while rendering the scene? Could you give me an example please? FiNegirO |
| ||
Well, you could for instance check the timer after each line of code. x# = cos(p) * 10: CheckTimer() y# = sin(p) * 10: CheckTimer() oval x, y, 10, 10: CheckTimer() for i = 0 to 10 oval rand(x), rand(y), 10, 10: CheckTimer() next If you want to render in several steps, you could use a Type for all your objects. For i.TObject = Each TObject ShowEntity i\mesh RenderWorld() HideEntity i\mesh CheckTimer() Next In fact, using threads does the same thing. Only then with two applications. Each application gets a certain amount of processor time. There is a wait built in the "Flip" command. The VWait waits for the ScanLine() to be zero. It avoids nasty flickering of the image. During this wait, other application can perform their tasks. Same thing goes for Delay(). To get as close to the millisecs() accuracy, you should have: * a tight loop * check very often |
| ||
i guess the simplest way is like this, ie. don't flip the 15 millisecs before getting your time result, 20 is the margin of error.Graphics3D 640,480,0,2 iniTime=MilliSecs() While Not KeyHit(1) tempTime=MilliSecs()-iniTime If MilliSecs()>=iniTime+1000 ;1 second test If once=0 once=1 Latency#=(MilliSecs()-iniTime)/1000.0 testTime=MilliSecs()-iniTime testFloat#=1000/1000.0 EndIf EndIf Cls Text 0,0,"Latency="+Latency+" testFloat="+testFloat Text 0,12,"testTime="+testTime+" iniTime="+iniTime+" tempTime="+tempTime If MilliSecs()>=iniTime+1000-15 And MilliSecs()<=iniTime+1000+5 Else Flip EndIf Wend |
| ||
ah, yes that should work perfectly! |
| ||
Ok! Timing is better (still not perfect) but what happens with the graphics? Try this: Graphics3D 640,480,0,2 camera=CreateCamera() light=CreateLight() RotateEntity light,90,0,0 cube=CreateCube() PositionEntity cube,0,0,5 iniTime=MilliSecs() OneSecondTime = iniTime While Not KeyHit(1) tempTime=MilliSecs()-iniTime If MilliSecs()>=OneSecondTime+1000 ;1 second test Latency#=(MilliSecs()-OneSecondTime)/1000.0 testTime=MilliSecs()-OneSecondTime OneSecondTime = MilliSecs() testFloat#=1000/1000.0 EndIf UpdateWorld RenderWorld Text 0,0,"Latency="+Latency+" testFloat="+testFloat Text 0,12,"testTime="+testTime+" iniTime="+iniTime+" tempTime="+tempTime ;Text 50,50,"" + MilliSecs() Mod 1000 TurnEntity cube,-.4,.2,.3 If (MilliSecs() - OneSecondTime) Mod 1000 < 985 And (MilliSecs() - OneSecondTime) Mod 1000 > 5 Flip ;flip only if "far" from time checking EndIf Wend Could you see the gap in the render process? It's a big problem in a real time game. Any idea to solve it? Thanks a lot, FiNegirO |
| ||
the main problem there is you're updating the cube every loop so it's not syncing with the flip and causing that big jump. the solution is to group any graphics code in with the flip as well. i changed your mod thingy as it gave some other kind of problem and i couldn't understand how to fix it. Graphics3D 640,480,0,2 SetBuffer BackBuffer() camera=CreateCamera() light=CreateLight() RotateEntity light,90,0,0 cube=CreateCube() PositionEntity cube,0,0,5 iniTime=MilliSecs() nextTime = iniTime While Not KeyHit(1) tempTime=MilliSecs()-iniTime If MilliSecs()>=nextTime+1000 ;1 second test Latency#=(MilliSecs()-nextTime)/1000.0 testTime=MilliSecs()-nextTime nextTime = MilliSecs() testFloat#=1000/1000.0 EndIf If Not MilliSecs()>=nextTime+1000-30 And MilliSecs()<=nextTime+1000+20 UpdateWorld RenderWorld Text 0,0,"Latency="+Latency+" testFloat="+testFloat Text 0,12,"testTime="+testTime+" iniTime="+iniTime+" tempTime="+tempTime ;Text 50,50,"" + MilliSecs() Mod 1000 ;If (MilliSecs()-nextTime) Mod 1000<985 And (MilliSecs()-nextTime) Mod 1000>5 TurnEntity cube,-.4,.2,.3 Flip ;flip only if "far" from time checking EndIf Wend |
| ||
Thanks muk! It worked for me. Now I get better timing without graphics gaps. Still there are some time errors. I'm trying to do time check more often, as bram32 said. I hope to get "almos perfect" results. I'll tell you. cheers FiNegirO |
| ||
Hey, I was thinking .. maybe you could play a .WAV that is exactly 1 minute and use Channelplaying ? edit: No, that would be the same actually.. Nevermind that. I was just thinking about the .wav playing as an independant process. |