そのため、そのような類似の目的のために、私の同僚は、Functor Managerと呼ばれるユニバーサルシステムを開発しました(そのようなシステムの名前には別の用語があるかもしれませんが、彼らが教えてくれれば嬉しいです)。
当初、コードはC ++で記述され、過去のプロジェクトで使用されていましたが、現在はC#のプロジェクトがあるため、C#で実装を行います。 簡単な概念と実装コード(C#)カットの下。
ファンクター
ファンクトールは、どれだけ時間がかかり、どの関数を呼び出すかを覚えているクラシックです。
したがって、実際にはファンクターは次のもので構成されます。
Guid-ファンクターを作成するときに生成される一意の識別子。 この識別子は、必要に応じてファンクターを削除できるようにするために必要です。
_deltaTimeは内部タイマーです。 関数呼び出しが発生するまでの時間を記録します。
_func-タイマーが切れた後にコードを実行する必要がある関数へのポインター。 この関数は値を返します-ファンクタはメソッド呼び出しを繰り返す必要がある期間(秒単位)を経過します。 関数が値0.0fを返した場合、ファンクターは破られます。
_funcArgは関数の引数です。 ここにオブジェクトへのポインタ、またはその他の必要な情報を渡すことができます。
ファンクタコードではすべてが単純です。フィールドを埋めるコンストラクタであり、説明に値する唯一のメソッドはProcessメソッドです。 カウンターはティックの数だけ減少し、ゼロに達すると関数が呼び出されます。 戻り値はタイマーに割り当てられます。
ファンコード:
public delegate float Func(object funcArg); public class HOFunctor { float _deltaTime = 0; Func _func = null; object _funcArg = null; Guid _id = Guid.Empty; public HOFunctor(float deltaTime, Func func, object funcArg) { _id = Guid.NewGuid(); _deltaTime = deltaTime; _func = func; _funcArg = funcArg; } public HOFunctor(float deltaTime, Func func) : this(deltaTime, func, null) { } public bool Process(float deltaTime) { if (_func != null) { _deltaTime -= deltaTime; if (_deltaTime <= 0) { _deltaTime = _func(_funcArg); } } return _deltaTime > 0; } public Guid ID { get { return _id; } } }
ファンクターマネージャー
ファンクタマネージャは、ファンクタのリストを格納するシングルトンのクラスです(実際には2つのリストがあります。詳細は以下を参照)。
そのため、マネージャーには2つのリストがあり、そのうちの1つは現在アクティブであり、2つ目はアクティブリストの実行時に追加されたものを含む、新しく追加されたファンクターで満たされています。 変数_currentIndexもあり、どのリストが現在アクティブであるかが決定されます。
ほとんどのメソッドも直感的です(AddFunctor(...)-ファンクタをリストに追加し、RemoveFunctor()-リストから削除します)。 説明する価値があるのは、ProcessFunctors(float delta)メソッドだけです。 現在のリストが取得され、各ファンクターはProcessメソッドと呼ばれるため、時間をカウントし、必要に応じて実行されます。ファンクターがゼロ以外の値を返した場合(つまり、再度呼び出す必要がある時間)、新しいリストに追加されます。 最後に、アクティブリストがクリアされます。
マネージャーコード:
public class HOFunctorMgr { #region Private fields private static HOFunctorMgr _instance = null; protected Dictionary<Guid, HOFunctor>[] _functors = { new Dictionary<Guid, HOFunctor>(), new Dictionary<Guid, HOFunctor>() }; int _currentIndex = 0; private HOFunctorMgr() { } #endregion public static HOFunctorMgr Instance { get { if (_instance == null) { _instance = new HOFunctorMgr(); } return _instance; } } #region Public methods public Guid AddFunctor(float deltaTime, Func func, object funcArg) { return AddFunctor(new HOFunctor(deltaTime, func, funcArg)); } public Guid AddFunctor(float deltaTime, Func func) { return AddFunctor(new HOFunctor(deltaTime, func, null)); } public Guid AddFunctor(HOFunctor functor) { if (functor != null && !_functors[_currentIndex].ContainsKey(functor.ID)) { _functors[_currentIndex].Add(functor.ID, functor); return functor.ID; } return Guid.Empty; } public void ProcessFunctors(float delta) { int indexToProcess = _currentIndex; _currentIndex ^= 1; foreach (HOFunctor f in _functors[indexToProcess].Values) { if (f.Process(delta)) { AddFunctor(f); } } _functors[indexToProcess].Clear(); } public void RemoveFunctor(Guid id) { if (_functors[0].ContainsKey(id)) { _functors[0].Remove(id); } if (_functors[1].ContainsKey(id)) { _functors[1].Remove(id); } } #endregion }
プロジェクト統合
プロジェクトへの統合は1行で行われます。 チャレンジを追加する必要があります
HOFunctorMgr.Instance.ProcessFunctors(デルタ);
ゲームループでは、最初にマネージャーファンクタークラスをプロジェクトに自然に追加します。 私の場合(NeoAxisエンジン)、これはゲームウィンドウの保護されたオーバーライドvoid OnTick(float delta)メソッドです。
deltaは、前の呼び出しからの経過時間(秒単位)です。
すべてがとてもシンプルです。
使用例
シングルコール:
GameEntities.HOFunctorMgr.Instance.AddFunctor(2.0f, arg => { HidePuzzleWindow(); return 0.0f; }, null );
2秒後、HidePuzzleWindow()が呼び出され、パズルウィンドウが消えます。
複数呼び出し:
... int k = 5; HOFunctorMgr.Instance.AddFunctor(5, arg => { GameMap.Instance.AddScreenMessage(string.Format("{0}", arg)); if (k-- >= 0) { return 5; } return 0; }, "test");
ファンクターが5回呼び出され、テストという単語が表示され、そのたびに5秒間隔で表示されます。 ちなみに、間隔は変更できます。
静的メソッドを呼び出します。
static float MyMethod(object arg) { if (arg != null) { ... } return 0; } HOFunctorMgr.Instance.AddFunctor(10, MyMethod, someObject);
10秒後、静的なMyMethodメソッドが呼び出され、someObjectが引数として渡されます。
使用について
プロジェクトでは、非商用および商用の両方のコードを変更および/または使用できます。
フルクラスコード
クラスコード、NeoAxis用にシャープ化された名前空間。
using System; using System.Collections.Generic; using System.Text; namespace GameEntities { public delegate float Func(object funcArg); public class HOFunctor { float _deltaTime = 0; Func _func = null; object _funcArg = null; Guid _id = Guid.Empty; public HOFunctor(float deltaTime, Func func, object funcArg) { _id = Guid.NewGuid(); _deltaTime = deltaTime; _func = func; _funcArg = funcArg; } public HOFunctor(float deltaTime, Func func) : this(deltaTime, func, null) { } public bool Process(float deltaTime) { if (_func != null) { _deltaTime -= deltaTime; if (_deltaTime <= 0) { _deltaTime = _func(_funcArg); } } return _deltaTime > 0; } public Guid ID { get { return _id; } } } public class HOFunctorMgr { #region Private fields private static HOFunctorMgr _instance = null; protected Dictionary<Guid, HOFunctor>[] _functors = { new Dictionary<Guid, HOFunctor>(), new Dictionary<Guid, HOFunctor>() }; int _currentIndex = 0; private HOFunctorMgr() { } #endregion public static HOFunctorMgr Instance { get { if (_instance == null) { _instance = new HOFunctorMgr(); } return _instance; } } #region Public methods public Guid AddFunctor(float deltaTime, Func func, object funcArg) { return AddFunctor(new HOFunctor(deltaTime, func, funcArg)); } public Guid AddFunctor(float deltaTime, Func func) { return AddFunctor(new HOFunctor(deltaTime, func, null)); } public Guid AddFunctor(HOFunctor functor) { if (functor != null && !_functors[_currentIndex].ContainsKey(functor.ID)) { _functors[_currentIndex].Add(functor.ID, functor); return functor.ID; } return Guid.Empty; } public void ProcessFunctors(float delta) { int indexToProcess = _currentIndex; _currentIndex ^= 1; foreach (HOFunctor f in _functors[indexToProcess].Values) { if (f.Process(delta)) { AddFunctor(f); } } _functors[indexToProcess].Clear(); } public void RemoveFunctor(Guid id) { if (_functors[0].ContainsKey(id)) { _functors[0].Remove(id); } if (_functors[1].ContainsKey(id)) { _functors[1].Remove(id); } } #endregion } }