How to make a custom event system framerate friendly?
Clash Royale CLAN TAG#URR8PPP
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty margin-bottom:0;
up vote
1
down vote
favorite
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(events[i].executionTime >= timeNow)
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?
unity events frame-rate
add a comment |Â
up vote
1
down vote
favorite
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(events[i].executionTime >= timeNow)
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?
unity events frame-rate
add a comment |Â
up vote
1
down vote
favorite
up vote
1
down vote
favorite
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(events[i].executionTime >= timeNow)
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?
unity events frame-rate
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(events[i].executionTime >= timeNow)
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?
unity events frame-rate
unity events frame-rate
edited 1 hour ago
asked 1 hour ago
Spectre
1,8402733
1,8402733
add a comment |Â
add a comment |Â
2 Answers
2
active
oldest
votes
up vote
3
down vote
accepted
This looks like you could solve it with a priority queue or min-heap. The code to process the queue would look something like this:
while(eventQueue.Count > 0 && eventQueue.Peek().executionTime < Time.time)
eventQueue.Dequeue().action();
This means you have only one check to do on frames when no events happen - you don't have to scan the whole list.
The nature of the priority data structure ensures that the next event to fire is always the first one you check, and when multiple events fire in the same frame, you process them in non-decreasing order of executionTime
.
Insertion and removal from such a data structure are typically logarithmic, so they remain reasonable even for large collections of events.
Are these any ready-to-go data structures like a priority queue available in Unity, .NET 4.5?
â Spectre
16 mins ago
It's absent from the standards .NET collections, but easy to whip up your own custom-suited to your needs. It's also a popular enough dara structure that you can find implementations in several third-party libraries you could include too, if you want something battle-tested without writing it from scratch yourself.
â DMGregoryâ¦
14 mins ago
add a comment |Â
up vote
2
down vote
If sufficient time passes between Update
calls to trigger multiple events, then as you note the actual firing order depends on the order in which you process the list. Since you process the list backwards you will evaluate and thus potentially fire "later" events sooner.
If you want your events to create an implicit dependency through their firing time (e.g., an event A
with an absolute time Ta
must fire before any events with absolute time Tn
> Ta
), then you need to ensure you process them in that order.
In your case, you could just sort the list by absolute time, either before you process it in Update
or by ensuring during scheduling you put new events in the proper sorted position.
Sorting the list backwards by absolute time means you can continue to process it backwards and rely on the efficiency of removing items from the end of the list (versus from the beginning, which would require moving the remaining items down).
add a comment |Â
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
3
down vote
accepted
This looks like you could solve it with a priority queue or min-heap. The code to process the queue would look something like this:
while(eventQueue.Count > 0 && eventQueue.Peek().executionTime < Time.time)
eventQueue.Dequeue().action();
This means you have only one check to do on frames when no events happen - you don't have to scan the whole list.
The nature of the priority data structure ensures that the next event to fire is always the first one you check, and when multiple events fire in the same frame, you process them in non-decreasing order of executionTime
.
Insertion and removal from such a data structure are typically logarithmic, so they remain reasonable even for large collections of events.
Are these any ready-to-go data structures like a priority queue available in Unity, .NET 4.5?
â Spectre
16 mins ago
It's absent from the standards .NET collections, but easy to whip up your own custom-suited to your needs. It's also a popular enough dara structure that you can find implementations in several third-party libraries you could include too, if you want something battle-tested without writing it from scratch yourself.
â DMGregoryâ¦
14 mins ago
add a comment |Â
up vote
3
down vote
accepted
This looks like you could solve it with a priority queue or min-heap. The code to process the queue would look something like this:
while(eventQueue.Count > 0 && eventQueue.Peek().executionTime < Time.time)
eventQueue.Dequeue().action();
This means you have only one check to do on frames when no events happen - you don't have to scan the whole list.
The nature of the priority data structure ensures that the next event to fire is always the first one you check, and when multiple events fire in the same frame, you process them in non-decreasing order of executionTime
.
Insertion and removal from such a data structure are typically logarithmic, so they remain reasonable even for large collections of events.
Are these any ready-to-go data structures like a priority queue available in Unity, .NET 4.5?
â Spectre
16 mins ago
It's absent from the standards .NET collections, but easy to whip up your own custom-suited to your needs. It's also a popular enough dara structure that you can find implementations in several third-party libraries you could include too, if you want something battle-tested without writing it from scratch yourself.
â DMGregoryâ¦
14 mins ago
add a comment |Â
up vote
3
down vote
accepted
up vote
3
down vote
accepted
This looks like you could solve it with a priority queue or min-heap. The code to process the queue would look something like this:
while(eventQueue.Count > 0 && eventQueue.Peek().executionTime < Time.time)
eventQueue.Dequeue().action();
This means you have only one check to do on frames when no events happen - you don't have to scan the whole list.
The nature of the priority data structure ensures that the next event to fire is always the first one you check, and when multiple events fire in the same frame, you process them in non-decreasing order of executionTime
.
Insertion and removal from such a data structure are typically logarithmic, so they remain reasonable even for large collections of events.
This looks like you could solve it with a priority queue or min-heap. The code to process the queue would look something like this:
while(eventQueue.Count > 0 && eventQueue.Peek().executionTime < Time.time)
eventQueue.Dequeue().action();
This means you have only one check to do on frames when no events happen - you don't have to scan the whole list.
The nature of the priority data structure ensures that the next event to fire is always the first one you check, and when multiple events fire in the same frame, you process them in non-decreasing order of executionTime
.
Insertion and removal from such a data structure are typically logarithmic, so they remain reasonable even for large collections of events.
answered 34 mins ago
DMGregoryâ¦
53.8k1199153
53.8k1199153
Are these any ready-to-go data structures like a priority queue available in Unity, .NET 4.5?
â Spectre
16 mins ago
It's absent from the standards .NET collections, but easy to whip up your own custom-suited to your needs. It's also a popular enough dara structure that you can find implementations in several third-party libraries you could include too, if you want something battle-tested without writing it from scratch yourself.
â DMGregoryâ¦
14 mins ago
add a comment |Â
Are these any ready-to-go data structures like a priority queue available in Unity, .NET 4.5?
â Spectre
16 mins ago
It's absent from the standards .NET collections, but easy to whip up your own custom-suited to your needs. It's also a popular enough dara structure that you can find implementations in several third-party libraries you could include too, if you want something battle-tested without writing it from scratch yourself.
â DMGregoryâ¦
14 mins ago
Are these any ready-to-go data structures like a priority queue available in Unity, .NET 4.5?
â Spectre
16 mins ago
Are these any ready-to-go data structures like a priority queue available in Unity, .NET 4.5?
â Spectre
16 mins ago
It's absent from the standards .NET collections, but easy to whip up your own custom-suited to your needs. It's also a popular enough dara structure that you can find implementations in several third-party libraries you could include too, if you want something battle-tested without writing it from scratch yourself.
â DMGregoryâ¦
14 mins ago
It's absent from the standards .NET collections, but easy to whip up your own custom-suited to your needs. It's also a popular enough dara structure that you can find implementations in several third-party libraries you could include too, if you want something battle-tested without writing it from scratch yourself.
â DMGregoryâ¦
14 mins ago
add a comment |Â
up vote
2
down vote
If sufficient time passes between Update
calls to trigger multiple events, then as you note the actual firing order depends on the order in which you process the list. Since you process the list backwards you will evaluate and thus potentially fire "later" events sooner.
If you want your events to create an implicit dependency through their firing time (e.g., an event A
with an absolute time Ta
must fire before any events with absolute time Tn
> Ta
), then you need to ensure you process them in that order.
In your case, you could just sort the list by absolute time, either before you process it in Update
or by ensuring during scheduling you put new events in the proper sorted position.
Sorting the list backwards by absolute time means you can continue to process it backwards and rely on the efficiency of removing items from the end of the list (versus from the beginning, which would require moving the remaining items down).
add a comment |Â
up vote
2
down vote
If sufficient time passes between Update
calls to trigger multiple events, then as you note the actual firing order depends on the order in which you process the list. Since you process the list backwards you will evaluate and thus potentially fire "later" events sooner.
If you want your events to create an implicit dependency through their firing time (e.g., an event A
with an absolute time Ta
must fire before any events with absolute time Tn
> Ta
), then you need to ensure you process them in that order.
In your case, you could just sort the list by absolute time, either before you process it in Update
or by ensuring during scheduling you put new events in the proper sorted position.
Sorting the list backwards by absolute time means you can continue to process it backwards and rely on the efficiency of removing items from the end of the list (versus from the beginning, which would require moving the remaining items down).
add a comment |Â
up vote
2
down vote
up vote
2
down vote
If sufficient time passes between Update
calls to trigger multiple events, then as you note the actual firing order depends on the order in which you process the list. Since you process the list backwards you will evaluate and thus potentially fire "later" events sooner.
If you want your events to create an implicit dependency through their firing time (e.g., an event A
with an absolute time Ta
must fire before any events with absolute time Tn
> Ta
), then you need to ensure you process them in that order.
In your case, you could just sort the list by absolute time, either before you process it in Update
or by ensuring during scheduling you put new events in the proper sorted position.
Sorting the list backwards by absolute time means you can continue to process it backwards and rely on the efficiency of removing items from the end of the list (versus from the beginning, which would require moving the remaining items down).
If sufficient time passes between Update
calls to trigger multiple events, then as you note the actual firing order depends on the order in which you process the list. Since you process the list backwards you will evaluate and thus potentially fire "later" events sooner.
If you want your events to create an implicit dependency through their firing time (e.g., an event A
with an absolute time Ta
must fire before any events with absolute time Tn
> Ta
), then you need to ensure you process them in that order.
In your case, you could just sort the list by absolute time, either before you process it in Update
or by ensuring during scheduling you put new events in the proper sorted position.
Sorting the list backwards by absolute time means you can continue to process it backwards and rely on the efficiency of removing items from the end of the list (versus from the beginning, which would require moving the remaining items down).
edited 1 hour ago
answered 1 hour ago
Joshâ¦
90.7k16203316
90.7k16203316
add a comment |Â
add a comment |Â
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fgamedev.stackexchange.com%2fquestions%2f164561%2fhow-to-make-a-custom-event-system-framerate-friendly%23new-answer', 'question_page');
);
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password