Appearance
第01回 環境確認とプロジェクト構造
次回: 第02回 ゲームループと描画
今回の授業内容
- 最終的に作る2Dシューティングゲームの仕様を確認する
- 開始用プロジェクトをVisual Studioで動かす
- フォルダ分割の意味と構成を確認する(
SourceとAssetsの役割) main.cpp、Game.h、Game.cppの役割を読む- 次回以降にコードを追加していく土台を用意する
この授業で作るもの
この授業では、DXライブラリを使った2Dシューティングゲームを13回で作ります
完成版では、プレイヤーを移動させ、弾を撃ち、敵を倒し、スコア、HP、残り時間、ゲーム状態を管理します
完成版の仕様は最初に確認しますが、完成版コードを写す授業ではありません
第01回では最小構成のプロジェクトを動かし、第02回以降で機能を1つずつ追加します
1つの機能を追加するたびにビルドして動作を確認するため、途中のどの回で止まっても、その時点までの実装は動く状態になります
完成形の仕様
| 項目 | 仕様 |
|---|---|
| 画面サイズ | 640x480 |
| 操作 | 矢印キーまたはWASDで移動、ZまたはSpaceでショット |
| 開始 | タイトル画面でEnter |
| プレイヤー | HPを3持ち、敵に当たるとダメージを受ける |
| 弾 | 最大48発を固定配列で管理する |
| 敵 | 最大24体を固定配列で管理し、一定間隔で出現する |
| エフェクト | 最大32個を固定配列で管理し、敵撃破時に表示する |
| クリア条件 | スコアが30に到達する、または制限時間を生き残る |
| ゲームオーバー条件 | プレイヤーのHPが0になる |
| リトライ | 結果画面でEnterを押す |
画像と音声は任意素材として扱います
素材がない状態でも、図形描画と無音でゲームロジックを確認できる構成にします
これは手抜きではなく、素材の準備状況に関係なく全員が同じ進度で実装を進められるようにするための設計です
授業の設計方針
この授業には、あらかじめ2つの方針があります
1つ目は、最初の6回はクラスを作らず、Gameクラスの中に構造体と配列を直接書くことです
プレイヤー、弾、敵をいきなり別クラスへ分けると、クラス同士がどんな情報をやり取りしているかが見えにくくなります
まず1つのクラスの中で全体の流れを書き切り、そのクラスが肥大化して見通しが悪くなる感覚を持ってから、第07回でクラスへ分割します
分割の前後で動作が変わらないことを確認できると、クラス分割が「動きを変える作業」ではなく「置き場所を整理する作業」だと実感できます
2つ目は、DXライブラリの各機能を独立した授業として扱わないことです
入力、衝突判定、画像、音、状態管理は、すべて同じシューティングゲームを完成させるための手段として登場します
1つの完成物を通して学ぶことで、機能同士がどう連携するかを合わせて学べます
今回の開始状態
配布ファイルからstarter.zipをダウンロードして展開します
第01回では、この開始用プロジェクトだけを使います
- Project
- Source
- main.cpp
- Common.h
- Game.h
- Game.cpp
- Assets
- Images
- Sounds
- Source
SourceにはC++のソースコードを置きますAssetsには画像や音声など、実行時に読み込むファイルを置きます
この2つを分けるのは、コードの変更とゲーム素材の変更を別々に扱えるようにするためです
たとえば画像を差し替えるだけであれば、Source側を再ビルドする必要はありません
最初に読むファイル
main.cppはゲームを起動する入口です
DXライブラリの初期化、ウィンドウ設定、Gameの実行、終了処理を担当します
cpp
int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
{
SetGraphMode(screenWidth, screenHeight, 32);
ChangeWindowMode(TRUE);
SetMainWindowText(L"Game Programming Practice C++/DX Library Intro");
if (DxLib_Init() == -1)
return -1;
SetDrawScreen(DX_SCREEN_BACK);
Game game;
if (game.Initialize())
game.MainLoop();
game.Finalize();
DxLib_End();
return 0;
}DxLib_Init()はDXライブラリ全体を使えるようにする関数で、失敗すると-1を返します
失敗時にそのまま処理を続けると、初期化されていない機能を呼び出してクラッシュするため、-1のときはmainをすぐ終了しますSetDrawScreen(DX_SCREEN_BACK)は、画面へ直接描かず裏画面へ描いてから一括で表示する設定です
1枚ずつ描くと描画途中がちらついて見えるため、裏画面を使ってからScreenFlip()で表画面へ切り替えます
game.Initialize()がfalseを返した場合はMainLoop()を呼びません
初期化に失敗した状態でゲームを動かすと、存在しないデータへアクセスする恐れがあるためです
第01回のInitialize()は常にtrueを返しますが、この形は第08回で画像読み込みの成否を扱うときにそのまま使います
Game.hは、ゲーム全体が持つ関数の宣言ですGame.cppは、それらの関数の中身です
第02回以降は、主にGame.hとGame.cppへ機能を追加します
実装手順
- DXライブラリ用のVisual Studioプロジェクトを作成する
starter/Source内の.hと.cppをプロジェクトへ追加するAssetsフォルダを実行ファイルから見える位置へ配置する- ビルドして、ウィンドウに
DX Library Projectと表示されることを確認する Common.hのscreenWidthとscreenHeightが画面サイズに使われていることを確認する
第01回ではゲーム機能を追加しません
環境を整え、次回から同じプロジェクトを継続して編集できる状態にします
よくある問題
DxLib.hが見つからない場合は、プロジェクトのインクルードディレクトリにDXライブラリのヘッダーパスが登録されているか確認する- リンクエラーが出る場合は、ライブラリディレクトリと追加の依存ファイル(
DxLib.libなど)が正しく設定されているか確認する - 黒い画面だけで文字が出ない場合は、
SetDrawScreen(DX_SCREEN_BACK)とScreenFlip()が呼ばれているか確認する Sourceに追加した.cppがVisual Studioプロジェクトへ登録されているか確認する。ファイルをエクスプローラーへコピーしただけでは、ソリューションエクスプローラー上に表示されていてもビルド対象にならない場合がある- ウィンドウがすぐ閉じる場合は、
DxLib_Init()が-1を返していないか、デバッグ実行でリターン値を確認する
今回の完成条件
- 開始用プロジェクトをビルドして実行できる
SourceとAssetsの違いを説明できるmain.cppがゲームの入口であることを説明できるGame.hとGame.cppの役割の違いを説明できる- 次回以降に同じプロジェクトを継続して編集できる
まとめ
今回は、完成形の仕様と開始用プロジェクトの構造を確認しました
次回は、この最小プロジェクトへプレイヤーの仮図形を追加します