オブジェクト指向ゲームプログラミングの落としどころ

id:arCtan:20060702で書いた問題についての今のところの結論。

  • とりあえず循環参照のないようにキャラクタクラスなどを設計する。
  • 依存度の低いものから生成し、コンストラクタで先に生成した参照先クラスへのポインタを渡す。

こんな感じですね。

CDraw* draw = new CDraw;			//描画クラス。依存度0
CShots* shots = new CShots(draw);		//依存度1
CShip* ship = new CShip(draw,shots);		//依存度2
CBullets* bullets = new CBullets(draw,ship);
CEnemys* enemys = new CEnemys(draw,ship,shots);	//依存度3

ゲームの起動時に生成し、終了時に解体するという静的な設計ならあとは各クラスが保持するポインタをいじる必要はありません。完全なクラス関連を張れたことになります。これでmove()やdraw()で引数を渡す必要がなくなります。コンストラクタが肥大化しますが、ここ一箇所にしわ寄せを集中できると思えば、やはりこれが一番ベーシックでわかりやすい解法といえるでしょう。
オブジェクト指向っぽさがまったくないのがあれれ?って感じですね。正直Cで書けるものをC++で書き直してみただけに見えます。でも大変わかりやすく、見通しのよい設計です。なお、この設計を行っていたのはABA氏のゲーム"Gunroar"のソースです。D言語ということで今まで読んでなかったのですが、読んでちょっとびっくりするとともにこんな程度のことが思いつかなかったのかよ俺、という気分でした。氏のオブジェクト指向設計というのがここまでシンプルだったということは、ゲームプログラミングに対しての落としどころはやはりこの程度でいいだろうという判断なのでしょう。
結局のところオブジェクト指向のゲームプログラミングを行うときには、「どの程度オブジェクト指向で行くのか」というのが一番の問題で、それはそのプログラマオブジェクト指向に対する理解度にも依存すると思うんですね。オブジェクト指向についてかなり理解しているならば、それを遺憾なく発揮してプログラムすることもできますし、そこの調節具合は自由です。一方で俺はオブジェクト指向を単に「主語をはっきりさせて処理の流れが読みやすい」くらいにしか捉えていないし、実際使っている機能といえばほんとにクラスだけなのではないかという程度なので、それならそれ相応の程度で極力自分にわかりやすいような設計をすべきであるように思ったのです。
つまり、俺はC++で書いてるけどオブジェクト指向なんてまったく意識してねーぜ。ただC++しか知らないからそれで書いてるだけだぜハッハー!というスタンスですね。プログラマとしては終わってるな俺( つ∀`)
しょせんゲームなのです。動けばいいのですよ。にぱ〜☆

追記

ところでなんでこだわるのかって感じですが、循環参照・・・嫌いなんですよね。やっぱ#include関係は木構造をしていないと、なんかダメ。クラスの先行宣言とか、見たくないんですよ。たぶん最初にこの問題にぶち当たったときに#include関係でこんがらがってコンパイル通すのに時間食ったのがトラウマになってるんでしょうね。