TL;DR - Trying to control sprites with the platform behavior using a list of per-tick instructions has different results every time, even with a fixed time step. Why?
Hello. I've been trying for a while to make some cinematics wherein sprites with the platforming behavior move as if controlled by a player. Instead of recording gameplay and displaying video, I would like to use a text file with instructions for how objects should move. This is the method I came up with:
I understand that, in order for the movement to remain consistent, I need a fixed timestep throughout the cinematics - so I set the minimum deltatime framerate to 99999 when recording and playing input. I expected this to be the only precaution I'd need to take - but it seems like I was wrong.
Sprites following the exact same instructions behave slightly differently each time, and these inconsistencies add up to make them end up in completely wrong places. I have no idea what could be going on, and I unfortunately cannot provide a capx file since it's a commercial project quite deep into development.
I have tested and am fairly sure that:
I know I shouldn't expect perfect precision from a computer when positioning sprites and such, but what I am attempting seems feasible, and a similar logic is used in many games for showing replays, so it shouldn't be impossible.
Am I missing something obvious? Can anyone who has used a similar method before shed some light? Does anyone know a better way to achieve a similar effect without playing video? Thanks a bunch
Not sure what you mean by per tick, or min frame rate, but I would timestamp based on the time elapsed since the layout started.
Then record what the action, and time was.
Any reason you set the minimum framerate to 99999 instead of 60?
I did a test and didn't set the minimum framerate and recorded the input. I was at a consistent 60 fps so that was good. Playing back was spot on, I did some stuff to create lag and the replay was failing. I set the minimum framerate to 60 and the replay looked perfect again. However if I set the minimum framerate to 99999 instead of 60 the replay failed badly. My guess is something non-intuitive is occurring with such a high value.
Wow, that was fast. You guys are awesome, thanks!
When I say 'per tick' I mean that every frame I append numbers - which identify current input - to a text file. Later I can read that file and have the game simulate the input that was down in each frame, in order, as if I was playing the game and doing the exact same thing.
When I say 'Minimumframerate', I'm referring to a system expression which caps deltatime - so I can use it to make my game framerate dependent and do more precise stuff like this.
I hadn't considered timestamping it, that is an excellent idea, yes. I'll let you know how that turns out. Thanks for the quick response!
I've set it to 99999 because, when set to 60, displaying "dt" every tick shows a value which changes slightly per frame, which I thought could be the cause of the problem. I've tried again with 60 just to be sure, and still get the same results.
The changes are quite slight, so it can be hard to notice if you only have a sprite moving around on its own. My game has moving platforms and hazards, which can make a tiny difference mean a lot more.
Would you mind sending your capx so I can compare the way you did it with mine and see if I've done something silly? Thanks for helping out so quickly!
I don't have Web access on my computer currently so maybe I'll be able to send it tomorrow.
I did some more testing with it. I recorded for 27 seconds and observed the final location. It varied maybe a thousandth of a pixel so it's not exact, and I can see how it can get further off as the recording gets longer. Dt does indeed vary slightly because the time between frames varies a little, and the the minimum frame rate is only used if dt is greater than it.
So instead I tried a framerate limit slightly higher than 60 like 64.
On chrome it worked well in giving me a constant dt and after a 37 second recording the end position was exact every time.
Edge didn't work so well with that. I was still getting a different dt occationally which made the end position off by around a pixel after 37 seconds. I tried 9999 but looking at dt it seems 1/120 is the minimum dt on my machine for chrome and edge.
But that also made my game run at half speed. Does your game run at the same speed?
Yes, it does. Using Minimumframerate is a temporary measure - once I get this to work, I'm planning on using some clever maths to set the timescale dynamically in a way that stabilizes fps without messing with speed much. For now, the game running slower isn't a much of a concern.
I have made a small project which makes it very very easy to reproduce the issue - all you need to do is follow the instructions on-screen. I'll post a link to it since I can't for the life of me figure out how to attach files:
Oh ok, I'll look at your capx later when I get the chance.
An idea just came to mind. Since setting the minimum framerate to 120 or higher will make dt be a constant 1/120, you could set the time scale to 2 to get a constant dt of 1/60 so that it wouldn't be half speed.
The thing is, time scale works precisely by changing the value returned by dt, so once I lock the framerate using minimumframerate, dt stays the same and timescale changes have no effect. This is the reason why I'll have to figure out another way to get a constant timestep.
Develop games in your browser. Powerful, performant & highly capable.
Here's my example. It plays back perfectly every time with chrome and probably nwjs.
https://dl.dropboxusercontent.com/u/542 ... cord2.capx
Looking at yours the only difference that may need investigating more is the save/load state. Maybe there's a delay or something.
I don't think it's the save/load state that's causing it... I switched mine so that, instead of saving and loading, it restarts the layout when you start recording and when you start playing, and it's still wildly inconsistent.
Your example does play back perfectly every time. I was under the impression it was due to less room for error, but then I made the character and moving blocks faster, then artificially lowered framerate, and still got identical results. I am not sure why mine doesn't work, but I'll try and adapt your code into my game and see if it does. Thanks for your help!