| || ● 1.ゲームを創ろう・入門編
 
 初回は「入門編」です。 ノーマルの C++Builder5 で簡単なゲームを作ります。 C++Builder には、フリーの優れたコンポーネントも沢山あるのですが、初回は「入門編」と言うことで、C++Builder5 付属コンポーネントだけでゲームを作ります。

○ 用意するもの
 一応、最新版の「C++Builder5 Learning」で作成しますが、旧バージョンでも全く大丈夫です。

○ 完成予定の作品
 「一匹インベーダー」の様なモノ。 画面上部で左右にウロウロしている敵機を、自機が打ち落とす簡単単純ゲームです。 キャラクタはテキスト記号などを使います。 自弾は連射無しの1発のみ。 3発ミス(敵に当たらず画面外に出てしまう)でゲームオーバーというルールです。

○ C++Builder5 起動直後画面
 
 
 以前から不思議に思っていたのですが、どうして一番安い Learning Edition に「server」なる項目があるのでしょうか? バグっすか?

○ コンポーネントの貼り付け
 
 
 [Additional] から、イメージをフォームに2枚貼り付けます。 場所は、どこでもOKです。 位置やサイズ指定、プロパティの制御等は、プログラムから直接行います。  
 
 
 
 [System] から、タイマーコンポーネントをフォームに貼り付けます。 このコンポーネントのプロパティも、プログラムから制御します。
今回使うコンポーネントは、これだけです。

○ 変数の宣言
 ヘッダファイル(Unit1.h)に変数の宣言を記述します。
 
 
 


  int jx, jy;  //  自機の位置格納変数
  int sx, sy;  //  自弾の位置格納変数
  int ex, ey;  //  敵機の位置格納変数

  int sf;      //  自弾が発射されてるか?フラグ
  int ef;      //  敵機の状態フラグ
  int eh;      //  敵機移動フラグ

  int score;   //  スコアを記録する変数
  int miss;    //  ミスカウントを記録する変数

  int K4, K6, KS; // キースキャン格納フラグ

 使う変数はこれだけ。 今回はポインタや構造体などは一切使いません。 このコーナーでは、C++の文法までは解説しませんので、各自でC++入門書は用意してください。
(注意)「//」と書かれている部分はリマークといって、この記号以降に書かれた文字は実行されず、コンパイラに無視されます。 つまり「//」と書かれている以降の文字は打たなくても大丈夫です。

○ プログラム開始
 まずは、FormCreate を起こします。 FormCreate に記述されたプログラムは、フォームが開く前に実行されます。 各初期化作業などを記述しておきます。 コンポーネントのプロパティも、ここで制御します。
 
 
 
 Form1 のイベントの「OnCreate」の項目をダブルクリックします。 するとエディタに「FormCreate」が用意されますので、そこにプログラムを記述します。


//  とりあえずタイマーコンポーネントは止めておく(今回のゲームでは、止めておかなくても良いんだけど)
  Timer1->Enabled = false;

//  Form1 の初期化(フォームのプロパティを制御)
  Form1->Caption = "サンプルゲーム";
  Form1->ClientWidth  = 200;
  Form1->ClientHeight = 200;
  Form1->BorderStyle  = bsDialog;
  Form1->Position     = poDesktopCenter;
 フォームのサイズを 200*200 に設定。 ウインドウタイプをダイアログタイプにして、位置はデスクトップセンター。

//  Image1 初期化(2枚のイメージキャンバスのプロパティを制御)
  Image1->Top  = 0;
  Image1->Left = 0;
  Image1->Width = 200;
  Image1->Height= 200;
  Image1->Visible = false;  //  非表示フラグ
//  Image2 初期化
  Image2->Top  = 0;
  Image2->Left = 0;
  Image2->Width = 200;
  Image2->Height= 200;
 2枚のイメージコンポーネントを 200*200 に設定。 Image1 は、作業用で画面には表示されません。 画面表示は Image2 のみです。 Image1 で作業 ― 転送 ―> Image2 で表示、とすることによって、画面のチラツキを軽減できます。

//  変数初期化(ヘッダファイルで宣言した変数に値を入れます)
  jx = 100;
  jy = 175;
  sf = 0;        // 0 -> 自弾発射OK ・ 1 -> 自弾発射中
  ef = 1;        // 0 -> 敵居ない ・ 1 -> 敵居る ・ 2 -> 敵爆発中
  ex = 100;
  ey = 15;
  eh = 0;        // 0 -> 左移動 ・ 1 -> 右移動
  score = 0;     //  最初はスコア値を「0」にしておく
  miss = 0;      // ミスも「0」に

// とりあえず背景を黒く塗っておく
  Image1->Canvas->Brush->Color = clBlack;
  Image1->Canvas->FillRect( Rect( 0, 0, 200,200) );

//  Timer1(タイマーコンポーネントを制御)
  Timer1->Interval = 45;
  Timer1->Enabled = true;    // タイマー・ON
 FormCreate の記述はここまで。
 
 OnCreate と同じ要領で、OnKeyDown と OnKeyUp を作ります。
OnKeyDown には、

  switch ( Key )
  {
    case VK_SPACE: KS = 1;
                   break;
    case VK_LEFT : K4 = 1;
                   break;
    case VK_RIGHT: K6 = 1;
  }
 を入力します。 OnKeyUP には、

  switch ( Key )
  {
    case VK_SPACE: KS = 0;
                   break;
    case VK_LEFT : K4 = 0;
                   break;
    case VK_RIGHT: K6 = 0;
  }
 を打ち込みます。 これで、「カーソルキー右」が押されたら変数 K6 に1が入り、「カーソルキー右」が押されていなければ K6 の値は0が入るようになりました。 同様に「カーソルキー左」の状態は K4、スペースバーの状態は KS に入ります。
 
 次は、いよいよタイマーコンポーネントです。 タイマーコンポーネントの OnTimer をダブルクリックし、Timer1Timer を起こします。 起こしたら、次のプログラムを入力しましょう。

//  作業画面(Image1)クリア
  Image1->Canvas->FillRect( Rect( 0, 0, 200, 200 ) );

//  スコア表示
  Image1->Canvas->Font->Size = 11;
  Image1->Canvas->Font->Color = clSilver;
  Image1->Canvas->TextOut( 20, 1, "Score" );
  Image1->Canvas->TextOut( 132, 1, "Miss" );

  Image1->Canvas->Font->Color = clFuchsia;
  Image1->Canvas->TextOut( 66, 1, IntToStr( score ) );
  Image1->Canvas->TextOut( 175, 1, IntToStr( miss ) );

  Image1->Canvas->Font->Size = 16;
 スコアの表示などをします。 Image1->Canvas->TextOut の記述は、Image1->Canvas->TextOut( X座標位置, Y座標位置, 表示する文字 ); です。

// ミスカウント
  if ( miss > 2 ) {
    Image1->Canvas->Font->Color = clYellow;
    Image1->Canvas->TextOut( 50, 100, "Game Over" );
    Timer1->Enabled = false;
  }
 変数 miss は、自弾の弾が画面外に出るたびに1づつ加算されるフラグです。 3になれば(プログラム的には、2以上になれば)、「Game Over」と画面に表示されて、タイマーコンポーネントが false になります。 つまりゲーム終了です。

//  自機移動
  if ( K4 == 1 ) {
    if ( jx > 10 ) jx -= 5;
  }
  if ( K6 == 1 ) {
    if ( jx < 190 ) jx += 5;
  }
 キースキャンフラグの K4 に1が入っているということは、カーソルキー左が押されているということなので、自機は左に移動します。 K6 も同様。

//  自機表示
  Image1->Canvas->Font->Color = clAqua;
  Image1->Canvas->TextOut( jx-9, jy, "Ω" );
 Image1->Canvas->TextOut は、Image1 に文字を表示するプログラムで、変数 jx, jy は自機の位置を覚えている変数。 つまり自機の座標X,Yに”Ω”を表示する。

//  自弾発射
  if ( sf == 0 && KS == 1 ) {
    sf = 1;
    sx = jx;
    sy = jy-5;
  }
 変数 sf は、自弾の状態フラグ。 0ならば、画面内に自弾が発射されていないと言う事なので、自弾を発射出来ます。 変数 sf が0で、しかもスペースバーのキースキャン状態が格納されている変数 KS が1(つまりスペースバーが押されている)の場合、自弾発射。

//  自弾移動
  if ( sf == 1 ) {
    sy -= 6;
    Image1->Canvas->Font->Color = clYellow;
    Image1->Canvas->TextOut( sx-9, sy, "‖" );
    //  自弾当たり判定
    if ( (ex-sx) > -26 && (ex-sx) < 23 ) {
    if ( (ey-sy) > -13 && (ey-sy) < 13 ) {
      ef = 2;
      sf = 0;
      score += 10;
    }
    }
    // 自弾、画面外へ(ミス加算)
    if ( sy < -10 ) {
      ++miss;
      sf = 0;
    }
  }
 自弾の移動と当たり判定。 自弾と敵機が当たれば、敵の状態フラグ ef に2が 入り、スコアが10加算されます。 自弾状態フラグ sf にも0が入り自弾も消えます。
 自弾が画面外に出てしまったら、miss が一つ加算されます。

//  敵機移動
  if ( ef == 1 ) {
    if ( eh == 0 ) {
      ex -= 4;
      if ( ex < 15 ) eh = 1;
    } else {
      ex += 4;
      if ( ex > 185 ) eh = 0;
    }
  }
 敵機移動方向変数 eh が0ならば左へ移動。 1ならば右へ移動。 画面端まで敵機が到達すれば、フラグには逆の値が入ります。

//  敵機表示
  if ( ef == 1 ) {
    Image1->Canvas->Font->Color = clRed;
    Image1->Canvas->TextOut( ex-19, ey, "∈∋" );
  } else {
    Image1->Canvas->Font->Color = clYellow;
    if ( ef%2 == 0 ) {
      Image1->Canvas->TextOut( ex-19, ey, "●●" );
    } else {
      Image1->Canvas->TextOut( ex-19, ey, "○○" );
    }
    if ( ++ef > 20 ) ef = 0;
  }
 敵機状態フラグに応じて、表示されるものが変わります。
 ef の値が1ならば敵機「∈∋」が表示されます。 ef の値が1以外なら爆発パターンが表示されますが、ef の値が1以上で偶数ならば「●●」が表示され、奇数ならば「○○」が表示されます。 交互にパタパタアニメさせているわけです。

//  敵機現る
  if ( ef == 0 ) {
    ex = 100;
    eh = random(2);
  }
 敵機が画面から居なくなれば、また中央に現れます。 移動方向は乱数で決めます。

//  Image1 -> Image2 へ転送
  Image2->Canvas->CopyRect( Image2->Canvas->ClipRect,
                            Image1->Canvas, Image2->Canvas->ClipRect);

}
 作業が終わった Image1 の画面は、表示用画面の Image2 に転送です。 これでチラツキ無く、表示できます。

○ プログラム完成
 これにて一応完成です。 実行させてみて、ちゃんとエラーなく動けばOKです。 エラーが出たら、打ち間違えた個所を修正しましょう。 この作業をデバックと言います。
 
 
 
 ゲーム画面。
 う〜ん、我ながらシンプル。 慣れれば、この程度のプログラム10分も掛からず完成させる事が出来ます。

○ プログラム配布
 ゲームは完成しましたが、このままでは友達にあげたり、ホームページで配布することが出来ません。(配布先の人のマシンに C++Builder が導入されている場合を除く)
 どのマシンでも動くように、ランタイムライブラリ無しでも動作するようにしておきます。
 
 
 
 まず、「プロジェクト」メニューの「オプション」を選び、プロジェクトオプションを呼びます。
 
 
 
 リリースを選択。
 
 
 
 「共有 RTL DLLを使う」のチェックを外します。
 
 
 
 「実行時パッケージを使って構築」のチェックも外します。
これで安心して配布できます。

○ 入門編終了
 入門編は、これで終了です。
 お疲れ様でした。 後はこのサンプルプログラムを改造したり修正したりして、プログラムそのものに慣れてください。 たとえば、自機の形や色を変えてみるとか、ミスが5つまで許される、といった具合に。 敵機が5体ほどワラワラ出てくる、というのも良いですね。