Fix Your Timestep!

BlitzMax Forums/BlitzMax Programming/Fix Your Timestep!

tonyg(Posted 2007) [#1]
I have been trying to convert this article to Bmax because I have never used Fixed Logic timing before.
Unfortunately, I'm finding some of the article incoherent so might be missing something. My code doesn't run very smoothly.
First, here's what I understand the example code to be doing with my own comments

    float t = 0.0f;    * Guess this is gametime but don't quite know what it's used for.
    const float dt = 0.01f; * Timestep in seconds? 

    float currentTime = 0.0f; * OK.
    float accumulator = 0.0f; * OK.

    State previous; * Guess in Bmax you have to keep the old positions.
    State current; * and this is the new position.

    while (!quit)
    {
         float newTime = time();  *Guess time() is millisecs()
         float deltaTime = newTime - currentTime; * OK with this..
*** Needed some clamp on deltatime here I assume.
         currentTime = newTime; * OK.

         accumulator += deltaTime;  * OK

         while (accumulator>=dt)
         {
              previousState = currentState;   * old_xpos=new_xpos etc?
              integrate(currentState, t, dt); * no idea 
what this really means but assumed you pass 
your update methods/functions the timestep value. 
Not sure what you use 't' for.
              t += dt;  * Keep a count of 't' but not sure why.
              accumulator -= dt;  * OK.
         }

         const float alpha = accumulator / dt;  * OK

         State state = currentState*alpha + previousState*(1.0f-alpha);   * OK.

         render(state);  *OK
    }

Here is the code I came up with :

Have I missed something?
I realise there are other timing methods available but this is purely to check how fixed rate logic behaves for myself.


Derron(Posted 2007) [#2]
copypaste and crippled a bit from my code (left out some specific things)

UpdateMain uses Game.intDeltaTime to calc movement and so on


'--- Variables for compensated timing
Const dt:Float=1.0/60.0
Global CurrTime:Int=0
Global Kompensator:Float=0.0
Global newTime:Int = 0
Global deltaTime:Float = 0.0
'-------------

Repeat
	If CurrTime = 0 Then CurrTime = MilliSecs()
	newTime   = MilliSecs()
	deltaTime = (newTime - CurrTime) / 1000.0
	CurrTime  = newTime
	Kompensator:+ deltaTime

	While(Kompensator >= dt)
		Game.intDeltaTime = (MilliSecs() - Game.IntTimer) / 1000.0
		Game.IntTimer = MilliSecs()            
		UpdateMain() 
		Kompensator :- dt
	Wend
	DrawMain()
Until AppTerminate() Or ExitGame = 1



So "previousState" is missing - no tweening

bye
MB


Gabriel(Posted 2007) [#3]
I'm not good at reading other people's code at the best of times, but your understanding of the article seems right to me, and I can't immediately spot anything wrong in your implementation. Have you tried using something more accurate than milliseconds to see if that makes the difference?


tonyg(Posted 2007) [#4]
Thanks Michael/Gab,
I was going to try and use this for a high resolution timer.
However, checking Michael's code (which still wasn't too smooth for me although I might have implemented it wrong) led me to this
For some reason this seems to work much better when (if I have read it right) it should be less 'blended'.

Also found Beakers interval system which looks funky with things done by events although I've yet to find how to get the remainder for an interpolation.
If anybody else uses, or has checked, fixed logic timesteps then I'd be interested how your code differs.


Kev(Posted 2007) [#5]
tonyg,

my version is based on the article in your first post. in the example below two of the three rects are moved by fixed logic timesteps. all move using the same amount.

http://www.winblitz3d.co.uk/FixYourTimestep.zip

kev


tonyg(Posted 2007) [#6]
Kev, does your code run smoothly?
Is this something you're using which works OK?
How does your code compare to the code I have posted?


Grey Alien(Posted 2007) [#7]
TonyG: Hmm, yeah that first one isn't so hot but the last one works well on my system. I used that article to make my framework timer. It uses the fixed rate logic but without the interpolation. BUT what it does is run the fixed rate logic a certain number of times with Delta at 1, then the last loop is run with Delta at an appropriate fraction. Then my game logic used Delta for movements and timers etc and it works really well. Best of both worlds. I don't know if you've seen my framework in action but it's pretty smooth ;-)


tonyg(Posted 2007) [#8]
To some degree I think all these methods use the 'remainder' whether they call it interpolation, blending or delta. I was just expecting more from the first method as it uses the extra information from the last step.
GA, I've seen the demos from your framework and it does look impressive. If I was interested in writing games I would probably consider getting it but as I simply mess about it's a bit of a waste to have somebody else do the 'messing' for me.
.
Anybody seen anything I've done wrong? Anybody explain what 't' is for in the Fix Your Timestep article?
Anybody got fully working source they're prepared to share so I can check what I'm missing?


Gabriel(Posted 2007) [#9]
I'd like to share my implementation of this but A) Since I'm still running my game engine in a window and only for the editors at the moment, I've no idea if it even works. and B) It's so tightly integrated within my game engine, it would be hard to rip out and even harder to read. When I get a little further along the line and I actually have the game doing something ( ANYTHING! ) then I'd be more than happy to share the implementation ( assuming it works. ) However, that's not likely to be for a while yet.

I haven't looked at Kev's so cannot comment on that.

The problem with Grey's implementation is that his timestep is not fixed, defeating the purpose of the article. In a simple game which doesn't use any physics, this won't matter, but if you do use any physics, it will matter, and it will explode your simulation just as the article describes. I haven't looked at Grey's implementation in any detail, but if you're not going to fix your timestep, I don't see the purpose in doing anything more complicated than delta time anyway. This may simply be shortsightedness on my part, however.

Since T is implemented in exactly the same way in each type of timing Glenn uses, it won't be having an impact on your results. As far as I can tell, and without digging through all my rather complicated code, I'm pretty sure I assumed that T was the total simulation time, as you have.

I'll try to find some time on Monday or Tuesday to have a proper look at your version and see if I can compare it to my own. A perfect game timing system is very necessary, so it would be good for all of us if we can all have a good understanding of it.


Grey Alien(Posted 2007) [#10]
TonyG: Fair enough :-)

Gabriel: My code runs at a fixed rate of 200 FPS (obvisouly that's modifiable) and just uses Delta time for a bit of extra smoothing (the remainder). It's based on that article. Maybe you misunderstood the way it works, or I've misunderstood something ;-)


Grey Alien(Posted 2007) [#11]
TonyG: Just looked at that link you posted, "The Game Loop", and I agree with why the first 3 are not great, but I also don't like the 4th one (it does have some merits of course). The 4th one uses render tweening and could result in objects being drawn within other objects before collisions are detected - this seems messy to me. Also if you are trying to make an object fall with gravity, the change in y velocity will only occur at 25FPS and the interpolation will NOT use gravity (unless you coded it that way I guess) in between - so I'm not sure it would look that good...but maybe it woudn't be that noticeable.

Probably my 200FPS fixed rate loop is overkill but it does look nice. I've also built in a threshold so that it won't go crazy on slow machines. It's probably not ideal either, I'm not sure there is an IDEAL game loop. Each has pros and cons and maybe it's down to developer preference e.g. do you want it to run on slow PCs, do you want it to look good on normal/fast PCs, how easy is the game to code etc.?

If a PC get's too slow, well maybe it's not suitable to run your game anyway...


Kev(Posted 2007) [#12]
tonyg,


does your code run smoothly?
Is this something you're using which works OK?



this is still to be tested. basicly its a wrapped version from the article, so it should function correctly.


How does your code compare to the code I have posted?


it does not, as before mine is a wrapped .cpp and your .bmx

if your intreasted in the code email me and i will send it your way.

*EDIT, this example now includes a simple example of firing a buttet that collides with 2 images. im intrested in the smoothness of this example.

http://www.winblitz3d.co.uk/FixYourTimestep.zip

kev


Gabriel(Posted 2007) [#13]
Gabriel: My code runs at a fixed rate of 200 FPS (obvisouly that's modifiable) and just uses Delta time for a bit of extra smoothing (the remainder). It's based on that article. Maybe you misunderstood the way it works, or I've misunderstood something ;-)


Well the article is not about fixing your frames per second, it's about fixing your timestep. The purpose is so that your physics updates are always fed the same timestep, because doing anything else results in broken, unpredictable physics. In your description above, you said you do a final timestep which is different from the rest, thus you're not using a fixed timestep at all.

So I'm not sure which of us has misunderstood either, but I thought you were describing a system of timing involving a variable timestep, because you do a small timestep instead of a tween.

The 4th one uses render tweening and could result in objects being drawn within other objects before collisions are detected - this seems messy to me.

No it couldn't. You cannot tween forwards, only backwards. So you're tweening back through a physics update you already did, and you didn't hit a collision in your physics update, then you won't hit one by not doing x% of that update.

Also if you are trying to make an object fall with gravity, the change in y velocity will only occur at 25FPS and the interpolation will NOT use gravity (unless you coded it that way I guess) in between - so I'm not sure it would look that good...but maybe it woudn't be that noticeable.


This, however, is quite correct. Your tweening is linear, and will not correspond perfectly with dynamics of whatever kind. I've engaged in long debates on this subject in IRC, and we never did reach complete agreement, but I feel that it won't be noticeable as long as you keep your FPS up. I'm not sure what you mean about only occurring at 25FPS, it will occur as often as you update your physics, but if you were updating your physics at 25FPS, then it might indeed be noticeable that your linear tweening was making things less than smooth. I wouldn't recommend going below 60.


tonyg(Posted 2007) [#14]
@Kev, that is a lot smoother.
@GA, I understood you were using the delta only in the render phase (e.g. as a type of tween) but it you're using it in the update phase then I can see why you Gabe asked why you don't just use Deltatime.
Anyway, I replaced millisecs() with QueryPerformanceCounter()
which *might* have made the first code look a bit better (my eyes are fried by looking at sodding ovals move across a screen).


Timing code *IS* bizarre. There must be lots of people happy with whatever method they used.
If there are pros/cons for different types of game then maybe there should be a 'suite' of timing solutions
e.g. set_timing_mode=FIXED_RATE
from simple 'waittimers' to those more difficult to implement.

<edit> Hold on. Other than (probably) a programming glitch causing some extra ovals to be drawn when x reaches graphicswidth() the code I just posted is smooth when I used Flip -1.
I was using Flip 0 to flip as quick as possible.

<edit2> AND it seems to be OK with normal millisecs() counter.

<edit3> Ignore the dodgy ovals drawn. It's simply when x loops t 0 so (x*alpha)+(prev_x*(1.0-alpha)) is not correct.


tonyg(Posted 2007) [#15]
...until, of course, I try it on another PC and flip -1 causes terrible tearing. Back to the drawing board.


Grey Alien(Posted 2007) [#16]
Gabriel: Ah yes I see now. My timestep is ixed for all but the last iteration which is based on delta as you have observed. The article actually says that the objects may be drawn in other objects but I see what you mean. As for 25FPS I was just referring to the timing that the article used.

TonyG: I'm not just using Delta because I wanted a high resolution game logic. Higher than the FPS, and one that remains constant so that collisions etc are always accurate. It really is the same method as fix your timestep except I'm not render tweening I'm using a variable Delta for the last game loop interation. I integrated sswifts sprite and physics code with my framework and that worked fine.


Sonic(Posted 2007) [#17]
Just have to say a big thankyou to Tonyg - I've had my game on hold for ages thinking it would be impossible to plug in some kind of timing code...

First tried delta timing, but it broke the predictability of my platformer (jumping etc)... However your code worked from the outset with very little work to add it in... Thanks so much!!!!

One thing I noted was you use:

all.x=(all.x+all.xvel)

Wheras I used:

all.x=all.x+( ( all.x - all.pre_x ) * alpha )

Wondered if there was a reason for that (I realise it's functionally the same in your code... But for something more complex?)


Grey Alien(Posted 2007) [#18]
Hey that's great news you finally got it sorted.


Sonic(Posted 2007) [#19]
Got a question though ...

When I introduce random fluctuations in the draw time (simply using delay() ), the smoothness factor drops quite a bit. The logic still feels the same, but the interpolation feels like it's not quite where it should be. In other words, I'm running logic at 60Hz, so sometimes the redraw is occurring only 30 times / second when the delay is introduced, however it should potentially run pretty smooth even in 30fps... So I'm wondering...

Is there something broken with your implementation Tony? Or would it just need some kind of averaging-out or 'anti-jitter'? If so I'm not quite sure where in the code I would implement that.


Sonic(Posted 2007) [#20]
Lol Grey, are you ever not in the forums? So do you have any idea what I'm talking about? You seem to be really good at this sort of thing...


tonyg(Posted 2007) [#21]
I didn't do any more work on it but this might help


Chroma(Posted 2007) [#22]
nm


Sonic(Posted 2007) [#23]
Hmm... This is what I'm using, based on your second example.

	Const FPS:Int = 60
	Const FRAMELENGTH:Int = 1000 / FPS
	Const MAX_FRAMESKIP:Int = 5
	
	Local nextframetime:Double = MilliSecs()
	Local loops:Int
	Local tween:Float
	
	Repeat

		' THE BIG BIT
		
		loops = 0	
		
		Local ms:Double=MilliSecs()
		
		While (ms>nextframetime And loops < MAX_FRAMESKIP)

			update()
			nextframetime:+ FRAMELENGTH
			loops:+ 1
		Wend
		
		tween=Float(ms+FRAMELENGTH-nextframetime)/Float(FRAMELENGTH)

		Cls
		
		draw(tween)

                flip (1)

       Until 0



Sonic(Posted 2007) [#24]
So I figure it happily flies when there's more draw() than update() called (the tween definitely works)...

But even when I force it to 30 fps draw() by using delay 17 (just over the length of one frame) it seems jerky. I know it's possible to be smooth in 30fps, so I'm wondering what could be causing it.

Hmm... The never-ending quest for smoothness continues.


deps(Posted 2007) [#25]
BTW How do I post a codebox?

You use [] with the word CODE in it. You can also use QUOTE like I did here. Finish it off with another [] with /CODE or /QUOTE
[quote ]This is a quote[/quote ]
[code ]Some code.[/code ]


I added spaces between the text and the ]
otherwise it would be interpreted.


Grey Alien(Posted 2007) [#26]
can you post some demo code of the jittering problem? Probably you just need some jitter correction code. Thing is if you start using timing code, it will never lopk as good as when you had none and locked to 60Hz BUT timing code is a neccessity for any pro game.

And yeah, I probably check the forum too often. I only check a couple of areas of interest tho so it's pretty quick.


Sonic(Posted 2007) [#27]
Hehe Jake I was only teasing... I think it's great! You've helped me out plenty, and you probably learn a lot yourself.

Anyway, the code I posted above is taken exactly from my game. The thing I'm not sure about is how Tony came from this:

         float newTime = time();  
         float deltaTime = newTime - currentTime; 
         currentTime = newTime; * OK.

         accumulator += deltaTime;  * OK

         while (accumulator>=dt)
         {
              previousState = currentState; 
              integrate(currentState, t, dt); 
              t += dt; 
              accumulator -= dt;  * OK.
         }


to this:

		loops = 0	
		
		Local ms:Double=MilliSecs()
		
		While (ms>nextframetime And loops < MAX_FRAMESKIP)

			update()
			nextframetime:+ FRAMELENGTH
			loops:+ 1
		Wend



The original author seems to be doing something extra in the update() phase - some kind of integration? Or am I being stupid?


Grey Alien(Posted 2007) [#28]
the original author was calling their update function Integrate, that's all. They were passing in more variables because it's a physics sim.

Does making FRAMELENGTH a float and doing 1000.0/FPS help?


tonyg(Posted 2007) [#29]
@Sonic
The second post I made was with code taken from a different article from the first.
First code taken from here
Second code taken from here


Sonic(Posted 2007) [#30]
So with the interest in my game on the forum, I thought I'd revive this thread to see if anyone can help me with my last stumbling block.

As I mentioned before I'm happily using the frameskip + tweening code at frame rates higher than the 60hz my logic runs at. However, when I introduce a delay of 17ms to ensure that it runs at under 60hz (and the nearest would be 30hz) it seems to jerk nastily. This is my code:


	Const FPS:Int = 60
	Const FRAMELENGTH:Int = 1000 / FPS
	Const MAX_FRAMESKIP:Int = 5
	
	Local nextframetime:Double = MilliSecs()
	Local loops:Int
	Local tween:Float

	Repeat

		' THE BIG BIT
		
		loops = 0	
		
		Local ms:Double=MilliSecs()
		
		While (ms>nextframetime And loops < MAX_FRAMESKIP)
			all.update()
			nextframetime:+ FRAMELENGTH
			loops:+ 1
		Wend
		
		tween=Float(ms+FRAMELENGTH-nextframetime)/Float(FRAMELENGTH)

		Cls
		
		all.draw(tween)

	Until 0	



Grey Alien(Posted 2007) [#31]
Why do you want to limit it to 30FPS, it will look better at 60...?


Sonic(Posted 2007) [#32]
No that's not it Grey - I'd like it to be runnable on machines that can only render at 30fps, hence introducing an artificial delay to test it.


Grey Alien(Posted 2007) [#33]
Ah I see, OK got it. Hmm I'm not really an expert on this sort of tweening code. Hope you can sort it.


tonyg(Posted 2007) [#34]
Does this code help any?


MGE(Posted 2007) [#35]
Sonic - Could you explain your main loop please? I've never seen a loop like that before? I can see the update being called as needed, but the tween value you pass to the draw routine confuses me, because the draw routine should just draw objects at their current position unless your draw routine is also moving objects based on the tween value passed? Thanks!


Grey Alien(Posted 2007) [#36]
That's what tweening does, it's a drawing thing. It doesn't move them, it interpolates between current and past (or maybe future) positions based on the tween and draws it there. It complicates drawing routines though which is why I didn't bother with tweening.


Gabriel(Posted 2007) [#37]
I can see the update being called as needed, but the tween value you pass to the draw routine confuses me, because the draw routine should just draw objects at their current position unless your draw routine is also moving objects based on the tween value passed?

That's right. The tween value is between 0.0 and 1.0 and represents how much of the last update you *should* have done. You only ever update in full steps, so your objects get ahead of themelves. The tween value is used in the draw function to linear interpolate between the position, scale, orientation, color, etc before the last update and the value after the last update.


dmaz(Posted 2007) [#38]
It complicates drawing routines though which is why I didn't bother with tweening.

a little but it's well worth it! I tweened all my Blitz3d stuff (using Marks code) and you could really tell the difference. My Invaders from Space looked 10 times better on a larger range of machines after I started tweening it. Most recommended. press the function keys in that demo to really see it in it's glory.

[edit] slowmo is a great tool, it allows you to see the animation defects that need to be fixed like with the little guy...


Grey Alien(Posted 2007) [#39]
Yeah but I did logic tweening instead so same difference and I have a slow mo mode too, I use it ALL the time to check out the effects I'm programming.


dmaz(Posted 2007) [#40]
oh I know... and you get slowmo with deltatime too. I just was mentioning it because I think the tweened slowmo looks smoother than any of the other methods.


Sonic(Posted 2007) [#41]
Yeah actually the beauty is it doesn't complicate drawing at all. All that's needed is an additional 'draw_x= ( current_x * tween ) + ( new_x * (1.0 - tween) )' etc. All my graphics derive from a bass class anyway, so it only needed to change one routine, rather than add delta time to all logic.

Still... something is slightly broken!

I will have a look at that code, Tony, hopefully I can spot a difference.


Chroma(Posted 2007) [#42]
I converted the whole Gaffer post about 4 months ago, including the RK4 (integrator function..etc) and it works silky smooth. If anyone is interested I can post it.

Here's part of it (non-RK4). Supply your own ball.png.

Press the Space Bar to see the Tween in action.

Part 1 (main.bmx):


Part 2 (Vec3.bmx):



Sonic(Posted 2007) [#43]
Hmmm, well I've double-checked your code Tony and it seems to behave identically to mine... probably because mine was taken from yours in the first place!

So I still have the problem of jerkiness when the graphics take more than one logic frame to redraw. I need to solve this to continue, but I'm at a loss.

Perhaps it's a problem with my introducing a Delay (17) artificially, but I don't have a slow machine to test on, and I can't think of any other way to force the redraw to run at half the logic rate.

[edit] Oh and Chroma - I can't really follow your code, even though it's well written! The main stuff seems to be the same, but could you explain the integration stuff to me?


tonyg(Posted 2007) [#44]
There are posts which discuss the jerkiness and GA created a test to even it out.


MGE(Posted 2007) [#45]
Seems like the code tony posted only runs smooth on my machine if it renders at refresh (vsync) speed. If you add delays so it skips vsyncs, you get the normal jerkiness.

If your game misses a vsync or 2, once in a while, you will get jerkiness, that's 100% unavoidable. The trick is to "do something" to stablize the frame rate or rendering so it's not so obvious when it happens. Averaging the delta over a period of frames can help, but it doesn't 100% get rid of it. What I do is give an option to the end user to run the game at a slower render speed. Sometimes it's better to run at a stable slower frame rate compared to the render loop speed being chaotic.


tonyg(Posted 2007) [#46]
Yep, that was the point of the post as I didn't understand why it wasn't smooth. Since then hrdnutz posted this with a code archive and GA posted this .
@JGOware, did you expand your code from this ?


Grey Alien(Posted 2007) [#47]
option to the end user to run the game at a slower render speed.
How did you do that?


dmaz(Posted 2007) [#48]
but I don't have a slow machine to test on, and I can't think of any other way to force the redraw to run at half the logic rate.

write a program that will take a lot of cpu time, allow control of that with a press of a button. now run that in the background when testing your app.


MGE(Posted 2007) [#49]
@Tonyg - Yes. I actually use two different timing options in my game engine. Dellta timing with averging or the more simplistic option you linked to. I choose which timing method I need based on the game type. For games that you pretty much need to run at full vsync all the time, I prefer the more simplistic timing method and if the end user can't run it full vsync, then they can turn some graphics options on/off render in lower resolutions, etc, which should allow it to run at 1 vsync.

@GA - Nothing techy, just using millisecs() to loop a bit at the end of the render loop until the requested frame rate has passed. The user can attempt to run the game at 20,30,50,60 if desired. Logic still happens at regular speed so you don't get slow down. But ofcourse objects will move greater distances at the slower frame rates.


Sonic(Posted 2007) [#50]
Hmm, I'm stumped, running a heavy program in the background produces the same effect as introducing a delay (ie stuttering). Unless I can figure out how to smooth out logic at 60hz and a frame rate below at, I can't realistically continue.


tonyg(Posted 2007) [#51]
I think you need to post the smallest demo which shows the problem.


MGE(Posted 2007) [#52]
As long as your internal logic is accurate, 99.99% of your end users won't care if the game jitters once in a while. Unless ofcourse your delay introduces some weird error in your logic handling? Otherwise, welcome to the world of PC coding, where the fix for the jitters is an endless quest. At some point you just have to think "that's good enough..." and move on.


Grey Alien(Posted 2007) [#53]
JGOware: OK thx.

Yeah post a demo, my PC never stutters on anything so we'll be able to find out if it's your PC or your code.
However it could just look bad simply BECAUSE it's at 30 fps. If the stuttering is regular and looks crap it's just due to the update being less that the refresh rate (like Amiga games running at 25Hz on a 50Hz TV (in UK)). If it's irregular then it's another problem...


Chroma(Posted 2007) [#54]
I just wanted to explain what the alpha(tween) variable is.

alpha = accumulator / dt

Alpha is the amount of interpolation between the previous frame and the current frame. It is a value between 0 and 1. 0 means that the value is fully set to the previous state. 1 means that the value is fully set to the current state. So a .5 would set the value halfway between the value of the previous state and the current state.

previous = 10
current = 20

alpha of 0 means that the value of 10 will be used.
alpha of 1 means that the value of 20 will be used.
alpha of 0.5 means that the value of 15 would be used.

A lot may already know this but for those that don't, it helps to be able to envision exactly what it's doing.


Chapman7(Posted 2016) [#55]
Sorry to bump such an old topic but I am having a weird issue. Chroma's post above which has two bmax files is an excellent port and I used that in my game.

The issue I am having is just before a Flip, I use WaitTimer if I want to limit the framerate. The problem is that (with 200 updates per second) once I start using WaitTimer, the updates per second either drop or raise slightly instead of staying at 200.

I'm having a hard time wrapping my head around why though, any ideas?


Chapman7(Posted 2016) [#56]
Main.bmx (Vec3.bmx is above)


When I limit the framerate to 30, the Updates Per Second jumps to 205ish instead of 200, when I limit the framerate to 1000, it goes to 211-212...


Chapman7(Posted 2016) [#57]
I'll send whoever can explain clearly why this happens, and how to fix it, $15 to their paypal.


Derron(Posted 2016) [#58]
You are working with floating point numbers.

So 0.05 becomes 0.049999998 or 0.05000012 or ... and then you are creating sums out of it. This might lead to odd scenarios in your while loop.

so there is a "as long as numberA is bigger than numberB".
Imagine numberA being 0.50002 and the subtracted value is 0.24999997. If you subtract, your remainder becomes 0.2500xxx5 - allowing another subtraction (an additional physics/logic call). If the numberA was 0.4999997 it might result in one logic call less.
This does not explain why it happens to have 5% off.

BTW: on my computer I got exact 200 and every 2-3 seconds a hickup to 201 (which fits nicely in my "floating point"-assumption).


Maybe you should log the values in your logic-while-loop (to a predefined array - and then outputting to a log file after finishing the whole app).


Another thing is:
	If MilliSecs() - SetTime > 1000
		GetFPS = SetFPS
		SetFPS = 0
		SetTime = MilliSecs()
		UPSSet = UPS
		UPS = 0
	Else
		SetFPS = SetFPS + 1
	EndIf

	newTime = MilliSecs()


so if you happen to have met the first condition ("1 second passed") you do something. This might ... because of some GC kicking in ... be delayed a bit. So when doing "SetTime = Millisecs()" the returned value might be different to the initial Millisecs() in the condition check.
So after the condition was met, a bit of time is already run until the "setTime"-assignment. This might lead to the next "fps-calculation" happening a bit earlier (1000ms minus "delay until new assignment"). Seems not to happen here ... so apparently not that problematic.


Back to logging - log what I described and you might see that there are floating point inaccuracies.


bye
Ron


Chapman7(Posted 2016) [#59]
Derron I was hoping for some code that solves it... I'm having a hard time just wrapping my head around the Timestep code in general.

When you tried it on your computer, did you click on another window so the app became suspended? Also if you change it to like CreateTimer(1000) I was seeing 210-211


Derron(Posted 2016) [#60]
My way to track it down:


When suspended I see it lowers to 97 of 100... initially blamed the timer and some inaccuracies there.


@ CreateTimer(1000)
No issues there.


But the lower, the more time goes by. With "CreateTimer(5)" I got a huge delay:

If MilliSecs() - SetTime > 1000
	'added:
	print MilliSecs() - SetTime


I see that with "CreateTimer(5)" I get ~1200 output, with higher Timers I get ~1000 (1000-1001).

A timer of 5 means: every 200ms (5 hertz).


Ok, and with some inaccuracy, it sometimes waits 197ms and sometimes 203ms
begin wait: 106358386
end wait: 106358583

begin wait: 106358585
end wait: 106358783

begin wait: 106358785
end wait: 106358984

Hmm, so in my case it was always a bit less than 200 ("begin" was printed before waiting, "end" was printed after waiting...so they ignore the time until the actual call).


Ok, so what does this mean?

Your WaitTimer always waits 200ms (in my example).
Your "FPS-Counter" sets the current UPS-count as soon as over 1 second was gone. It does not set the counter if "992 ms" were gone (x * 198ms in my case). It then waits until it reaches 1190ms (the next cycle).

BUT ... while it did not set the current UPS in that cycle, it will run the next round of "While accumulator >= dt" (and the logic-updates).

So in the time slot "1000 to 1190ms" it will run some updates which are then counted to the "1 second" (which in reality was 1.19s).



-----------

Conclusion:

	If MilliSecs() - SetTime >= 1000
		local secondsGone:Float = ((MilliSecs() - SetTime)/1000.0)
		GetFPS = int(SetFPS / secondsGone + 0.5)
		SetFPS = 0
		SetTime = MilliSecs()
		UPSSet = int(UPS / secondsGone + 0.5)
		UPS = 0
	Else


">= 1000" instead of "> 1000"
- you want to track a second, not 1.0001 seconds

secondsGone
- to be able to "scale down" the FPS/UPS values in the given time interval (something > 1000ms)

int(x / srecondsGone + 0.5)
- if secondsGone is 1.001 (so minimally over 1 second) it might round wrongly: 100/1.0001 = 99.999 - which is casted to an "int" as 99 (as it just truncates everything after the "." / it removes the decimal part). If we now would use "Ceil(x)" it would always round up, if we used "Floor(x)" we always rounded down. We now add "0.5" so the "int-cast" (truncation of decimal part) leads to the "economical rounding" (<x.5 rounds down, else rounds up).

0.99 + 0.5 = 1.49 = 1 (as int)
0.49 + 0.5 = 0.99 = 0 (as int)



bye
Ron


Chapman7(Posted 2016) [#61]
Thanks Derron! Email me your paypal address and Ill send you ze money.

One more Q if you don't mind... Why does WaitTimer(1000) not produce 1000fps/ticks? it seems to be under for me.

In the example above it's only a few off but on my main application its about 50 off

Edit: Nvm I think I got it


Derron(Posted 2016) [#62]
@ paypal

Send it to someone who needs it (some care/red-cross/-organisation - or to "Yue", think he is one of us in the forums who really earns too less) ... or if too time-consuming: buy your mom some flowers.


@ timer and "off"
Yes, the problem is what I described as "more than a second" (it measures fps/ups of eg. 1200ms but presents it as if it was done in 1000ms - which is why I added the scale-down).


bye
Ron