-
-
Notifications
You must be signed in to change notification settings - Fork 142
Description
Some background to the question/scenario
I have a situation where a framework I maintain had an IUpdateScheduler interface that looked something like:
public IUpdateScheduler
{
Observable<float> OnUpdate {get;}
float ElapsedTime { get; }
}Where in the default implementation, it would run a timer on a frequency (i.e 1000.0f/60 for 60fps) and on every time the timer triggered it would work out how much time had elapsed and then fire the onUpdate.OnNext(elapsedTime) and cache the elapsed time for any other code to call to see how much time had elapsed since last update cycle, it was based on how unity provides deltaTime anywhere on main thread and how UniRx provides Observable.EveryUpdate but being agnostic of engines etc.
The implementation of this would vary per engine etc, i.e the console one would just track off a timer, unity one would hook into the Update cycle but it was all ok as we controlled the calculation of elapsed time AND the execution of updates once we cached it for that time slice, it was fairly accurate and worked ok.
Current day situation
Fast forwarding to current day the library now uses R3 and as that has a native Observable.EveryUpdate it feels like the notion of IUpdateScheduler is somewhat redundant, which is great, but the missing piece of the puzzle is how to get the elapsedTime in the context of the update cycle, as previously we cached the elapsed time between updates THEN triggered all updates for that cycle, but now R3 is controlling the update cycle and I cant see a way to run code before all other updates etc.
All engines provide Delta time in a different way, and I can see in the R3 source code that there are lots of custom providers that factor these in and often make use of the elapsed time to some extent but its never bubbled up via any mechanism I can see, as in an ideal world I would want to be able to do Observable.EveryUpdate().Subscribe(elapsedTime => ...) but as its a Unit next best thing seems to be providing some agnostic way of getting elapsedTime i.e Observable.EveryUpdate().Select(_ => timeTracker.ElapsedTime).Subscribe(elapsedTime => ...).
The main problem
Anyway the thing thats got me a bit stumped at the moment is that the Observable.EveryUpdate triggers kinda operate in their own bubble so it is under the hood running off a timer/whatever the providers setup, but I need to sync my elapsed time to that somewhat so that my elapsed time is being updated in unison with the update cycle kicking off, and I cant see a nice way to do this.
Just taking a simple console app as an example so there are no custom providers to account for, we can just do something like:
// Some default initializer as we are just running in a console app
public static class DefaultR3Initializer
{
public static void SetDefaultObservableSystem(int updateFrequencyPerSecond = 60)
{
var updateInterval = 1000f / updateFrequencyPerSecond;
var timeFrameProvider = new TimerFrameProvider(TimeSpan.FromMilliseconds(updateInterval));
ObservableSystem.DefaultFrameProvider = timeFrameProvider;
}
}
// Some imaginary interface for executing logic
public interface ISomeLogicExecutor
{
void Execute(float elapsedTime);
}
// Imagine we have several implementations
public class SomeLogicExecutor1 : ISomeLogicExecutor { ... }
public class SomeLogicExecutor2 : ISomeLogicExecutor { ... }
public class SomeLogicExecutor3 : ISomeLogicExecutor { ... }
// Imaginary code for running in the Main function
DefaultR3Initializer.SetDefaultObservableSystem(); // Observable.EveryUpdate should be firing at 16ms ish giving 60 updates a second
// Setup our logic executors
var executor1 = new SomeLogicExecutor1();
var executor2 = new SomeLogicExecutor2();
var executor3 = new SomeLogicExecutor3();
// Schedule them all separately
Observable.EveryUpdate().Select(/*Get Elapsed Time Somehow*/).Subscribe(executor1.Execute);
Observable.EveryUpdate().Select(/*Get Elapsed Time Somehow*/).Subscribe(executor2.Execute);
Observable.EveryUpdate().Select(/*Get Elapsed Time Somehow*/).Subscribe(executor3.Execute);While this is slightly contrived and complex ideally I want to be able to provide some functionality to resolve the elapsed time without having to resort to each Observable.EveryUpdate needing to track its own time and pass that on as even if I did that I couldnt check for the elapsed time between the last 2 update cycles etc.
It looks like R3 already does lots of this but its just not exposed in a standardised way but it looks like it keeps track of elapsed time between update cycles, so is there any way to mimic this and keep it in sync or expose it so that I could hook into that?
Any advice/guidance would be great.