http://www.page.sannet.ne.jp/hirasho/diary/diary0811.html#30p5 このへんの話。「あータスクシステムなんて昔あったな」、と思って検索してみたら今でも紹介されてたりして、「こんなの使うのが普通なの?」とか思ってびっくりした。
というか、それは本当に80年代のナムコが開発したジョブコンって奴と似てるのだろうか? 誰かが要らんメモリ管理を付け加えてないか?
http://game.2ch.net/gamedev/kako/1006/10061/1006184421.htmlの>>810によればジョブコンというのは下記のようなものらしい。
スタックにプッシュしてある
リターンアドレスも含めたCPUコンテクストを復帰させて
各ジョブを呼び出す。ただし、リターンアドレスをポップする
形で呼び出すので、 RTS で呼び出す訳ですが。
以下の様なルーチンが、V-Blank処理後に毎回呼ばれる感じ。for(i=0; i<SizeofArraySP; ++i){ StackPointer = ArraySP[i]; POPALL; RTS; WAIT: PUSHALL; ArraySP[i]=StackPointer; }呼び出される側は、JSR WAIT; でNMI待ちができるし、
コルーチン的に単体の処理を書き下せるので、記述性に優れます。
保存するレジスタを必要最小限に留めれば軽い処理で済むし、
ArraySPに双方向リストを使えば優先順位の管理もできます。
だいたい理解した。
「タスクシステム」でググって上の方に出てくる技術解説は、上の二つの特徴のうちコンテクストの保存は無視されて優先順位の管理だけを実装している上に(素人目には危険そうな)リングバッファを特徴としているような感じ。「単に1int毎に呼び出されるインタフェースを実装したオブジェクトのリスト」と変わらないような気がして、今だったら要らないよなあ、あるいは、それを大げさにシステムと呼ぶほどのものなのか? と思ってしまう。
あとはゲーム全体をタスクシステムでやるという説明の割に敵を1体1体タスクとして登録するような例を出している解説サイトが多く、そのへんが何かおかしいような気がする。そのへんは階層化されるべき。おそらく上記の引用から類推するとジョブコンは敵の1体1体をタスクにしていない。
http://qo.sakuratan.com/2008/07/24/%E3%82%BF%E3%82%B9%E3%82%AF%E3%82%B7%E3%82%B9%E3%83%86%E3%83%A0%E3%81%AE%E3%81%93%E3%81%A8%E3%80%82/で書かれてることに大体同意する。
追記
説明が不足していたかもしれないので追記すると、ジョブコンの優位性はコルーチンが実現できることだったと理解した。
なにせファミコンもスーファミもブランキング期間にしかVRAMに書き込みができなかったんでドラクエのウインドウなんかは1/60秒に1行ずつしか書けないという話だ。ウインドウ描画の処理と主人公のアニメーションその他を並列に動作させる必要があり、かつウインドウ描画の処理はコード上で連続して書いてしまいたいはず。
毎フレーム呼ばれる下記のようなサブルーチンを書くよりも
//ウインドウ描画処理だぜ(毎フレーム呼んでくれよ) void drawWindow(void) { if (drawWindowCount == 0) { 上端描画(); } else if (drawWindowCount != WINDOW_YSIZE - 1) { 真ん中部分の描画(drawWindowCount); } else { 下端描画(); } drawWindowCount++; }
ジョブコンを使って下記のようなのを書いたほうがそりゃ分かりやすいし、実は速かったので1フレーム2行ごとに書けるようになった場合の修正も簡単だったりするだろう。ドラクエがタスクシステムを実装していたかどうかは知らないが。
//ジョブコンに登録されてるウインドウ描画処理 void drawWindow(void) { 上端描画(); JSR WAIT; // ジョブコンに処理をいったん戻す。ここから先は次フレームの処理になる for (int i = 1; i < WINDOW_YSIZE - 1; i++) { 真ん中部分の描画(i); JSR WAIT; // 同様 } 下端描画(); ジョブコンから自分自身を外す; }
このへんのメリットがなくなってる今のタスクシステムは…魅力あるのかねぇ。