performSelectorを使ったタスクシステムもどき
ゲームのメインループ、switch(mode) case:モード名 みたいに書いてたんですが、
ふと、タスクシステムというのを見つけました。
http://www5f.biglobe.ne.jp/~kenmo/program/task/task.html
タスクシステム自体は、X68000の時に、スタック操作してこんな感じのを作った事があります。
void main()
{
:
// 処理1
wait(1); // 次の割り込みまで停止。次の割り込みではココから再開。
// 処理2
wait(2); // 次の割り込みはお休みして、その次の割り込みから処理再開。
:
}
とても便利だったのですが、プログラムカウンタのスタックを操作しないと実現できないので、
このタイプは諦めてます。インタープリタなら可能だと思います。
話が脱線しました。
先のリンクのタスクシステム、キモになるのはC言語の関数ポインタ。
今実行している関数内で、つぎに割り込みで実行する関数のポインタを設定して、
次の割り込みでは、その設定した関数ポインタで関数を呼び出す、という仕組みもできるな、と。
これObjective-Cには、@selector(メソッド名)という機能とperformSelector:というメソッドがあります。
仕組みは違いますが、関数ポインタと同じような事ができそうだと思い、
作っているゲームのメインループをswitch caseから書き換えてみました。
メイン処理のループ
- (void) mainLoop
{
[self performSelector:mainMethod]; // これだけ
}
このmainMethodは、SEL型の変数で、メソッドを実行する為の情報が入っているそうです。
仮に、mainMethodにmainInitと言うメソッドが入っているとすると、
- (void) mainInit
{
//処理
mainMethod = @selector(mainNext);
}
と書いておくと、次の割り込みではmainNextというメソッドが呼ばれます。
switch caseと違い、分岐もないのでその分高速なのと、case:〜の定数を定義しなくて良くてラクチンです。
(もちろん、分岐を最適化して一つのメソッドや関数内に全部記載する方式の方が高速ですが、
ソースコードは読み難くなりますね)
デバッグするとき、[self performSelector:mainMethod];でステップインしても、
そのメソッドに移らないのが玉に瑕ですけど、まあ、ブレークポイントを仕掛けておく事でなんとかなりました。
この方法便利そうなのでこれから先も使いそうです。