ゲーム開発とMVC
-
Upload
takashi-komada -
Category
Technology
-
view
3.810 -
download
2
description
Transcript of ゲーム開発とMVC
ゲーム開発とMVC
~コスト削減とクオリティの両立を目指して ~
もんぐり
前回のおさらい• デザインパターンを使いこなせれば、いい感じに開発スピードと品質が向上する!(かもしれない)
• 以下を紹介しました。– Singleton– FactoryMethod– State– Strategy– Flyweight– Mediator
• 今回はObserverとMVCを紹介します。– ていうかこの勉強会で一番伝えたかったのはMVCです!
• ちなみに、僕はMVCの専門家でもゲーム開発の専門家でもなく、どっちも駆け出しなので、暖かくご意見ご指摘ください!
こんな経験ないですか?• EnemiesManagerからEnemyの非同期処理メソッド呼び出すぞ。結果通知はEnemiesManagerのメソッド呼び出しで。
• → EnemiesManagerとEnemyが相互に#includeしあう(相互依存)関係になった。依存性強すぎ。
• EnemyからEnemiesManagerが見えている必要はないんでない?
• 別の例:タッチイベントが起こった時に、他クラスにそれを伝えよう。。• → 伝えるクラスが状況によって違う場合、それら全部を #includeしなきゃいけなかったら依存増えすぎ?
EnemiesManager Enemy
命令
結果通知
Observer• イベントを受けるための共通 I/Fの抽象クラスを用意し、イベントを受けるクラスはそれを派生することで、抽象クラスだけ#includeすればいいようにしておこう(タイプ1)
• イベントコールバックとして関数ポインタを登録しておこう(タイプ2)
• Cocos2d-xではCCTouchDelegateでObserverの考え方が使われています。(タイプ1)• Cocos2d-xではCCNotificationCenterという、イベント通知のための万能クラスが用意されています(タイプ2)
• CCNotificationCenterの使い方
• CCNotificationCenterは積極的に使いましょう
• ポーリングで監視する手もあります
イベントリスナ登録CCNotificationCenter::sharedNotificationCenter()->addObserver(this, callfuncO_selector(HelloWorld::enemyJumpEndHandler), ”enemyJumpEnd", NULL);
イベント通知CCNotificationCenter::sharedNotificationCenter()->postNotification( ”enemyJumpEnd", NULL);
こんな経験ないですか?• ゲームの演出について、仕様変更が頻繁すぎてソースがぐちゃぐちゃになってきたよ。。
• UIを変更したいんだけど、内部のコアなロジックと関連してて修正範囲めっちゃでかいよ。。。
MVC
• 画面の表示の都合や操作の都合により左右される部分と、内部のコアなロジックは分離しよう
• GUIアプリケーションやWebサービスの開発でよく使われるパターンです
• MVCはデザインパターンというよりアーキテクチャパターンと言われます– アプリ全体の設計方針を決定します– いくつかのデザインパターンを利用して実現します
MVC
ModelView
Controller
• Model– 抽象的な内部ロジック。アプリケーションの核。
• View– ユーザに見える部分。画面表示や、UIのユーザ操作窓口処理を受け持つ。
• Controller– ViewとModelを結びつける。ユーザ入力を受け付け、Modelを駆動する。
直接的依存性
Observerへの通知
MVCを使うメリット
• View(ユーザに見える部分)を修正してもModel(コアロジック)に影響が出ません→ 表示系の仕様変更に対して柔軟
• クラスの独立性が高いです→ 品質、メンテンナンス性向上
• Model部分を環境やフレームワーク非依存に作れます→ 移植性向上
• (Model部分は純粋にロジックだけなので自動テストを作成しやすいです)→ 品質、メンテンナンス性向上
• デメリットは、使いこなすのも処理を追うのもMVCへの理解と慣れがいること
ModelView
Controller
直接的依存性
Observerへの通知
MVCの実装例• 倉庫番の Playerクラスを PlayerModelと
PlayerViewクラスに分割してみる
左ボタン押下
ModelView
Controller
左ボタン押下
左ボタン押下
PlayerModel
PlayerView
PlayerModelの x座標変更
PlayerViewでの歩行アニメーション 座標変更通知
MVCの実装例:Modelと Viewの分割・ PlayerModelclass PlayerModel {public:
int m_cellX;int m_cellY;STATE m_state;・・・
};
Modelの世界では、プレーヤーの大きさだとか画面上の表示位置だとかは扱わない。セルの座標やプレーヤーの状態値といった、抽象的な情報のみ扱う。
・ PlayerViewclass PlayerView : public CCSprite {
PlayerModel* model;・・・
};
Viewの世界では、Modelの抽象データを、画面上の描画として具体化する。
通知にイベントリスナーを使用した場合
・ PlayerModel
void PlayerModel::walkTo(int cellX, int cellY) {m_cellX = cellX;m_cellY = cellY;// イベント通知CCNotificationCenter::sharedNotificationCenter()->
postNotification( ”playerMoved", NULL);}
・ PlayerView
bool PlayerView::init() {// 初期化時にイベントリスナ登録をしておくCCNotificationCenter::sharedNotificationCenter()->
addObserver(this, callfuncO_selector(PlayerView:move), ”playerMoved”, NULL);}
void PlayerView::move() {runWalkAimation(); // その場での歩行アニメーション// 0.5秒で目的地まで移動CCMoveTo* move = CCMoveTo(0.5f, getRealPosition(model->m_cellX, model->m_cellY));runAction(move);
}
ゲームループによって描画反映する場合・ PlayerModel// ゲームループにより毎フレーム updateメソッドが実行されるvoid PlayerModel::update() {
switch (Input->getInput()) {・・・case KEY_L: // 入力が左キーのとき
m_cellX--;// 状態を歩行中状態へ変更m_state = STATE_WALKING;break;
・・・}
}
・ PlayerView//ゲームループにより毎フレーム drawメソッドが実行されるvoid PlayerView::draw() {
switch(m_state) {・・・case STATE_WALKING:
// 毎フレームちょっとずつ位置を左にずらしていって 0.5秒後に目的地へ到達する処理。詳細は省略。
break;・・・}
}
いわゆるポーリングですが、これも ViewがModelの状態を監視してることには変わりない!
• ModelとViewの分離方法は、各ゲーム内容によって適した方法があると思います。
• あくまで、「表示やUIの詳細に左右される部分と、内部のコアロジックを切り離すことでメリットを享受する」のが目的です– 個人的には「」内が実現できるならどんな作り方でもいいと思います。
各ゲームジャンルへのMVCの適用シューティング
※SlideShare版では絵を外しました
アクション
※SlideShare版では絵を外しました
パズル
※SlideShare版では絵を外しました
(MVCって)本当にゲーム開発の現場で役に立つんかいな?
知り合いに聞いてみた
※このスライドは、個人情報が入ってくるので、SlideShare版では記載を外しました。
• 個人的には、経験上、取捨選択すればおおいに使えると思っています。
まとめ
• MVCをいい感じに使えるようになって開発スピードと品質を向上させよう!