Skip to content

第11回 C++実践 独自ゲームの制作 2 / 基本動作の実装

前回: 第10回 C++実践 独自ゲームの制作 1 / 企画とクラス設計 / 次回: 第12回 C++実践 独自ゲームの制作 3 / 拡張とデバッグ

前回の振り返り

企画と実装順を決めました

  • 最小完成形を決めました
  • 操作、目的、終了条件を書き出しました
  • 登場するオブジェクトと持つ情報を洗い出しました
  • 今回は、企画を動くコードへ変えていきます

今回の目的

遊べる土台を作る

  • プレイヤーを表示して操作できるようにする
  • 相手や障害物を表示して更新する
  • 当たり判定またはスコア条件を入れる
  • PlayingGameOverGameClear の流れを作る

今回の授業内容

C++実践 独自ゲームの制作 2 / 基本動作の実装

  • 第10回で決めた実装順に沿って作る
  • 画面に出るものを1つずつ増やす
  • 毎フレームの更新と描画を分けて書く
  • 判定結果を状態につなげる
  • 完成度より、最後まで動く流れを優先する

基本動作の実装

とにかく動く形へ

完成の入口を 作ります

作業の進め方

1つ追加したら動かす

  • プレイヤーを出したら実行する

  • 入力を入れたら実行する

  • 敵を出したら実行する

  • 判定を入れたら実行する

  • まとめて書いてから実行すると、どこで壊れたか追いにくくなります

基本のゲームループ

更新してから描画する

cpp
while (ProcessMessage() == 0 && CheckHitKey(KEY_INPUT_ESCAPE) == 0)
{
    // 更新

    ClearDrawScreen();

    // 描画

    ScreenFlip();
}
  • 更新では、位置や状態を変えます
  • 描画では、現在の状態を画面に出します
  • 更新と描画を混ぜすぎないようにします

状態を先に用意する

終了条件を入れやすくする

cpp
enum GameState
{
    Playing,
    GameOver,
    GameClear
};

GameState gameState = Playing;
  • 独自制作でも、第06回と同じ考え方を使えます
  • Playing の間だけゲームを更新します
  • 結果が出たら表示を切り替えます

プレイヤーを用意する

操作できるものを最初に作る

cpp
GameObject player = { 320, 400, 32, 32, true };
int playerSpeed = 4;
  • 最初は画像でなく四角形でも構いません
  • 位置、大きさ、速度があれば操作の確認ができます
  • 見た目は、動く土台ができてから差し替えられます

プレイヤーを動かす

入力で位置を変える

cpp
if (gameState == Playing)
{
    if (CheckHitKey(KEY_INPUT_LEFT))  player.x -= playerSpeed;
    if (CheckHitKey(KEY_INPUT_RIGHT)) player.x += playerSpeed;
    if (CheckHitKey(KEY_INPUT_UP))    player.y -= playerSpeed;
    if (CheckHitKey(KEY_INPUT_DOWN))  player.y += playerSpeed;
}
  • 操作できることを優先します
  • 画面外へ出ない制限は、この後で追加しても構いません

相手や障害物を用意する

ゲームの目的に関係するものを出す

cpp
const int obstacleMax = 5;
GameObject obstacles[obstacleMax] = {};
int obstacleSpeed = 3;
  • 複数出すものは配列で扱えます
  • isActive を使うと、出ているものと空いている場所を分けられます
  • 弾やエフェクトと同じ考え方です

障害物を更新する

使用中のものだけ動かす

cpp
for (int i = 0; i < obstacleMax; i++)
{
    if (obstacles[i].isActive)
    {
        obstacles[i].y += obstacleSpeed;

        if (obstacles[i].y > 480)
            obstacles[i].isActive = false;
    }
}
  • 画面外へ出たら再利用できる状態に戻します
  • 落下、横移動、追尾など、動きの種類は企画に合わせます

当たり判定を入れる

判定結果を状態につなげる

cpp
for (int i = 0; i < obstacleMax; i++)
{
    if (IsHit(player, obstacles[i]))
    {
        gameState = GameOver;
    }
}
  • 当たったかどうかだけで終わらせず、結果へつなげます
  • クリア条件がある場合は、同じように GameClear へ切り替えます

スコアやタイマーを入れる

数値で達成条件を作る

cpp
int score = 0;

if (gameState == Playing)
{
    score++;

    if (score >= 1800)
        gameState = GameClear;
}
  • 60FPSなら、1800 フレームはおよそ30秒です
  • 正確な時間処理は後で調整できます
  • 最初は条件が分かりやすいことを優先します

結果を表示する

状態に応じて文字を出す

cpp
if (gameState == GameOver)
{
    DrawString(260, 220, L"GAME OVER", GetColor(255, 255, 255));
}
else if (gameState == GameClear)
{
    DrawString(260, 220, L"GAME CLEAR", GetColor(255, 255, 255));
}
  • 結果が表示されると、ゲームの区切りが分かりやすくなります
  • リトライ処理は、基本形ができた後で追加します

実習1: プレイヤーを操作する

画面に出して動かす

  1. プレイヤー用のデータを用意する
  2. 矢印キーで位置を変える
  3. プレイヤーを描画する
  4. 画面外へ出ないように調整する

実習2: 相手を追加する

敵や障害物を出す

  1. 敵や障害物のデータを用意する
  2. 画面に表示する
  3. 毎フレーム動かす
  4. 画面外へ出たら再利用できる状態にする

実習3: 結果までつなげる

ゲームとして終わる状態を作る

  1. 当たり判定またはスコア条件を入れる
  2. GameOver または GameClear に切り替える
  3. 結果の文字を表示する
  4. 途中まででも、遊べる流れを残す

よくあるつまずき

基本動作が安定しないときの確認ポイント

  • 1つ追加するごとに実行しているか
  • 更新処理が Playing の中にあるか
  • 描画処理が毎フレーム呼ばれているか
  • 配列の範囲外にアクセスしていないか
  • 結果が出たあとも更新が続いていないか

今回のまとめ

今日のポイント

  • 独自制作では、動く土台を先に作ることが重要です
  • 更新、判定、描画を分けると、問題を追いやすくなります
  • GameState を使うと、ゲームの結果までつなげやすくなります
  • 次回は拡張とデバッグを行い、遊びやすさを上げます

おつかれさまでした!

次回予告 第12回 独自ゲーム制作 3

ここから 詰めていきます