挫折不可能!初級ゲームプログラミング完全マニュアル  RSSを登録する

「ゲームが作りたいけどプログラミングなんて全然知らない」「文系だし数学や物理が苦手だけどゲームが作れるだろうか?」そんなアナタのためのメールマガジンです。PCの電源を入れてからどうすればいいのか?から自分のゲームが完成するまでを応援します!

最新号をメルマガでお届けします    
登録 解除

規約に同意して

登録した方には、まぐまぐの公式メルマガ(無料)をお届けします。
2008/09/03

初級ゲームプログラミング完全マニュアル [vol.0061 2008/09/03]

┏┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳┓
┣┛                                                              ┗┫
┃       挫折不可能!  初級ゲームプログラミング完全マニュアル       ┃
┃                                                                  ┃
┃                       第 61 号  2008/09/03                       ┃
┣┓                                                              ┏┫
┗┻━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┻┛
                            - Ads space -
┌┬───────────────────────────────┬┐
││ はじめに                                                     ││
└┴───────────────────────────────┴┘

 みなさま、こんにちは!

 個人ゲーム制作アドバイザーの Byerkut です!

 9月に入りましたが、暑かったり、肌寒かったり、ラジバンダリです。

 先日のことですが、なんと当ブログが Google で「ゲーム 作り方」の

 検索結果で1位になることができました。

 これも日頃、みなさまにご愛顧いただいているおかげです。

 本当にありがとうございました!

 これからもためになる情報発信を信念にがんばります!

 さて、今回は地球防衛隊員のまどかに最強の敵キャラが挑みます。

┌┬───────────────────────────────┬┐
││本日のラインナップ                                            ││
└┴───────────────────────────────┴┘

  ・今日のメインテーマ
      【敵母艦襲来!戦えまどか!明日を取り戻すんだ!】

  ・あとがき

┌┬───────────────────────────────┬┐
││ みんなの備忘録                                               ││
└┴───────────────────────────────┴┘

  ■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

┏┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳┓
┃┃                                                              ┃┃
┃┃                      今日のメインテーマ                      ┃┃
┃┃                                                              ┃┃
┃┃       【敵母艦襲来!戦えまどか!明日を取り戻すんだ!】       ┃┃
┃┃                                                              ┃┃
┗┻━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┻┛

 前回までのメルマガでゲームオーバー画面を実装できるように

 なりました。しかしながら、あの程度のヌルいゲームでやすやすと

 ゲームオーバーになってしまうプレイヤーは多くないでしょう。

 そこで今回は私からの挑戦です。ボスキャラクターを追加してみました。

 それではまいりましょう。



 早速、サンプルソースをダウンロードください。

  http://www.game-create.com/archives/673

 ダウンロードできましたら画像ファイルをプロジェクトディレクトリに

 コピーして遊んでみてください。しかも本気で。

 最後にボスキャラクターが出てきますので倒してみましょう。

 油断してはいけませんよ?ボスは敵キャラクターを吐いてきます。

 もちろん、ボスが吐いた敵キャラクターが陣地に落ちてもダメージを

 受けますので注意してください。



 …さて、いかがでしたでしょうか?

 ボスキャラクターらしいしぶとさがありましたよね。

 ちなみに 1000 発打ち込まないと倒せないようになっています。

 このクソゲーっぽい数値設定も好きな人にはたまらないと思います。



 さて、早速このボスキャラクターの裏側をお伝えしていくのですが、

 実は、ボスキャラクターと言っても今回のボスキャラクターは

 雑魚敵となんら変わりはありません。実際に enemies.cpp を開いて

 みてください。 Enemy001_* とよく似た Boss_* という関数があります。

  ------------------------------------------------------------------
 enemies.cpp
  ------------------------------------------------------------------
  void Boss_Initialize(Enemy &enemy)
  {
    // ボスの初期化
  }
  
  void Boss_Update(Enemy &enemy, HWND hWindow)
  {
    // ボスの更新(移動など)
  }
  
  void Boss_Draw(Enemy &enemy, HDC hBackBuffer)
  {
    // ボスの描画
  }
  ------------------------------------------------------------------

 ということは、ボスキャラクターが登場するタイミングも雑魚敵と同じ

 なのでしょうか? enemies_controller.cpp を見てください。

  ------------------------------------------------------------------
 enemies_controller.cpp
  ------------------------------------------------------------------
  static EnemiesTimeline enemiesTimeline[] = {
    100, Enemy001_Initialize, Enemy001_Update, Enemy001_Draw,
    200, Enemy001_Initialize, Enemy001_Update, Enemy001_Draw,
    300, Enemy001_Initialize, Enemy001_Update, Enemy001_Draw,
    400, Enemy001_Initialize, Enemy001_Update, Enemy001_Draw,
    500, Enemy001_Initialize, Enemy001_Update, Enemy001_Draw,
    600, Enemy001_Initialize, Enemy001_Update, Enemy001_Draw,
    1000, Enemy002_Initialize, Enemy002_Update, Enemy002_Draw,
    1100, Enemy002_Initialize, Enemy002_Update, Enemy002_Draw,
    1200, Enemy002_Initialize, Enemy002_Update, Enemy002_Draw,
    1300, Enemy002_Initialize, Enemy002_Update, Enemy002_Draw,
    1400, Enemy002_Initialize, Enemy002_Update, Enemy002_Draw,
    1500, Enemy002_Initialize, Enemy002_Update, Enemy002_Draw,
    2000, Enemy003_Initialize, Enemy003_Update, Enemy003_Draw,
    2100, Enemy003_Initialize, Enemy003_Update, Enemy003_Draw,
    2200, Enemy003_Initialize, Enemy003_Update, Enemy003_Draw,
    2300, Enemy003_Initialize, Enemy003_Update, Enemy003_Draw,
    2400, Enemy003_Initialize, Enemy003_Update, Enemy003_Draw,
    2500, Enemy003_Initialize, Enemy003_Update, Enemy003_Draw,
    3000, Boss_Initialize, Boss_Update, Boss_Draw,
  };
  static int frame   = 0;
  ------------------------------------------------------------------

 注目すべきは最後の1行です。

  ------------------------------------------------------------------
    3000, Boss_Initialize, Boss_Update, Boss_Draw,
  ------------------------------------------------------------------

 どうやら、雑魚敵と同じように時間が来たら登場するようですね。

 そうです、今回の場合は 3000 フレームが経過したらボスキャラクターが

 登場します。今回は簡略化のためボスキャラクターと雑魚キャラクターを

 同じような枠組みで使っていますが、実際のゲームでは全く別の

 プログラムが動くようなケースも珍しくありません。

 というかむしろそっちの方が多くなるはずです。

 本格的なボスキャラクターの作り方はタスクシステムを勉強してから

 取り扱いたいと思いますので今しばらくお待ちください。



 今回のボスキャラクターは雑魚敵と同じ枠組みで動いていることが

 わかりましたが、同じと言っても明確に違う部分がひとつあります。

 そうです、ボスキャラクターは雑魚敵を吐いてきます。

 この雑魚敵を吐くという行動はボスだけのものなのです。

 では、ボスキャラクターに雑魚敵を吐かせるためにはどうしたら

 良いのでしょうか?



 難しそうと思われましたか?

 でも冷静に考えてみてください。

 雑魚敵を画面に登場させる方法はすでに組んであるのです。

 ゲームが始まると敵キャラが上から降ってきますよね?

 この「上から降ってくる」を「ボスから降ってくる」に変えられれば

 目的を達成することができます。

 つまり、ボスキャラクターから「上から雑魚敵が降ってくる」という

 一連の処理を呼び出すことができればいいのです。



 この「呼び出す」という単語が出てきたら関数を思い出してください。



 プログラムでは「処理」を「呼び出す」という表現が出てきたら

 「関数を使う」ということなのです。



 では、「上から雑魚敵が降ってくる」という処理は

 どこにあるのでしょうか?わかったらすごいと思います。

 答えは enemies_controller.cpp です。

 UpdateEnemiesController() 関数の中をご覧ください。

  ------------------------------------------------------------------
  enemies_controller.cpp
  ------------------------------------------------------------------
  // タイムスケジュールに従って敵キャラを生成する
  if (current < (sizeof(enemiesTimeline) / sizeof(EnemiesTimeline))) {
    while (enemiesTimeline[current].frame == frame) {
      CreateEnemy((std::rand() % ENEMIES_SCREEN_WIDTH) - 32, -16,
                  enemiesTimeline[current].initializer,
                  enemiesTimeline[current].updater,
                  enemiesTimeline[current].drawer);
      current++;
    }
  }
  ------------------------------------------------------------------

 お、よく見ると CreateEnemy() といういかにも目的が達成できそうな

 関数があるではありませんか。これを使えば簡単にボスキャラクターから

 雑魚敵を生成することができそうですね。

 (ちなみに前回まではここが関数化されていませんでした、

  設計のミスですので、申し訳ありませんが忘れてください)



 この CreateEnemy() という関数は、第1引数と第2引数に

 生成する敵キャラクターの初期座標を設定し、第3第4第5引数に

 それぞれ、初期化関数、更新関数、描画関数を指定します。

 前述の例ではいろいろと計算していますが、これは敵キャラクターを

 ランダムな位置に登場されるための計算です。興味のある人は

 インターネットで調べてみましょう。当サイトにもヒントがあります。



 さて、これですべての用意が調いました。早速ボスキャラクターに

 雑魚キャラクターを吐かせてみましょう。

 …と、意気揚々と挑むのは良いのですが、どこに CreateEnemy() 関数を

 書けばいいのかわかりますでしょうか?

 実はいろんなところに書けるのですが、もっとも適切なのは

 enemies.cpp の Boss_Update() 関数の中です。

 この関数は敵の初期化と描画以外のすべての処理を担当するため、

 雑魚敵を吐くという処理はここがもっとも適しているのです。

 ちなみになぜ更新と描画の関数が分かれているのかというと、

 処理落ちが発生したときに描画処理のみをスキップするためです。

 関数が分かれていないと、どこからどこまでをスキップすればいいのか

 わからないというわけです。



 Boss_Update() 関数のなかに CreateEnemy() 関数を書けば良いという

 ことがわかりました。では具体的にどう記述すればいいのでしょうか?

 たとえば Enemy001_* に対応する敵キャラクターを吐かせたい場合は…

  ------------------------------------------------------------------
  enemies.cpp
  ------------------------------------------------------------------
  CreateEnemy(enemy.y, enemy.y, Enemy001_Initialize, Enemy001_Update, Enemy001_Draw);
  ------------------------------------------------------------------

 …となります。

 生成する敵キャラクターの初期座標に自分のX座標とY座標を入れている

 点に注目してください。自分が今いる位置から敵キャラクターを登場

 させることで、敵キャラクターを「吐かせる」という行動を実現します。

 同様に Enemy002_* と Enemy003_* の敵キャラクターを

 吐かせたい場合は…

  ------------------------------------------------------------------
  enemies.cpp
  ------------------------------------------------------------------
  CreateEnemy(enemy.y, enemy.y, Enemy002_Initialize, Enemy002_Update, Enemy002_Draw);
  CreateEnemy(enemy.y, enemy.y, Enemy003_Initialize, Enemy003_Update, Enemy003_Draw);
  ------------------------------------------------------------------

 …となります。

 実際に書く場合は乱数などを使って 100 フレームに1回くらいの

 ペースで敵キャラクターを生成するようにしてください。

 もし1フレームごとに敵キャラクターを生成してしまうと、

 1秒間に 60 体も敵キャラが登場してしまい、ゲームになりません。

 ちなみに Byerkut さんはここをどうやって書いたかというと…

  ------------------------------------------------------------------
  enemies.cpp
  ------------------------------------------------------------------
  void Boss_Update(Enemy &enemy, HWND hWindow)
  {
    int x = static_cast<int>(sin(static_cast<float>(enemy.time % 360) / 180 * 3.141592f) * 240);
  
    enemy.x = x + 320 - 120;
  
    enemy.y++;
  
    // 1/100 の確率で敵を吐く
    if ((rand() % 100) == 0) {
      int x = enemy.x + ((240 - 16) / 2);
      switch (rand() % 3) {
      case 0:
        CreateEnemy(x, enemy.y + 100, Enemy001_Initialize, Enemy001_Update, Enemy001_Draw);
        break;
      case 1:
        CreateEnemy(x, enemy.y + 100, Enemy002_Initialize, Enemy002_Update, Enemy002_Draw);
        break;
      case 2:
        CreateEnemy(x, enemy.y + 100, Enemy003_Initialize, Enemy003_Update, Enemy003_Draw);
        break;
      }
    }
  }
  ------------------------------------------------------------------

 …となっています。

 if ((rand() % 100) == 0) ということで 1/100 の確率で

 敵キャラクターを生成していることになります。

 この計算の意味は「ランダムな数値が 100 で割り切れたときに」です。

 つまり、適当な数値をコンピュータに決めてもらい、その数値が 100 で

 割り切れたときに敵キャラクターを生成するということをやっています。

 さらにその下に計算がありますが、これもランダムで3種類の敵の

 どれかを生成するということをやっています。

 それ以外にも計算をやっていますが、これらは座標の位置を調整するための

 ものですので、最初はわからなくてもかまいません。

 わかったところでプログラミングの腕は上達しませんので、

 気にしないのが良いと思います。



 さて、これでボスキャラクターが雑魚敵を吐くという仕様の全貌が

 明らかになりました。このあたりの数値を調整することで、

 ゲームの難易度を簡単にしたり難しくしたりということが

 できるようになります。



 では、次回は最終調整をしてゲームとして完成させてしまいましょう。

 いよいよ地球防衛戦線の最終決戦となります!



 今週も最後まで読んでいただきましてありがとうございます!

 それでは!

                                                            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

┌┬─────┬─────────────────────────┬┐
││ あとがき │  発行者のつぶやきです                            ││
└┴─────┴─────────────────────────┴┘

 今週は配信が送れてしまいましたが、次号は普通に土日に送ります。

 来週はインフィニットアンディスカバリーの発売が控えておりますので

 メルマガを書きためておこうと思います。

 トライエース最高!!!!!

┌┬───────────────────────────────┬┐
├┘                                                              └┤
│  購読の解除はこちら↓                                            │
│  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.
最新号をメルマガでお届け
登録 解除

規約に同意して

登録した方には、まぐまぐの公式メルマガ(無料)をお届けします。

最近の記事

上へ戻る