今回は、Cocos Sharp の もう一つの重要な機能であるスケジューラがどのような内部動作をしているのかを深く解析したいと思います。
スケジューラにメソッドを登録する場合には、以下のようにCCNode
のSchedule
メソッドを使用します。
Schedule(t => this.DetectCollisions(), 0.1f);
これは、0.1秒ごとにDetectCollisions
メソッドを実行しなさいという意味です。
まずは、Schedule
メソッドの内部動作を確認してみましょう。
CCNode
のSchedule
メソッドのソースコードを見てみると以下のようになっています。
public void Schedule (Action<float> selector, float interval) { Schedule (selector, interval, CCSchedulePriority.RepeatForever, 0.0f); }
Schedule
メソッドのオーバーロードをコールしていますので、コール先のソースコードを見てみると以下のようになっています。
public void Schedule (Action<float> selector, float interval, uint repeat, float delay) { if (Scheduler != null) Scheduler.Schedule (selector, this, interval, repeat, delay, !IsRunning); else AddLazySchedule (selector, this, interval, repeat, delay, !IsRunning); }
Scheduler
プロパティのSchedule
メソッドをコールしています。AddLazySchedule
の方も追っていくと、最終的にはSchedule
メソッドをコールするようになっています。
Scheduler
プロパティのを確認すると、その実体はCCScheduler.SharedScheduler
のようです。
CCScheduler Scheduler { get { return CCScheduler.SharedScheduler; } }
SharedScheduler
というプロパティ名からもわかるとおり、CCScheduler
を確認すると Singleton になっています。
さらに、Schedule
メソッドを確認すると以下のように、デリゲートと付帯情報をCCTimer
のリストとして登録しています。
public void Schedule (Action<float> selector, ICCUpdatable target, float interval, uint repeat, float delay, bool paused) { // 省略 element.Timers.Add(new CCTimer(this, target, selector, interval, repeat, delay)); // 省略 }
よって、CCNode
のSchedule
メソッドに登録したデリゲートは全てCCScheduler
で一括管理されるようになっていることがわかります。
では次に一括管理されたデリゲートがどのように実行されていくか見てみましょう。
デリゲートと付帯情報はCCTimer
のリストとして管理されており、CCScheduler
のUpdate
メソッド内で、各CCTimer
のUpdate
メソッドがコールされています。
public class CCScheduler { internal void Update (float dt) { if (TimeScale != 1.0f) { dt *= TimeScale; } // 省略 for (elt.TimerIndex = 0; elt.TimerIndex < elt.Timers.Count; ++elt.TimerIndex) { elt.CurrentTimer = elt.Timers[elt.TimerIndex]; if(elt.CurrentTimer != null) { elt.CurrentTimerSalvaged = false; elt.CurrentTimer.Update(dt); elt.CurrentTimer = null; } } // 省略 } }
CCTimer
のUpdate
メソッドを確認してみると以下のようになっています。
internal class CCTimer : ICCUpdatable { public void Update(float dt) { if (elapsed == -1) { elapsed = 0; timesExecuted = 0; } else { if (runForever && !useDelay) { //standard timer usage elapsed += dt; if (elapsed >= Interval) { if (Selector != null) { Selector(elapsed); } elapsed = 0; } } else { // 省略 } } } }
今回のフレームの経過時間であるdt
から、前回デリゲートを実行してからのトータル経過時間elapsed
を計算して、与えられたInterval
を経過していたら、Selector
デリゲートを実行しているのが分かります。
これで、スケジューラがどのような内部動作をしているのかがわかりました。
というわけで、今回はここまでです。