Syncing multiple game elements with lag

Does anyone have some advice for syncing multiple actions going on with each other so that lag (caused by other phone processes activating while playing the game) will affect all equally. 

For example, I have a character that moves right or left using applyForce and up or down based on jump actions and gravity.  I also have objects throughout each level that move or rotate using transition.to.  There is also a count up timer (using delta time) that runs to record the time it takes to finish the level.  And I have a recording function that records the characters’ X, and Y coordinates at a set interval.  This recording can be played back using transition.to so that the player can race against a ghost player of their best time. This playback operates based on the count up timer and the recorded time stamp intervals. 

All these things seem to be affected differently by lag, the frame rate, and maybe even the processor speed of the device the user is on.  

Does anyone have any advice on how to sync all these things up so they would be timed more perfectly relative to each other and to lag?

Thanks in advance for any advice.

Hey, I would advise not using transitions and instead manually animate in an enterFrame() event.  You can use delta time to workout exactly the position of objects based on their last position and the delta time passed.

This will explain things https://coronalabs.com/blog/2013/06/18/guest-tutorial-delta-time-in-corona/

Thanks for the reply Adrian… I read the article and I have a concern. If the active character is racing against his former ghost recording and delta time is in use, then the device lags, wouldn’t the active character slow down due to the lag while the ghost recording continues on the delta time pace?

What I would do is split the players journey into n data points - lets call this 100 for simplicity.  You know the start time so you can then use a high resolution timer to record the delta times per data point.  Something like this will help

--timing functions local startTime = nil local dataPoints = {} function startTimer() startTime = system.getTimer() dataPoints = {} end function stopTimer() local totalTime = system.getTimer() - startTime startTime = nil end function getElapsedTimeFromTimer() local elapsedTime = system.getTimer() - startTime --log current position dataPoints[#datapoints+1] = {} dataPoints[#datapoints+1].time = elapsedTime dataPoints[#datapoints+1].x = player.x dataPoints[#datapoints+1].y = player.y print("Time = "..math.round(elapsedTime).." ms") end

Using an enterFrame() listener you can record the data points for the first run ( using getElapsedTimeFromTimer() ). On the second run you can use the players current delta time to loop the dataPoints array and find exactly where the ghost should be (you might need to extrapolate between two dataPoints.

Thanks again Adrian, i really appreciate your advice… it sounds like you truly know your stuff.

That’s, actually, exactly what I am doing to record and playback the player ghost. And it works great… but the problem comes in when I experience lag on my device. The active player lags as the frame rate slows while the ghost stays perfectly in tune with the timer, which references delta time. It makes it unfair for the active player when lag comes into play.

I’m trying to find a way to keep all entities in sync throughout lag.

Hey kthompson200, you missed my last point about adjusting the ghost position based on current player elapsed/delta time.  There will be some maths involved but I’m sure you can figure it out.  You need to calculate where the ghost should be relative to the current player coords at any given millisecond.

For example, if the player has moved 4 squares but for a delta time of 50ms and the ghost has logged 6 squares for a delta time of 80ms then the ghost has effectively moved 6 * 50/80 relative to the player for the given delta time.  This should keep the 2 in sync irrespective of timing fluctuations.

To be honest, unless you have thousands of moving assets you shouldn’t experience any lag.  Optimisation is key!

I guess I did miss that… I’ll put some brain power into your recommendation and see if I can find a solution. Thanks again.

I do have a lot going on… mostly graphics processing… but I’m certain I could have been better at optimizing this beast along the way.

So I move my active player by using the myJoint.motorSpeed function.  How would I set this to reference delta time and keep the ghost in sync irrespective of timing fluctuations?  I guess I’m just not seeing the math just yet.

I just had a bit of an idea… my clock timer doesn’t really have to be relatable to real time. So what if I create a timer that updates every frame (if that’s possible) and reference it for everything? Would that sync everything up the way I’m thinking it would? If so do you see any other potential problems from doing that?

So my idea seems to have worked and suits my needs perfectly.  What I learned was that Corona has two sources of time… so to speak.  transition.to and timer.perform with delay are based off OS time while most of the physics engine works off of frame rate.  I just made sure the pertinent parts of my game were in sync with the frame rate by creating my own frame rate timer and all is well.  Thanks for helping talk me through this Adrian.

Hey, I would advise not using transitions and instead manually animate in an enterFrame() event.  You can use delta time to workout exactly the position of objects based on their last position and the delta time passed.

This will explain things https://coronalabs.com/blog/2013/06/18/guest-tutorial-delta-time-in-corona/

Thanks for the reply Adrian… I read the article and I have a concern. If the active character is racing against his former ghost recording and delta time is in use, then the device lags, wouldn’t the active character slow down due to the lag while the ghost recording continues on the delta time pace?

What I would do is split the players journey into n data points - lets call this 100 for simplicity.  You know the start time so you can then use a high resolution timer to record the delta times per data point.  Something like this will help

--timing functions local startTime = nil local dataPoints = {} function startTimer() startTime = system.getTimer() dataPoints = {} end function stopTimer() local totalTime = system.getTimer() - startTime startTime = nil end function getElapsedTimeFromTimer() local elapsedTime = system.getTimer() - startTime --log current position dataPoints[#datapoints+1] = {} dataPoints[#datapoints+1].time = elapsedTime dataPoints[#datapoints+1].x = player.x dataPoints[#datapoints+1].y = player.y print("Time = "..math.round(elapsedTime).." ms") end

Using an enterFrame() listener you can record the data points for the first run ( using getElapsedTimeFromTimer() ). On the second run you can use the players current delta time to loop the dataPoints array and find exactly where the ghost should be (you might need to extrapolate between two dataPoints.

Thanks again Adrian, i really appreciate your advice… it sounds like you truly know your stuff.

That’s, actually, exactly what I am doing to record and playback the player ghost. And it works great… but the problem comes in when I experience lag on my device. The active player lags as the frame rate slows while the ghost stays perfectly in tune with the timer, which references delta time. It makes it unfair for the active player when lag comes into play.

I’m trying to find a way to keep all entities in sync throughout lag.

Hey kthompson200, you missed my last point about adjusting the ghost position based on current player elapsed/delta time.  There will be some maths involved but I’m sure you can figure it out.  You need to calculate where the ghost should be relative to the current player coords at any given millisecond.

For example, if the player has moved 4 squares but for a delta time of 50ms and the ghost has logged 6 squares for a delta time of 80ms then the ghost has effectively moved 6 * 50/80 relative to the player for the given delta time.  This should keep the 2 in sync irrespective of timing fluctuations.

To be honest, unless you have thousands of moving assets you shouldn’t experience any lag.  Optimisation is key!

I guess I did miss that… I’ll put some brain power into your recommendation and see if I can find a solution. Thanks again.

I do have a lot going on… mostly graphics processing… but I’m certain I could have been better at optimizing this beast along the way.

So I move my active player by using the myJoint.motorSpeed function.  How would I set this to reference delta time and keep the ghost in sync irrespective of timing fluctuations?  I guess I’m just not seeing the math just yet.

I just had a bit of an idea… my clock timer doesn’t really have to be relatable to real time. So what if I create a timer that updates every frame (if that’s possible) and reference it for everything? Would that sync everything up the way I’m thinking it would? If so do you see any other potential problems from doing that?

So my idea seems to have worked and suits my needs perfectly.  What I learned was that Corona has two sources of time… so to speak.  transition.to and timer.perform with delay are based off OS time while most of the physics engine works off of frame rate.  I just made sure the pertinent parts of my game were in sync with the frame rate by creating my own frame rate timer and all is well.  Thanks for helping talk me through this Adrian.