I have a simple event system:
class GameEvent{
float executionTime;
Action action;
}
class EventMgr : MonoBehaviour{
List<GameEvent> events = new List<GameEvent>();
void Update(){
float timeNow = Time.time;
for(int i=events.Count - 1; i >= 0; i--)
{
if(timeNow >= events[i].executionTime)
{
exents[i].action();
events.RemoveAt(i);
}
}
}
public void ScheduleEvent(float delay, Action action){
events.Add(new GameEvent(){
action = action,
executionTime = Time.time + delay;
});
}
}
Then,
I schedule events like this:
eventMgr.ScheduleEvent(0.1f, () => {
// EVENT A - should be fired first
};
eventMgr.ScheduleEvent(0.15f, () => {
// EVENT B - should be fired second
};
Everything works fine when I play on 60 FPS
. Update()
is fired once every ~0.016s
. When I play the game on a device with 20-40FPS
- things got a little bit tricky. Events seem to run in an incorrect order (Event B fired before event A).
The only possible cause is of course the framerate itself.
If the game runs at 20FPS
, Update()
would be called less frequently and both of these events would be fired in the same frame - and then, the order of their execution depends on the list itself.
What to do here? Is there any trick to prevent this, is there any pattern for accurate, ordered event system in games which is FPS friendly?
events[i].executionTime >= timeNow
) reversed? Don't you want to execute the events for which theexecutionTime
has already passed? \$\endgroup\$timeNow
is at0
andexecutionTime
is at1
it means that we've just scheduled an event for1 second
. Then,timeNow
grows, grows, grows and after one second it has a value like1.0013424
- which makes thecondition == true
, fires the event and removes it from the list. \$\endgroup\$executionTime
is greater thantimeNow
, what you just described is the opposite. iftimeNow
is at0
andexecutionTime
is at1
, thenexecutionTime >= timeNow
istrue
, notfalse
. The event will be fired immediately. \$\endgroup\$