The big TimeDelta headache

This forum is currently in read-only mode.
From the Asset Store
Jump over the small square and avoid hitting it as long as you can!
  • I checked out the link you posted Kayin - it's a very good article, the best I've read on the subject. However, I'm still not convinced by variable rate logic. Firstly, as the article mentions, it could substantially increase CPU usage, especially with a high logic rate. Secondly - and I don't think the article covers this - if logic runs at a rate which is not a multiple of the V-sync rate, then you can get uneven motion. Lets consider easy numbers - VSync = 50Hz and logic = 75fps - for every VSync you alternate between 1 logic update and 2 logic updates. This means between screen updates, objects will move twice as far every refresh. I don't think this would look as smooth as the current system we have. Interpolation is an interesting idea, but I fear it's too difficult to retro-fit it to our current engine (and it would make eventing a custom movement much harder).

    Well glad it was a good article and a good read! Yeah, which seems why a much higher logic rate would be better -- with obvious potential problems. It'd be nice if there was a good way to tell how much cpu the logic in comparison to the display. Just for theory sake. But anyways a lot of this will depend on how easily you can program it and have it work appropriately. What issues would this have with custom movement engines, for example? is it a more technical issue?

    Anyways, as I think about it,the best way to handle this might be on the event list side. Say a loop-esque feature that times an event for x times a second. Basically, updating the chosen logic at the rate desired (sort of like setting it on the timing but it will interpolate how many times it has to run it per tick). I'd set this like a function. Like

    -On Independant Logic "hurfdurf"

    --Game jumping/moving logic.

    and then like

    -on start of frame

    -- set Independant Logic Rate "hurfdurf" 100 cycles per second

    This might even be doable with stuff already provided. The only problem involved in this is that animations would likely not sync up appropriately and we would need some way to control that. I personally like setting all animation speeds to zero and manually forcing 'tick' updates on the animations, but thats just seems like what would be the easiest answer from my view.

    Assuming there was some option to run logic at a multiple of the vsync rate (eg. 5x logic runs per vsync), and assuming timers and user input were updated between these separate logic executions, I guess it might be possible to reduce the inaccuracy by reducing the quantisation effect error. I think this could be programmed like Motion Blur, but without the rendering of logic-only runs.

    [quote:1u9nnqgi]

    If it's easy to program, I might give it a shot. I don't think I can truly have keyboard input update fairly in logic-only runs, but it might work. It is a very CPU intensive way of solving the problem though - I have no choice but to execute the full event list, not just the motion/timer based ones, in logic-only runs. And I don't know if it'll even help solve the problem significantly. What do you think?

    By the way, I've noticed fullscreen games run with very consistent timedelta values - they are usually exactly equal to 1 / vsync rate. It's only windowed games which suffer random timedelta variations, probably because Windows treats fullscreen apps with a higher priority.

    I thank you for considering this as always and hopefully we can come up with a solution to the problem some of have. I don't see how this wouldn't solve the problem -- more the issue I;'d more think is if it'd cause more problems (by being stuttery or something). Maybe I'll take a stab at making an engine that does this with the available features as a proof of concept (ignoring animation issues).

  • Try Construct 3

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

    Try Now Construct 3 users don't see these ads
  • I realise my little 'for' loop accuracy thing doesn't actually increase accuracy, it does however lessen the jump of timedelta based custom movments at low fps

  • I did some basic tests of the concept I described. The code is pretty darn simple.

    Always: Set Count 1 * (60 * timedelta)

    This value basically is equal to how many ticks of logic should have ran at this point. 60 can be whatever you want your logic rate to be.

    For the test I used a black box coded to move with the code.

    While

    -Count Equal Or Greater Than 1

    And then had the event as

    Subtract 1 from Count

    Set Position X (X + whatever)

    I tested it alone and then injected it in my game so I could test it under stress. The results were pretty great -- it seemed no less attractive than the normal, low FPS movement yet, if it were a more complex engine, would be far more accurate in terms of pixel exact movement (probably at an impercievable cost of time accuracy). I'm thinking this could be programmed to use the loop function but I'm not sure how that handles I take it it runs each loop event once then repeats instead of going, say.. "loop event A 3 times. Loop even B 3 times. Loop event C 3 times."? I don't have the time to test right now.

    Still, construct at low FPS seems extra stupid ugly for some reason. Maybe it's just my code in general? Who knows, but heres my thought. My idea of time scale smoothing for frame rate is a little weird and as I think about what I would do if I was making a game from the ground up would more involve not letting the FPS jump wildly in the first place -- Basically even out in frame updates instead of on a timescale basis. Would that sound more like a reasonable developers decision, Ashley.

    With this process I'm still sort of concerned about properly linking animations to the logic refresh rate, but as I think of it it might not be a problem (though as I'm using animations as almost a timing function, I'm a little anal about this -- but I think I'm in the VAST minority). Thoughts on this? I could upload examples but it seems pointless as it's such an easy little setup. I might try plugging my entire engine in like this at some point and testing that to see how much the logic eats away at the framerate.

    Thoughts anyone? I'm particularly curious as to what you think, Ashley, especially because this direction would mean less work for you -- but I'm not sure if it'/s the right one. It seems good and intelligent to me, but I'm a fake programmer.

  • Things get more interesting now. I tested it and converted the base chunk of my engine. It works well. It also gives me a way to control the time delta 'shimmie' that seems to happen a lower framerates.

    Currently my engine is tooled to run at 60 ticks. At runs pretty okay at lower FPSs but gives the appearance of relatively lower frame rates Not very bad, but a notable problem with a solution. I'll, at one point, have to try and retool the engine to a higher logic rate -- not a big deal, just tweaking values. Like that, it should be good even at low frame rates. I was able to run the logic at -1000- cycles and the frame rate was still pretty good. I think 100 or 120 cycles will be easily handleable even with a relatively complex engine like mine. Zipping around at insane speeds with pixel perfect accuracy? Priceless.

    Anyways if you look at the code,you'll notice a logic limiter right now. It's set to 2,meaning logic can only update a max of 2 times.This nearly kills all the positional jerkiness under lower FPSs (30-45). What was weird is while watching the logic counter tick up, I'd occaisonally see numbers like 7 or 9 while running primarily at the 45 fps range. Really at 45 there should never be a number larger than 2 -- maybe 3 somehow? But yeah. Thats ODD, but it's not an issue now. if I increase the logic rate (which I believe I wll), I can up this probably to 5 or something and still keep things hella smooth.

    I think this is the most productive path to follow for us super anal developers and again, I'd like to hear Ashley's opinion on this all to make sure it's a safe course ot proceed down.

    http://kayin.pyoko.org/logicspeed.cap

    This is the example. Note that not all of the engine is converted, just the very minimal (jumping,gravity and horizontal movement), so theres some weirdness with some of the stuff like dashing and air dashing. All the relevant core logic stuff is the first view events. As you can see, this is a very simple to implement and even still benefits from things like timescale!

  • I've thought about this idea and it's interesting... one thing I'm sure of, is that the logic rate should never be less than the display rate. If this happens, eventually you end up drawing the screen with no logic runs in between, which results in an uneven display. Your example uses 60 - my refresh rate is 75 Hz so this would be happening for me. I noticed the scrolling seemed to be jittering side to side constantly, maybe that's a side effect of that.

    Next problem is that you might get uneven logic runs - alternating 1 and 2 logic runs per display means you'd move twice as far in one display than the next - but I guess we can live with that, since everything is pixel perfect precision. V-synced display is not perfect in windowed mode - it's much more reliable in fullscreen - so V-synced windowed games tend to 'drop' a frame (ie. miss a V-sync) every now and then. This could explain the logic running a lot to catch up when the next tick runs.

    So it's a nice way to go about coding things - the only catch is if this is to be built in to the runtime, it can't distinguish movement code so would have to run the entire event list every logic execution. This might be OK I guess, but it might also use a lot of unecessary CPU. I would prefer to avoid using a trigger like 'On logic execution', because it won't integrate nicely with other features (ie. in theory it should be able to easily switch between a timedelta'd platform engine to a fixed rate logic platform engine without recoding the whole thing). If a 'fixed rate logic' mode was enabled, combined with 'override timedelta' (so timedelta is constant), this would achieve a similar thing, but at the expense of running the entire event list.

    Your engine looks pretty good at the moment - you might find it more convenient to simply put all the movement code as a subevent to a single trigger (saves repeating the condition all the time). Also, the Function object does what you're trying to do with fastloops (a one-run fastloop is effectively a function). And as mentioned, you probably want to boost this to at least 120fps logic.

    So really for a pixel-perfect engine which is as efficient as possible, you've hit on the right way to do it already! It can be done entirely with events. Do you think it should still be a built in feature, at the expense of running the entire event list?

  • Yeah I just boosted the rate to 120 not too long ago and adjusted the all the values to match the speed. It works pretty nicely I'd say. Yeah, the uneven movement is there but it seems mostly unnoticeable, but it is a flaw. Granted if you run at higher logic rates which I think a lot of games could easily get away with (IWBTG for example which has a very simple engine), the difference would be very hard to notice. at all

    But yeah at this point I don't think a built in feature is really a necessity. I think this is actually better in a way as it's more customizable and easy for me to select what needs to be time sensitive and what doesn't.I would perhaps want features that would facilitate precision games such as manual animation 'tick' advancement, which could be useful elsewhere too, but I think this is rather low priority. I'll try and make a simpler 'tutorial' example with comments and maybe write a small tutorial so people who are in situations like me or the original poster won't have to bug the crap out of you.

    I'm just happy I don't have to annoy the hell out of you about this anymore. Thanks for your advice and patience through all my bitching and long winded posts.

    (I'll also look into the function thing. This is as good a time as any to restructure my engine a bit and clean things up)

  • :P I'm just happy I don't have to annoy the hell out of you about this anymore. Thanks for your advice and patience through all my bitching and long winded posts.

    Does this mean no more walls of text between you and Ashley any more? This is truly the end of an era

    Glad to see you have come to a resolution though

  • > :P I'm just happy I don't have to annoy the hell out of you about this anymore. Thanks for your advice and patience through all my bitching and long winded posts.

    >

    Does this mean no more walls of text between you and Ashley any more? This is truly the end of an era

    Glad to see you have come to a resolution though

    Hahaha, I certainly had a "lol" at that one. A friend of mine frequently joked "Hows your novel coming along?" if he was over while I was making a post on the issue (or occasionally some other issues elsewhere ). But yeah, I don't think we're going to come across an issue that required this level of headbanging.

    I'm just glad everyone gets to be happy in the end and that the solution is extremely elegant in implementation and it didn't require Ashley to use up his valuable time. I'll be writing up a tutorial for this (and maybe other time delta issues/solutions) in the future. Hopefully this won't have to come up again -- and if it does, hopefully it'll be a much smaller issue.

    It'll be sad without having anything to rant about.

  • It'll be sad without having anything to rant about.

    Try this:

    [quote:38k3xxb3]We�re all going to die, you know that don�t you? One of these days, probably during Friday rush hour, there�s going to be a 9.9 Earth quake and then it�s all going to come down. No more Taco Bells, no more Rite-Aid, no more little oompah-loompahs making chocolate for Willy Wonka. It�ll all be over.

    At first I thought that this would be kinda cool. You know, puts me on an even footing with the BMW�s and the cool people. When society breaks down, people like me with street smarts, who graduated from the school of hard knocks� the lower to middle class people will inherit the earth - survival of the thickest. Just think: people freak out when their toilet doesn�t flush right or they can�t login to Live Journal. What�s gonna happen when Starbucks runs out of coffee? Maximum anarchy.

    Anyone who lived through the Los Angeles riots knows what I mean. Back in 1992, we were all appalled at the looting and burning but we could all console ourselves that in a couple days it would all be over. No such luck come doomsday� and no one, including myself, has made any provisions or taken any precautions to prepare for this Apocalypse. When the �big one� happens, I�ll be fucked just like everyone else. I�ll have to recycle my feces to power my car� and start eating veggies and tree bark. It will be a real horror show living day to day� no more Kurt Russel�s, no MTV, no more fear of aids� in other words, normal.

    This service announcement has been brought to you by the letters and numbers OU812� thank you� please drive through�

    ~Sol

  • Wow that's just great Kayin!

    Just had to add 2 events to my exisiting engine and make the whole movement stuff subevents. And that's it, works just fine!

    I think my very own TimeDelta headache may be finally gone now. Thx a lot!

  • No problem! Believe me, I'm thanking my self too! This has been a big headache for me. Now its time to put together some more examples.

  • i dont feel like using the delta!!!!!!!

    im against the man

    no kidding ashley, im just lazy to insert that thingy everywhere

    edit:well i actually read your post now and i must say, you are alot like me, anal wise lol. i too try really hard to get things perfect, always thinking it should run perfectly how i invisioned it, and never do something i didnt intend, but after a while you realise that everything doesnt have to be perfect, infact every shouldnt be perfect or else youll spend way to much time trying to keep things perfect while you should be working on the game. games arent good because they have beautiful programming, i cry because of this but its the truth, just like how animators in 3d movies get no props, yet the actors who voice a character get emmys or wtv ugh

    you gotta realise that good games are good cause their fun, not cause everthings perfect, world of goo is super fun, but it has lotsa problems and things i would never let fly, but the thing is, thats not what makes it bad or good. a slight animation bump and things like that are annonying to us, but to a player they dont really care, its only the experience which is returned to them which matters. i love over complicating things so their perfect but it always ends up making something fruitless cause it takes to long. i do like how you made this problem simple tho, i would like to see a tut

  • I know this is old but I DO have something to contribute.

    In YEARS of discussing this bit (sometimes heatedly) with fellow coders, I found out that the best thing to have is:

    -fixed logic rate, to gauge minimum object size and max speed, thus making sure no object will ever go RIGHT THROUGH another.

    -decoupled vsynched graphic updates, for maximum smoothness

    -interpolated animation: this is key. Without this, you better couple logic with the graphics update rate or it'll look strangely jerky.

    But you all knew this. Now comes my contribution:

    I also spent a long time fighting timer issues, because the timer I was using (SDL) has a really crappy resolution (10ms!!)

    So with that low low resolution, animations and general game logic used to jump around a lot. First approach was to average over a number of frames, then the game would go smoothly over that number of frames and then jump to the new framerate, so that's no good either.

    The next approach is really good and gave me solid animation with a crappy timer:

    -Keep a circular buffer, save the the timedelta in a new cell and move the head in each update, average all stored timedeltas and return that.

    TADA! high-precision non-jumping timer feeding from any timer, crappy or not. That added to the (already in Construct) minimum FPS makes for a SOLID and smooth logic.

    Suggestion? Could specify the size of this circular array in application properties Larger takes longer to adapt to FPS changes, smaller could be jerkier. I kept using 10 to 20 cells and that was enough (remember, I had 10ms resolution!).

  • There's always QueryPerformanceCounter, which is accurate to microseconds, and available to any C++ program. Construct uses it.

  • Back at the time I wasn't aiming at Windows only

    Just thought it would be nice to share, that circular buffer trick works under the most horrid timing conditions

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