ページ 11

タスクシステムについて

Posted: 2010年11月09日(火) 23:59
by うしお
タスクシステムというのをよく耳にし、
特にSTGでは人気があるようなのですが、
どうにも合点が行かない箇所があります。

大真面目に凝ったタスクシステムは作ったことはないのですが、
基本的に
class TaskBase
{
  virtual ~TaskBase(){}
  virtual void Update() = 0;
}
というのを継承して関数定義をして、

list<TaskBase*> TaskList;
//****************************

//擬似コード イテレータは略
for()
{
It->Update();
}
のように一斉処理をする、のような感じだろうと解釈しています
(これは勘違いかもしれませんし、実装には多種多様な方法があるそうですが)

ここで私が感じる違和感は
1、追加修正も含め、オブジェクト同士の通信が非常に面倒そう
  (一つ一つが独立しているし、関係性が増えてくると、私の脳がパンクしそう)
2、仮に弾ひとつひとつにTaskを割り当てるとすると、
  100個の弾だと100回のnewが入ってしまうこと
3、アルファ合成もの、影の描画など順序が重要な場合の部分の制御が面倒そう

4、レンダリングの設定を大きく変更する必要がある場合、処理が独立していると、
  設定変更に大きな無駄が出る。
  (Taskの中で、変更→描画→元にもどす、が繰り返されてしまう分変更が無駄に繰り替えされてしまう)
  (すごくシンプルに書けば、変更→必要なものすべてループで描画→元にもどす、と無駄が少ない)

どうしてもタスクシステムの適用が良いという状況が少ないように感じられてしまいます。
しかし、おいしいところがあるから、
もてはやされたトピックだと思うのですが、いまひとつピンと来ないのです。
そこで、”おいしさ”の部分についてもう少し知りたく、お伺いしたいです。
よろしくお願いします。

Re:タスクシステムについて

Posted: 2010年11月10日(水) 00:56
by S.N.
私もそれで悩んだことがあります。タスクシステムの定義は見たことはありませんが、周りの人の使用方法からすれば上の説明であってると思います。
質問に対する答えになっていないのは承知で私なりの解決策を述べさせていただきます。
1.
 タスクに親子関係をつける。全体のタスクの連鎖に弾タスクの連鎖、敵タスクの連鎖などがぶら下がってるイメージ。適切な連鎖を持ってきてループで処理する。

2.
 現代のPCなら 動的確保はネックにならない気がします。1フレームにつき10回ぐらいのnewは問題ないのではないでしょうか。deleteしないでその領域を再利用という手段も使われます

3.
 タスクに優先順位をつける。タスクの連鎖挿入時に適切な位置に挿入する。

4.
 上で述べたように子タスクを実行するタスクに前後の処理をまかせればよいかと(無理やりすぎ?)
 ...->タスクFの処理          ー>タスクGの処理ー>...
     前処理
      loop{子タスクの処理}
     後処理

メリットとしてはエフェクトなど他のオブジェクトに作用しない&左右されないタスクの追加が楽。規則を持たせることで外部モジュールからとってきた互換性のあるタスクの追加が楽。newするだけで追加されdeleteすると削除されるとは、ふつくしい!。タスクシステムを作ると次回からは使いまわせる。などでしょうか。

 質問の意は「1~4についてタスクシステムだと不便だけど、それ以上のメリットあるの?」ということでしょうが、これは個人的な意見ですが、発明された当時はメモリの効率的な使い道として誕生しましたが、今はメモリ容量はきにしなくて良くなったのであまり意味がないのかもしれません(コーディング効率は別として)。
 オブジェクト指向になりつつある中、時代の流れであまり推奨されてないですが、実際、広域変数or関数を駆使すればより効率的に開発できると思います。

Re:タスクシステムについて

Posted: 2010年11月10日(水) 02:01
by Justy
 タスクシステムは多種多様なので、なかなかイメージを一致させにくいかもしれませんが。


>1、追加修正も含め、オブジェクト同士の通信が非常に面倒そう
 タスクにするものしないもの、データをどこに置いてどうアクセスさせるか等
設計時に気をつけておけば、さほど面倒にはならないと思います。

 ですがもし今までが、いろんなオブジェクトをグローバル変数にしていつでも誰でも
アクセス可能状態にしていたのであれば、確かに面倒に感じるかもしれません。


>2 仮に弾ひとつひとつにTaskを割り当てるとすると
 メモリが非常に少ない、仮想メモリがない、CPU速度が相当遅い環境を想定されているのだとは
思いますが、標準 newの代りに高速なアロケータを割り当てればそれなりに高速化できる
余地はあるでしょうし、最悪いろいろ制約を加えればこの辺りは効率良く処理できると思います。


>3、アルファ合成もの、影の描画など順序が重要な場合の部分の制御が面倒そう
 実行順と描画順が異なるケースですね。

 1つの手としては、タスク内で描画しないという方法があります。
 例えば、タスク内からは描画リクエストだけ出しておき、別の描画システムが後からリクエストを
とりまとめてソートなど行い、描画するとか。

 タスク内で描画したいのであれば、タスクの実行を更新部と描画部と分けた上で、
先に更新部を実行し、その実行結果から描画順を決め、その順番で描画部を実行するという手もあります。

 描画の順番は固定でよけえば、最初からそうなるようタスクリンクをつないでおけばいいかと。


>4、レンダリングの設定を大きく変更する必要がある場合……設定変更に大きな無駄が出る
 先に例として挙げた描画リクエスト方式にしておけば、描画システム側で吸収できるので
改善できると思います。

 タスク内で描画をするとなるとちょっと面倒ですけど、レンダーステートを変更するタスク・復帰させるタスクを
作り、その間に必要な描画を行うタスクを入れるようにすれば、一応は無駄はなくなります。
 或いはそれらを1タスクで全部処理してしまうような設計にするか、ですね。



>おいしさ
 作り方を共通化することで再利用が楽になったり、柔軟に複数の処理を実行できる、とかはメリットになりますが
1本しかリンクがなくただ単に順番に実行していくだけのタスクシステムなら微妙ですね。

 しかし、タスクシステムにゲームを作りやすくするための汎用的な機構が入っていると
またちょっと話が変わってきます。
 例えば S.N.さんが挙げられている様なタスクを階層化だったり、タスクが終了したときに
別のタスクや親のタスクに終了したことを通知する機構があるだけでも
作りやすさは結構変わってくるでしょう。

 更に話を広げるのであれば、タスクシステム以外のシステムとの連携を考えた場合
(別にタスクシステムでなくてもいいのかもしれませんが)何らかの共通したシステムの
存在はあった方がいろいろと楽になる可能性はあります。

Re:タスクシステムについて

Posted: 2010年11月10日(水) 12:38
by うしお
ご回答ありがとうございます

ということは、
タスクシステムは、それぞれのアプリケーションごとにカスタマイズする作業が
どうしても必要で、汎用的とはちょっと違うものだと解釈していいのでしょうか?

とはいってもこれはひどく主観的な表現なのでいくらでも異論はありそうですが・・・

また、
確かに、本当に独立したオブジェクトの制御には向いていると感じました

Re:タスクシステムについて

Posted: 2010年11月10日(水) 15:55
by ISLe
> タスクシステムは、それぞれのアプリケーションごとにカスタマイズする作業が
> どうしても必要で、汎用的とはちょっと違うものだと解釈していいのでしょうか?

自分の場合は、
・フレーム更新処理をするタスクシステム
・↑のタスクリストに対してイベントをブロードキャストする仕組み
・優先順位付き描画オブジェクトリスト管理および描画処理システム
であらゆるゲームに対して汎用的に使い回すことができています。

イベントは、ボスキャラが破壊されるとボスタスクがボスキャラ破壊イベントをブロードキャストしてボスが発射した弾のタスクはイベントを受けて自身で消滅ステータスに移行するような仕組みです。

むかしのゲーム機はスプライトの数が少なくてフレームごとに動的に割り当てる仕組みが必須だったので、描画処理を独立させるのは必然でした。
いまのゲーム機でもスクリーンセーバーの実装がガイドラインに組み込まれていたりするので描画処理が独立していると(特に復帰時の処理が)楽ですね。

Re:タスクシステムについて

Posted: 2010年11月10日(水) 17:03
by うしお
ありがとうございます。
たしかにイベントを飛ばす考えでいくと解決する部分が結構おおいかなと思いました
(そういえばGameProgramingGemsにこの方法が載っていたような気がしました)

>フレームごとに動的に割り当てる仕組み
ここの部分がいまいちピンとこなかったので、
もう少し噛み砕いて説明をお願いしてもよろしいでしょうか?

描画処理を独立というのはここでいうタスクごとに分離という意味でしょうか?
それと復帰処理の楽さというのもいまいち実感がわきません。
なのでもう少し詳しくおねがいしたいです。

よろしくおねがいします。

※誤字を修正しました 画像

Re:タスクシステムについて

Posted: 2010年11月10日(水) 18:32
by ISLe
> >フレームごとに動的に割り当てる仕組み
> ここの部分がいまいちピンとこなかったので、
> もう少し噛み砕いて説明をお願いしてもよろしいでしょうか?
表示優先順位とスプライト番号が直結してたので、AとBのキャラの前後関係が変わると使うスプライトを交換しなければならなかったのですが、単純に表示するときに表示優先順位の順でスプライトを割り振っていったほうがアルゴリズムが簡単になるのです。
むかしのスプライト機能自体がピンときませんよね。
いまだと不透明のポリゴンを手前から描いてそれが全部終わってから半透明のポリゴンを奥から描くというふうにすると描画を高速化できるのですが、例えば戦闘機で胴体(不透明)とキャノピー(半透明)を個別の描画オブシェクトとして管理すると描画処理を最適化できます。

> 描画処理を独立というのはここでいうタスクごとに分離という意味でしょうか?

タスクごとではなくタスクシステムとは完全に分離します。
タスクが作成されるときにタスク初期化部でビットマップを描画する描画オブジェクトを作成し描画管理リストに登録します。
タスクは自身が作成した描画オブジェクトの参照(ポインタ)を保持しそれを使って描画オブジェクトに移動や変形を指示することになります。
描画は描画オブジェクトを優先順位順に処理します。
タスクと分離していると描画で内部状態が変化することはなく何度でも同じ画面を描画することができます。

> それと復帰処理の楽さというのもいまいち実感がわきません。
ウインドウズであれば最小化したあと元に戻したとき最小化する前の画面を元通り描画するにはどうしますか?
即座にゲームを進行させてしまうとか一枚絵を表示するとかで逃げることもできますけど。

Re:タスクシステムについて

Posted: 2010年11月10日(水) 19:25
by うしお
ISLeさん、ありがとうございます
より詳しい説明ありがとうございます

昔のスプライトの事情に触れたことがないとなかなかピンとこない事情でした(あせ

分離についてはタスク云々に限った話ではなく、
描画システムとゲーム管理部分の分離ということでしたか

イベントベースのWinアプリケーションは.net以外はあまり組んだことがないので
この場合の復帰の問題は考えてはいませんでした。
この場合もとにかく描画とその他が分離していることがポイントであって、
タスクシステムに限ったことではないのですね!

タスクシステムのイメージがかなり変わってきました

タスクシステムの考え方を利用して、こういう管理をしよう。
タスクシステムにこういう機能を用いてこう制御しよう。
こうした立場で考えた時に、よいシステムになるケースがある
こんなイメージになりました。

また、タスクシステムにはこんな使い方でおいしい部分があるぞ、
という方がいらっしゃいましたら、よろしくお願いします。