2008/10/19
初級ゲームプログラミング完全マニュアル [vol.0067 2008/10/19]
┏┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳┓
┣┛ ┗┫
┃ 挫折不可能! 初級ゲームプログラミング完全マニュアル ┃
┃ ┃
┃ 第 67 号 2008/10/19 ┃
┣┓ ┏┫
┗┻━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┻┛
- Ads space -
┌┬───────────────────────────────┬┐
││ はじめに ││
└┴───────────────────────────────┴┘
みなさま、こんにちは!
個人ゲーム制作アドバイザーの Byerkut です!
仕事との調整がつかなかったため2週間ぶりのメルマガとなりました。
定期的に情報を発信できなくて申し訳ない気持ちですが、
適度な多忙は良いことだと思いますので、これからもがんばります。
さて、今回は if 文地獄を回避するための秘策があります。
┌┬───────────────────────────────┬┐
││本日のラインナップ ││
└┴───────────────────────────────┴┘
・今日のメインテーマ
【シーンを切り替えよう、メインループが小さくなるよ】
・あとがき
┌┬───────────────────────────────┬┐
││ みんなの備忘録 ││
└┴───────────────────────────────┴┘
■Visual C++ 2008 Express Edition をインストールする手順
http://www.game-create.com/archives/235
■Visual C++ 2008 Express Edition でプロジェクトを新規作成する手順
http://www.game-create.com/archives/270
■VC++ 2005 EE でプロジェクトにソースファイルを登録する手順
http://blog.mag2.com/m/log/0000240151/108824854.html
■画像ファイルを LoadImage() 関数で読み込めるようにする手順
http://www.game-create.com/archives/308
■ゲーム用ウィンドウのテンプレート
http://www.game-create.com/menu/downloads
■ビットマップ学習用クラス - Study::Bitmap
http://www.game-create.com/menu/downloads
┏┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳┓
┃┃ ┃┃
┃┃ 今日のメインテーマ ┃┃
┃┃ ┃┃
┃┃ 【シーンを切り替えよう、メインループが小さくなるよ】 ┃┃
┃┃ ┃┃
┗┻━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┻┛
2週間ぶりのごぶさたでしたが、今週も作って参りましょう。
宮崎 Byerkut 駿作品「崖の上のうみょーん」。
今回は予定していたとおり画面の切り替え部分を作っていきます。
まず、最初に言っておきますが、今回のプログラムは非常に地味です。
非常に地味ですが、前回お伝えしたような if 文の羅列を回避するための
最初の解決策ですので、頭に入れておいてください。
では、サンプルソースをダウンロードください。
http://www.game-create.com/archives/858
ダウンロードできたら実行してみてください。
今回は画像ファイルはありません。
真っ白な画面にメッセージが表示されます。
最初は「オープニング画面」です。
1を押すと「ゲームメイン画面」に移ります。
2を押すと「ゲームオーバー画面」に移ります。
3を押すと「ゲームメイン画面」に戻ります。
以下、これの繰り返しです。
何とも単純ですね。何とも単純なのですが、今回のプログラムは非常に
大きい意味があります。いったいどういう意味があるのでしょうか?
以前のサンプルソースでは、ゲームの機能が増えるたびに template.cpp 、
つまり WinMain() 関数があるファイルを更新していました。
これはなぜかというと template.cpp がゲームの中心となり、
「今ゲームはどういう状態か?」「今どの画面を表示すべきかか?」
「今何を描画すべきか?」などを if 文によって判断していたためです。
この方法でも問題なくゲームを作ることはできるのですが、
template.cpp が if 文だらけになり無駄に長くなってしまいます。
無駄に長くなるとバグが潜みやすくなります。
これでは大きいゲームの開発には向きません。
では、今回はいったい何をしたのでしょうか?
はい、今回は「今どの画面を実行すべきか?」を変数に
保存しておくようにしました。この変数の中身を書き換えることで
違う画面を実行できるようにしております。
たとえば以前までの template.cpp は次のようになっていました。
------------------------------------------------------------------
template.cpp
------------------------------------------------------------------
void UpdateGame(HWND hWindow, HDC hBackBuffer)
{
if (currentScene == Opening) {
// オープニング
UpdateOpening(hWindow, hBackBuffer);
} else if (currentScene == Main) {
// ゲームのメイン
UpdateBackground(hWindow, hBackBuffer);
UpdatePlayer(hWindow, hBackBuffer);
UpdatePlayerBullets(hWindow, hBackBuffer);
UpdateEnemiesController(hWindow, hBackBuffer);
UpdateEffectsController(hWindow, hBackBuffer);
CheckCollisionPlayerBulletsAndEnemies(GetPlayerBullets(), GetEnemies());
} else if (currentScene == GameOver) {
// ゲームオーバー
UpdateBackground(hWindow, hBackBuffer);
UpdateEffectsController(hWindow, hBackBuffer);
UpdateGameOver(hWindow, hBackBuffer);
} else if (currentScene == Ending) {
// エンディング
UpdateEnding(hWindow, hBackBuffer);
}
}
------------------------------------------------------------------
currentScene という変数の中身を判断して、 Opening の時には
UpdateOpening() 関数を実行し、 Main の時には次の関数を
実行していました(ゲームのメインとなる関数群ですね)。
UpdateBackground();
UpdatePlayer();
UpdatePlayerBullets();
UpdateEnemiesController();
UpdateEffectsController();
CheckCollisionPlayerBulletsAndEnemies();
このメルマガで扱っているくらい小さなゲームでさえこれだけの if 文に
なってしまうのですから、この調子では本格的なゲームは作れそうに
ないですよね。 if 文だらけになってしまいます。
それが、今回はこうなっています。
------------------------------------------------------------------
bootstrap.cpp
------------------------------------------------------------------
void UpdateGame(HWND hWindow, HDC hBackBuffer)
{
UpdateScene();
}
------------------------------------------------------------------
なんと、1行ですね!
しかもすごいのはこの1行はどんなにゲームが大きくなっても
一切変更されることがないということです。もう最後までこのままです。
先ほどの方法では画面が増えるたびに if 文が増える計算ですが、
今回からの方法では画面が増えてもソースコードは増えますが、
この1行は変化しません。
これはなぜなのでしょうか?
では、 UpdateScene() の中身を見てみましょう。
scene.cpp を開いてください。
------------------------------------------------------------------
scene.cpp
------------------------------------------------------------------
void UpdateScene()
{
currentUpdate(window, device);
}
------------------------------------------------------------------
おや、こちらも1行です。これではなんのこっちゃわかりませんね?
実は currentUpdate というのは変数なのです。
currentUpdate という変数の中には「今実行すべき画面の関数の番号」が
入っており currentUpdate() と書くことで currentUpdate 変数の
中に入っている関数を実行することができるのです。
今回のサンプルプログラムを実行すると最初に「オープニング画面」が
表示されますが、それは currentUpdate 変数に UpdateOpening() という
関数が入っているからです。ちなみに bootstrap.cpp の
InitializeGame() という関数の中でセットしています。
------------------------------------------------------------------
bootstrap.cpp
------------------------------------------------------------------
void InitializeGame(HWND hWindow, HDC hBackBuffer)
{
InitializeScene(hWindow, hBackBuffer);
// 最初はオープニング画面
ChangeScene(UpdateOpening, DrawOpening, NULL, InitializeOpening);
} ~~~~~~~~~~~~~ ~~~~~~~~~~~ ←注目!
------------------------------------------------------------------
ChangeScene() という関数は currentUpdate 変数に関数を保存するための
関数です。第1引数にゲーム更新の関数、第2引数にゲーム描画の関数を
渡します。第3引数と第4引数は今回使っていませんので無視してください。
ChangeScene() 関数では引数として渡された関数を変数に保存しています。
------------------------------------------------------------------
scene.cpp
------------------------------------------------------------------
void ChangeScene(Scene update, Scene draw, Scene finalizer, Scene initializer)
{ ~~~~~~ ~~~~
// 前は省略… ↑更新関数 ↑描画関数
currentUpdate = update; // ←更新関数を保存
currentDraw = draw; // ←描画関数を保存
}
------------------------------------------------------------------
つまり、まとめると次のようになっています。
ゲーム開始
↓
currentUpdate 変数にオープニング画面の関数を保存する
↓
ゲームループ
↓ ↑
currentUpdate 変数に保存されている関数を実行する
↓ ↑
currentDraw 変数に保存されている関数を実行する
↓ ↑
(以下、繰り返し)
最初は currentUpdate 変数には UpdateOpening() 関数が入っていますので
ゲームループでは UpdateOpening() 関数が実行されますが、
オープニング画面で1を押すと「ゲームメイン画面」に切り替わります。
これは currentUpdate 変数に UpdateGameMain() 関数を保存することで
実現します。具体的には opening.cpp の UpdateOpening() 関数を
開いてください。
------------------------------------------------------------------
opening.cpp
------------------------------------------------------------------
void UpdateOpening(HWND hWindow, HDC hBackBuffer)
{
if (GetKeyState('1') & 0x8000) {
ChangeScene(UpdateGameMain, DrawGameMain);
} ~~~~~~~~~~~~~~ ~~~~~~~~~~~~
} ↑更新関数 ↑描画関数
------------------------------------------------------------------
先ほど使った ChangeScene() 関数を使って currentUpdate 変数の中身を
書き換えています。今までは currentUpdate 変数には UpdateOpening()
関数が入っていましたが、1キーを押すことで currentUpdate 変数に
UpdateGameMain() という関数を新しく保存しています。
今後は currentUpdate() と実行すると UpdateGameMain() 関数が
実行されるようになります。
これで画面がいくら増えてもメインのプログラムに if 文が増えることは
なくなりました。これは「関数へのポインタ変数」という技術なのですが、
最初は難しいと思いますので、今回は次のことだけ覚えてください。
今後は画面を切り替えるときには ChangeScene() 関数に
次の画面の更新関数と描画関数を渡す!!!
…です。
たとえばライフが0になってゲームオーバー画面を出したいときには
必ず ChangeScene() でゲームオーバー画面の関数を設定しますので、
注意深くソースコードを観察してみてください。
来週も「崖の上のうみょーん」の制作を続けていきます。
どんどんソースコードを追加してゲームらしくしていきましょう。
今回も最後まで読んでいただきましてありがとうございます!
それでは!
Byerkut.
┌┬───────────────────────────────┬┐
││ 重要記事のダイジェスト ││
└┴───────────────────────────────┴┘
■C++ は計算と記憶しかできない
■外部の機能(関数)を借り受けるには #include を使う
■#include で借り受けた機能を使うには関数を呼び出す
http://archive.mag2.com/0000240151/20080203171350000.html
■Windows プログラムには必ず WinMain() 関数から開始する
http://archive.mag2.com/0000240151/20080209215231000.html
■プログラムは関数の集まり
■プログラムは関数を増やしてソフトウェアを作る
■関数には次の要素がある(名前・機能・引数・戻り値)
http://archive.mag2.com/0000240151/20080216090000000.html
■関数を作には次の要素を決める(名前・機能・引数・戻り値)
http://archive.mag2.com/0000240151/20080608200909000.html
■プログラムはソースコードを分散させて大きなソフトを作る
http://archive.mag2.com/0000240151/20080525121425000.html
http://archive.mag2.com/0000240151/20080531212858000.html
■ゲームを作るためには「入力」「出力」「条件分岐」が必要
http://archive.mag2.com/0000240151/20080301221623000.html
■画像ファイルの絵を画面に表示する際にはメモリに読み込む
http://archive.mag2.com/0000240151/20080406202024000.html
■LoadImage() 関数はコピペで使い回せる
■LoadImage() 関数の第2引数は
メモリに読み込みたい画像ファイルの名前を渡す
■LoadImage() 関数で読み込むファイルは
プロジェクトディレクトリにおいてある必要がある
http://archive.mag2.com/0000240151/20080413174135000.html
┌┬─────┬─────────────────────────┬┐
││ あとがき │ 発行者のつぶやきです ││
└┴─────┴─────────────────────────┴┘
Wii でモンハンが出るらしいですね。
また Wii 売れますね。
このままではスタン・ハンセンが黙っていません。
┌┬───────────────────────────────┬┐
├┘ └┤
│ 購読の解除はこちら↓ │
│ http://www.game-create.com/contents/gp_beginners_ml │
├┐ ┌┤
└┴───────────────────────────────┴┘
- Ads space -
┌┬───────────────────────────────┬┐
├┘ └┤
│ 「挫折不可能!初級ゲームプログラミング完全マニュアル」は、 │
│ 「いちばんやさしいゲームの作り方」が運営しています。 │
│ │
│ サイト : http://www.game-create.com/ │
│ 発行元 : http://www.game-create.com/menu/about │
│ 発行者 : http://www.game-create.com/menu/profile │
│ 問い合わせ : http://www.game-create.com/menu/contact │
│ 利用規約 : http://www.game-create.com/informations/agreement │
├┐ ┌┤
└┴───────────────────────────────┴┘
POWERED BY LIBERTIASTER GAME STYLE.


