ゲーム開発とデザインパターン
DESCRIPTION
社内勉強会で使った資料を公開します。TRANSCRIPT
ゲーム開発とデザインパターン
~コスト削減とクオリティの両立を目指して ~
もんぐり
この勉強会の目的• デザインパターンに親近感をもってもらうこと
• ゲーム開発における、よりよい設計について一緒に考えてもらうこと
• ゲームの品質と開発スピードの向上に寄与すること
ちなみに、僕はデザインパターンの専門家でもゲーム開発の専門家でもなく、どっちも駆け出しなので、暖かくご意見ご指摘ください!
デザインパターンとは• Wikipediaの定義
– 過去のソフトウェア設計者が発見し編み出した設計ノウハウを蓄積し、名前をつけ、再利用しやすいように特定の規約に従ってカタログ化したものである。
• 代表的なのは GoFの 23個のデザインパターン
• 一言で表すと「直に書かずにクラスを分けろ」ってことかなと。(個人的解釈です)
デザインパターンを学ぶメリット
• 設計の世界共通言語– 「ここは FactoryMethodで設計してるんだ」って説明すれば、「ああ FactoryMethodね」って、すぐ話が通じるよ!
• 巨人の肩に乗る• 品質向上(バグを作りこみにくい設計)• メンテナンス性向上(読みやすい、修正しやすい)
• 品質向上 開発スピード向上≒
デザインパターンを学ぶメリットデザパタ駆使したとき
クラスの独立性が高くなるようにだけ気をつけた時
直にがんがん処理を書いてる時
パフォーマンス ◯ ◯ ◯
可読性 △ ◯ ☓
クラス独立性 ◯ △ ☓
ソースを書く速度 △ △ ◯
バグ発生率の低さ ◎ ◯ ☓
トータルな開発とメンテのコストの低さ
◎ ◯ ☓
※独断と偏見に基づく評価です
23個も覚えきれないよ!
(独断と偏見で)厳選したパターンを、適用事例とともにご紹介します!
こんな経験ないですか?• このインスタンスはアプリ内で 1個だけのはずなのに、勝手に別の場所でも作られちゃった!– アプリ全体のデータを保持したクラスとかの話
• → 利用者がそれと知らずに、複数インスタンスを扱っていると、バグに気づくのが遅れると大混乱に
インスタンス 1
インスタンス 2
利用者
更新 参照インスタンス
は1個だけだよね
Singleton• 1個しか作っちゃいけないものは1個しか作れないようにしておこう
• コンストラクタで例外投げたりAssertしたり、コンストラクタをprivateにしたりして、newを禁止します。
• Cocos2d-xでは、CCTextureCacheなど、キャッシュ系でよく使われてます。CCDirectorなどの単一機能クラスも Singletonになってます。
class SingletonClass {public:
static SingletonClass* getInstance();
private:static SingletonClass* m_instance;SingletonClass();
};
こんな経験ないですか?• Animalクラスを継承した子クラスを作って、子によって違う処理はそれぞれに隠蔽するぞ!
• → 開発してるうちに、子クラスの種類がどんどん増えてきたんだが。。。• → 大量の子クラスのヘッダを#includeしちゃってるよ! Switch-caseの caseの数がめっちゃ多いよ!
• ビルド時間増大、依存性増大、クラスの行数が増大し、扱いにくいソースに。。。
#include “Cat.h”#include “Dog.h”・・・ 100個の #include#include ”Dragon.h”
bool Game::init() {m_cat1 = new Cat();m_dog1 = new Dog();・・・m_doragon1 = new Dragon();return true;
};
FactoryMethod( &AbstractFactory)• 派生クラスのどれでもインスタンス生成できるクラスを別に作っておいて、それを使うようにしよう
• 派生クラスへの依存性をなくし、ポリモーフィズムを駆使できます
class AnimalFactory {public:
IFAnimal* createAnimal(ANIMAL_TYPE type);};
IFAnimal* AnimalFactory::createAnimal(ANIMAL_TYPE type) {switch(type) {case CAT:
return new AnimalCat();case DOG:
return new AnimalDog();・・・default:
return NULL;}
}
こんな経験ないですか?• 敵によって攻撃パターン(アルゴリズム)が違う。攻撃パターンはそれぞれの敵クラスに実装しよう
• → 攻撃パターン変更依頼もらったけど、それぞれの敵クラスに処理が散らばってて、少しずつ差分があるから修正量が半端ないよ!
• → 「敵 Aの攻撃パターンを敵 Bと同じやつに差し替えといて」って依頼もらったけど、アルゴリズムに結びつけたソースにしてるからほぼ全て書きなおしだ!
Strategy• →アルゴリズムごとにクラス作って、クラス内に詳細な処理は隠蔽し、どれも同じ I/Fで使用できるようにしておこう
• 僕は、複数パターンの AIを使い分けるときによく使っています。
class AttackAIFactory {public:
IFAttackAI* createAttackAI(AI_TYPE type);};
IFAttackAI* AttackAIFactory::createAttackAI(AI_TYPE type) {switch(type) {case VERTICAL_LASER:
return new AttackAIVerticalLaser();・・・default:
return NULL;}
}
class IFAttackAI { virtual vector<Cell> createAttackCollisionArea() = 0;
・・・};
こんな経験ないですか?• 状態管理は enumだね。ゲームのループで呼ばれるメソッド内で Switch 文書いて、処理を分岐すればよし!
• → case数の増大、 case内処理の増大。。。クラスの行数が増えて 3000 行を超えますた
switch(m_state) {case STATE_MOVING:
・・・break;
case STATE_ATTACKING:・・・break;
・・・case STATE_DEAD:
break;default
break;}
State• 状態ごとにクラス作って、どれも同じ I/Fで処理を起動できるようにしよう!
• 実際は、主クラスから、状態依存する処理だけを独立して切り出すのはなかなか難しい印象。使えるところに使っていこう。
class PlayerStateFactory {public:
IFPlayerState* createPlayerState(PLAYER_STATE state);};
IFPlayerState* PlayerStateFactory::createAttackAI(PLAYER_STATE state) {switch(state) {case PLAYER_STATE_POISON:
return new PlayerStatePoison();・・・default:
return NULL;}
}
class IFPlayerState {virtual void moveTo(Point point) = 0;・・・
};
こんな経験ないですか?• 弾幕シューティング、弾発射時にインスタンス生成、画面外にいったらインスタンス解放だ!
• →弾が多くなるとめっちゃフレームレート落ちるんですが。。。
Flyweight
• →必要なくなったインスタンスを解放せずに再利用すべし
• オブジェクトをプーリングするってことです• Cocos2d-xの場合は CCTextureCacheとか
CCSpriteBatchNodeとかの仕組みは揃ってるけど、まああんまり生成解放が頻繁だったら最初からプーリング書いてもいいと思う
• サンプルコードは書くのが面倒くさいので省略
こんな経験ないですか?• Playerと Enemyと Stageクラスを作ったぞ!
• 3者が密接に絡みすぎて、何か一つ修正するだけで影響範囲調査がしんどい。。。
Player
Enemy1
Stage
Enemy2
Mediator• →各オブジェクトを仲介するクラスを用意し、独立なオブ
ジェクト同士は直接やりとりしないようにする
• Mediatorは、次回に紹介するObserverパターンと組み合わせて、非同期処理の命令を実装するといいです– 非同期処理の例:
• 命令 :メソッド• 結果通知 : 次で紹介するObserverパターンによる通知
PlayerEnemy Stage
GameManager
(デザパタって)本当にゲーム開発の現場で
役に立つんかいな?
知り合いに聞いてみた
※このスライドは、個人情報が入ってくるので、SlideShare 版では記載を外しました。
• 個人的には、経験上、取捨選択すればおおいに使えると思っています。
まとめ• デザインパターンをいい感じに使えるようになって開発スピードと品質を向上させよう!– Singleton– FactoryMethod– State– Strategy– Flyweight– Mediator
• 次回は ObserverとMVCパターンを議論します。
参考書籍• 検索するとわかりやすい解説サイトが出てくるのでそれで
十分かもです。
• オブジェクト指向における再利用のためのデザインパターン– いわゆるGoF 本
• リファクタリング Martin Fowler 著
上の 2 冊は僕は読んでません!
• Java言語で学ぶデザインパターン• Java言語で学ぶリファクタリング入門
– 結城浩さんの本です