every x milliseconds accuracy

This forum is currently in read-only mode.
  • well, for all you out there, the "every x milliseconds" has a huge problem.

    if you create an action let's say, every 1000 milliseconds (every second) add 1 to some global variable, you will be surprised how that "accurate to ~10 milliseconds" is going to affect this. well, after exactly 24 hours, the above variable, should count 86400... believe me, it will not. in this case, the ~10 ms after 2000 ms becomes ~20ms, so, after 86400000ms it's like ~864000ms = 864 SECONDS = which is like 15 minutes accuracy!

    to try it out, make a directx game, put text object somewere and add mouse and keyboard. add 2 actions:

    System: Every 10 milliseconds

    TextSet text to str(float(Text 0 .Text) + 0.010)

    MouseKeyboard: On Left mouse button Clicked

    TextSet text to "0"

    run the app and some kind of external windows counter (can be date and time properties / dbl click the taskbar clock) and click inside the game window, when the second hand comes to 0. watch as when it reaches 0 again after doing a full cirlce, the text is about 50 or something (should be 60).

    is there any way to prevent this from happening?

  • Every ... msec isn't suited for intervals so low they'll execute every frame. Your code is correct, but the thing is, every event can be triggered only once during single loop.

    You can make PV that adds timedelta per loop. And then you can check in WHILE whether its value is greater than desired "every ... msec" (but you input values in second units then).

    Check this .CAP:

    http://www.republika.pl/tymczasownik/ev ... WithPV.cap

  • Every ... msec isn't suited for intervals so low they'll execute every frame. Your code is correct, but the thing is, every event can be triggered only once during single loop.

    You can make PV that adds timedelta per loop. And then you can check in WHILE whether its value is greater than desired "every ... msec" (but you input values in second units then).

    Check this .CAP:

    http://www.republika.pl/tymczasownik/ev ... WithPV.cap

    tymczasownik, lol

    poland ftw!

    as I remember from earlier testing, timedelta also has problems with accuracy, but you have a point.

  • Timedelta is basically the time between last and current frame. You know how wildly FPS can fluctuate.

  • if you want time elapsed from the beginning you're better off using Timer (system - get time)

    To fire off an event every certain amount of miliseconds with long-term accuracy, you could do something like

    +compare Timer%MyFiringPeriod less or equal than MyFiringPeriod*0.4

    +Fire once while true

    Timedelta will always have rounding errors which will accumulate to something hideous.

    Even if its precision was to the milisecond, rounding errors would still crop up when you accumulate.

    This timer, of course, will wrap after a certain amount of days (which I'm too lazy to calculate). Adjust accordingly.

  • Timedelta's theorethical accuracy makes about 0.0001% error coming from using float for it. But if there was some practical tests made, I'd love to hear about them ^^.

  • Try Construct 3

    Develop games in your browser. Powerful, performant & highly capable.

    Try Now Construct 3 users don't see these ads
  • Sorry, learned this in physics a while ago.

    You just *can't* take a value and do calculations on it and expect the error not to grow.

    Timedelta is in seconds, thus 0.0001% of timedelta amounts to 0.000001* = 0.0001ms error

    that over a day is: 24 hours * 60 minutes * 60 seconds * 1000 miliseconds = 86400000 ms.

    the error thus will be bounded by 86400000 * 0.0001ms = 8640ms

    That is, off by eight and a half seconds.

    Of course, float's rounding error is not fixed and timedelta's error depends on the internal timer resolution, which could be QueryPerformanceCounter(). I read that one has microsecond resolution, which is nice. Still, it's not exact. It cannot be. Nothing is.

  • Hmm, I didn't think this would be a problem. Can someone put up a quick .cap that demonstrates this? (preferably one I don't have to wait a day to see)

  • I don't think it is a problem actually.

    One has to blow up the error almost on purpose. I could do one example anyway, but there would be glaring ways to fix it without having to rewrite anything in construct.

    I'd say it's more of a design issue on the game's side. I've worked with SDL and it had a terrible timer resolution, yet I managed to make smooth accurate movement using a few tricks here and there (which are perfectly doable within Construct but somewhat unnecesary).

    That said, it would be nice to redefine Timedelta before behaviors touch it. Is that doable? One could rewrite timing at will that way without having to renounce behaviors.

    Right now it *can* be done (look at my frameskip example ) but you have to forget about any behaviors that use Timedelta.

    Edit: it would seem I'm contradicting myself I'm not. I'm just saying that while rounding errors do accumulate (in everything), one can just avoid accumulating them. Just look at Euler versus Verlet integrators in physics, both come from the same Newton equations, but one of them accumulates rounding error while the other cancels it.

  • Since I don't know how was this solved by programmers, experiments will show some stuff.

    Here is the simple "add timedelta" thingy:

    :arrow: Text('t') adds timedelta meaning it counts seconds

    :arrow: Text('t1000') adds timedelta*1000 meaning it counts miliseconds

    :arrow: Timer retrieves play time

    And all those errors provide difference between Timer and Text('t')*1000 or Timer and Text('t1000'). The [msec] error doesn't divide stuff, the error divide result by 1000.

    http://www.republika.pl/tymczasownik/timerCountingError.cap

    <img src="http://www.republika.pl/tymczasownik/timer_error.png">

    :arrow: Timer is based on adding timedelta

    :arrow: 1000*timedelta produces numerical errors

    :arrow: Numerical errors are random (one time positive, one time negative) and that leads to minimalizing the error

    :arrow: The bigger the time is, the bigger numerical error is produced on every tick

    :arrow: 0 error for adding nonscaled timedelta doesn't neccesary mean that Timer is compatible with system time (well, actually who'd bother if there was like 0.001msec error during the longest play possible?).

    I'm now leaving program on to see results after some time...

    <img src="http://www.republika.pl/tymczasownik/timer_error2.png">

    Because errors are random, maybe after few hours the error will be positive value ^^.

    Maybe there's a better point in checking this incrementing with Profiler's "getTickCount()"? I remember using getTickCount() and it's resolution wasn't really pleasing, is it the same way in Construct's profiler?

    Edit:

    <img src="http://www.republika.pl/tymczasownik/timer_error3.png">

    ...positive :-).

    Edit2:

    <img src="http://www.republika.pl/tymczasownik/timer_error4.png">

  • BROO: Your application does not prove anything wrong with Construct's timers. Construct uses double-precision timers using QueryPerformanceCounter, which is accurate to microseconds or better. The 'timer' system expression returns the sum of all past timedeltas (in effect, the runtime is doing what your 't' variable is doing, adding all timedeltas). So 'timer' is not the system timer, there's no way to retrieve it in the runtime currently, since it's difficult to apply timescaling to the system clock. In effect, the .cap you posted merely explores the effect of double-precision rounding errors when you multiply a number by 1000, which is independent of any timers.

    I realise the timer in the runtime therefore may accumulate a rounding error from summation of the timedeltas, and I might be able to improve the resolution of this in the next build. Still, the error shouldn't be large except over long durations.

  • So 'timer' is not the system timer, there's no way to retrieve it in the runtime currently, since it's difficult to apply timescaling to the system clock.

    :O could we get a way to retrieve the unscaled system timer? I've been assuming it was.

  • I don't think it is a problem actually.

    One has to blow up the error almost on purpose.

    well for me it is a problem, for some reason (don't ask :) I use every 50ms to do something, and every 1000ms to do something else that should be done exactly after running the first event 20 times. and between the 20th time and the second event there is some lag always, because, the 19th time is not after 950ms, but about 900ms... I think, this kind of accuracy will spawn multiple problems in the future, so if possible I think it should be corrected.

    a cap is available here:

Jump to:
Active Users
There are 1 visitors browsing this topic (0 users and 1 guests)