出向にきてから4週間目、というかもう年末前です。
あとはもう会社の大掃除をして、学校の先生方と飲み屋で忘年会を開いた後に翌年までぐーたら…
といいたいところだが、そのあいだに出向で学んだことをおさらいしていきたいです。
今週学んだことは非常に多かったかもしれない。
メモリのアライメントの話とか、ゲーム設計の話とかそういう系ですけどね。
つまりクラスとクラスの間に参照関係は持たせるなと、
当たり前のことではあるんですが、OOP的に書こうとすると陥りやすいのではないでしょうか。
かくいう私もそのひとりです。
変にオブジェクト指向的な設計をするくらいなら綺麗にCの書き方で設計してしまったほうがよっぽど
可読性も保守性も柔軟性も高いコードがかけるのかもしれない。
というかC++はどこまでいってもマルチパラダイムなのであって純粋なオブジェクト指向言語ではないのだから、
ある程度Cの機能を取り入れて組んだほうがベターなんだと思いました。
そして情報の公開の程度に関して言えば公開する分だけヘッダーに記述して
必要以上にヘッダーには宣言を書かないということ。
ソース内でだけシングルトン形式で公開するマネージャークラスを作っておいて、
外部からもどうしても呼びたいAPIだけグローバル関数化してヘッダーに定義、
これで必要最小限まで公開範囲を抑えられるわけですね。
そして一個一個のオブジェクトはすべて独立して動くようにする、
一つのタスクの下に複数の子タスクが独立してぶら下がっている感じ、と教わりました。
そしてタスクはすべて独立して動く、状態が変わったことをマネージャークラスやハンドラーから受け取って
必要に応じてその状態に合わせた挙動を個別に取る。
親タスクが子タスクを管理する、くらいなら簡単ですが、孫タスク、ひ孫タスク、と階層が深くなれば厄介です(そもそもそんなに階層構造を深くはしませんが…)
アクションゲームなどでステージがあれば
そのステージにあるオブジェクトは一つ一つが実は独立して動いているのですね。
ギミックがあれば一つ一つのギミックはギミックというタスクとして動き、
それ全体を管理する親タスクから子タスクであるギミックを管理して…
でもその管理する親タスクはシーンという巨大なタスクが管理する…
シーンが変わると管理しているタスクはすべて破棄されて、とそんな感じの構造を理解しました。
この辺の考え方はゲーム作成の核心ともいえる部分で、
ここがわかるかどうかが重要なのかもしれません。
物理演算や衝突判定や3D座標系なんてものはそこに付随したものに過ぎないわけで、
実際一番大事なのは個々に動くオブジェクトの管理の仕方、メモリの管理の仕方にあるのかもしれない…
ではでは皆様良いお年を!
(o・・o)/
せんちゃの修行日記~わけのわからんことはしてはいけないの巻~
Re: せんちゃの修行日記~わけのわからんことはしてはいけないの巻~
クラスの参照関係というのがどのあたりを指しているのか分かりませんけど…
ゲームプログラミングの入門書とかにはサブクラスで個々のキャラクタを定義しましょうなんて書いてありますが、いまどきのゲームプログラムはスクリプトプレイヤーなのでそもそも複数のサブクラスを定義すること自体が無いのですよね。
プロジェクトの規模にもよりますけど。
shared_ptrのようなスマートポインタは内部でコンテナ作ってオブジェクト参照するので、オブジェクト自身がコンテナを参照するためには外から渡してやらなければいけませんし、不要になったインスタンスの回収をマネージャークラスなり外部で行なってやらなければいけません。
タスクがコンテナを内包するクラスを継承する設計でスマートポインタを作っておくと、孫タスク、ひ孫タスク、といくら階層が深くなっても、タスク自身が内部で自身の参照(というか所有権)を解放するだけで自動的に回収される仕組みを作れます。
タクスは自身のライフサイクルを内部完結で管理できますし、参照しているタスクが他にあるのにインスタンスが解放される危険もありません。
ブログにそれを続き物として書いてたんですが、途中まで書いたところで、標準ライブラリやboost知らないのかとか突っ込みをたくさんいただいたので、モチベ低下して放置したままなんですよね。
(追記)
落ち物パズルの落下ブロックの管理とかOOP的に設計するとめちゃくちゃシンプルにコード書けますよ。
ゲームプログラミングの入門書とかにはサブクラスで個々のキャラクタを定義しましょうなんて書いてありますが、いまどきのゲームプログラムはスクリプトプレイヤーなのでそもそも複数のサブクラスを定義すること自体が無いのですよね。
プロジェクトの規模にもよりますけど。
shared_ptrのようなスマートポインタは内部でコンテナ作ってオブジェクト参照するので、オブジェクト自身がコンテナを参照するためには外から渡してやらなければいけませんし、不要になったインスタンスの回収をマネージャークラスなり外部で行なってやらなければいけません。
タスクがコンテナを内包するクラスを継承する設計でスマートポインタを作っておくと、孫タスク、ひ孫タスク、といくら階層が深くなっても、タスク自身が内部で自身の参照(というか所有権)を解放するだけで自動的に回収される仕組みを作れます。
タクスは自身のライフサイクルを内部完結で管理できますし、参照しているタスクが他にあるのにインスタンスが解放される危険もありません。
ブログにそれを続き物として書いてたんですが、途中まで書いたところで、標準ライブラリやboost知らないのかとか突っ込みをたくさんいただいたので、モチベ低下して放置したままなんですよね。
(追記)
落ち物パズルの落下ブロックの管理とかOOP的に設計するとめちゃくちゃシンプルにコード書けますよ。
最後に編集したユーザー ISLe on 2012年12月28日(金) 00:01 [ 編集 1 回目 ]
Re: せんちゃの修行日記~わけのわからんことはしてはいけないの巻~
ISLeさん
クラスの参照関係というのは
ここでは単純に「あるオブジェクトの参照がないと動かない」という関係です。
クラスAはクラスBの参照が必要、クラスC、クラスDなどを追加するたびにクラスBにそれぞれの参照を渡さなければいけない、
というような作りにしてしまうと修正も非常に大変になってしまうのでできる限り一つ一つのオブジェクトは関係を持たない、
独立したものにしましょうというような話ですね。
ものすごい数のオブジェクトを取り扱うとなるとスクリプト化しないとやってられませんが、
ある程度その周りが小規模なプロジェクトなので現在のところはソースで持ってる感じです。
クラスの参照関係というのは
ここでは単純に「あるオブジェクトの参照がないと動かない」という関係です。
クラスAはクラスBの参照が必要、クラスC、クラスDなどを追加するたびにクラスBにそれぞれの参照を渡さなければいけない、
というような作りにしてしまうと修正も非常に大変になってしまうのでできる限り一つ一つのオブジェクトは関係を持たない、
独立したものにしましょうというような話ですね。
ものすごい数のオブジェクトを取り扱うとなるとスクリプト化しないとやってられませんが、
ある程度その周りが小規模なプロジェクトなので現在のところはソースで持ってる感じです。
Re: せんちゃの修行日記~わけのわからんことはしてはいけないの巻~
タスクにコンテナを内包した設計にすると参照する側が参照先の所有権(ポインタ)を持つだけで済むようになるんですけどね。せんちゃ さんが書きました:クラスAはクラスBの参照が必要、クラスC、クラスDなどを追加するたびにクラスBにそれぞれの参照を渡さなければいけない、
というような作りにしてしまうと修正も非常に大変になってしまうのでできる限り一つ一つのオブジェクトは関係を持たない、
独立したものにしましょうというような話ですね。
各タスクが自身の処理だけに集中できるのでむしろ保守性は上がると思いますが。
不要な参照をしてはいけないですが、必要な参照にも気を使わなくてはいけないとなるとキツイですね。
そんなもんですかね。せんちゃ さんが書きました:ものすごい数のオブジェクトを取り扱うとなるとスクリプト化しないとやってられませんが、
ある程度その周りが小規模なプロジェクトなので現在のところはソースで持ってる感じです。
ガラケーで数百KB程度の圧縮ファイルで配布される規模でもデータテーブルを並べたりスクリプトデータを読み込んで動かしてましたよ。
クライアントのルールでクラスの数に上限があったというのもありますけど。
最後に編集したユーザー ISLe on 2012年12月29日(土) 23:47 [ 編集 2 回目 ]
Re: せんちゃの修行日記~わけのわからんことはしてはいけないの巻~
例えば、オブジェクトの状態を管理するようなクラスであれば(Stateパターンのようなもの)ISLe さんが書きました: タスクにコンテナを内包した設計にすると参照する側が参照先の所有権(ポインタ)を持つだけで済むようになるんですけどね。
各タスクが自身の処理だけに集中できるのでむしろ保守性は上がると思いますが。
不要な参照をしてはいけないですが、必要な参照にも気を使わなくてはいけないとなるとキツイですね。
参照を渡してコントロールする、とかそういうのはありなのではないかなと。
ここでいう参照関係というのはもっと単純なもので、
STGで言うのであればエネミーがプレイヤーからの攻撃情報を取得するために
プレイヤーオブジェクトの参照を受け取ったり、アイテムオブジェクトの参照を取得したり、というものです。
つまり仕様が変更するに従ってパラメータが増えたらすべてのロジックに参照先を追加しなくてはいけないので、
さすがにそのような設計だとやがて破綻してしまうよね、というすごくシンプルな設計間違いの話です。
なのでそういったオブジェクトとオブジェクトの参照関係はできる限りシンプルに、ということなのだと思います。
逆に言えば全体に関わるレベルの参照でなければ、階層も追いやすく、
柔軟に対応もできるので法法としては全然ありなのではと私も思っています。
Re: せんちゃの修行日記~わけのわからんことはしてはいけないの巻~
そうでしたか。せんちゃ さんが書きました:ここでいう参照関係というのはもっと単純なもので、
STGで言うのであればエネミーがプレイヤーからの攻撃情報を取得するために
プレイヤーオブジェクトの参照を受け取ったり、アイテムオブジェクトの参照を取得したり、というものです。
つまり仕様が変更するに従ってパラメータが増えたらすべてのロジックに参照先を追加しなくてはいけないので、
さすがにそのような設計だとやがて破綻してしまうよね、というすごくシンプルな設計間違いの話です。
なのでそういったオブジェクトとオブジェクトの参照関係はできる限りシンプルに、ということなのだと思います。
たしかにわたしならそういう場合に参照を持たせるようなことはしませんね。
インターフェースを取得するメソッド(あるいは公開関数)を用意して、必要に応じてインターフェース経由で情報を取得する設計にします。