ゲーム制作講座1-3

3.自機が弾を撃てるようにしよう


 さて、前回は自機を操作できるようにしました。
 今回は自機の操作を発展させて弾を撃てるようにしてみようと思います。

 さて、ショットキーを押したかどうかの判断は前回まで何度も出てきた
CheckHitKey 関数を使えば容易に行えます。
 次に弾をどうやって飛ばすかですが、四角君とボール君を同時に動かすには
ゲーム制作講座1-1

 ボール君を少し動かして描画→四角君を少し動かして描画→描画したものをプレイヤーにみせる

を高速に繰り返すことで実現しました。弾の動きもボール君達と同じようにこの中に
追加することで実現します。
 つまり

 ボール君を少し動かして描画→自機の弾を少し動かして描画→四角君を少し動かして描画→描画したものをプレイヤーにみせる

 となります。
 ただ、自機の弾はボール君と四角君とは一つ違うところがあります。それは
弾は撃ち出されるまで画面には存在していないということです。
 当然ですが、弾が画面に飛んでいないのに。『自機の弾を少し動かして描画
をするのは明らかにおかしいです。どうにかしなくてはいけません。どうすれば
いいのかといいますと、それは弾が撃ち出されていないときは『自機の弾を少し
動かして描画』をしなければいい
のです。
 …当たり前ですね。重要なのはどうやって撃ち出されているかどうか判断
するか
です。
 こんなときに登場するのが、フラグです、旗です。なんらかの変数今弾が
画面上に撃ち出されているか
、というステータスを保存しておくのです。
例えば、存在している場合は変数にを代入しておき、存在していない場合は
を代入しておく、といった感じです。
 このように、ONかOFFか、のような状態を表しているのが丁度記し
となる旗の上げ下げに似ていることから、このような用途で使われる変数の
ことを『フラグ変数』とか、ただ単に『フラグ』等と呼びます。

 さて、『弾が撃ち出されているか』の状態を保持する変数を用意しなくてはならないことは
わかりました、では次に、一体どのタイミングでこの変数の内容を変えればいいのか
考えなければなりません。
 答えは弾が撃ち出された瞬間と、弾が何らかの原因で画面から消える瞬間の2つ
です。
 弾を撃ち出した瞬間に『弾が撃ち出されているか』の状態を保持する変数に
存在する』を意味するを代入してやり、画面から見えなくなったり、敵に
当たったりしたら『存在しない』を意味するを代入するのです。

 こうしてフラグ変数の内容の信頼性が確立出来たら、後は『自機の弾を少し
動かして描画
』を if 文を使ってフラグ変数の内容が『存在する』を意味する
のときのみ行うようにしてやります。

 ごたくが長くなりましたが、そんな感じで出来たのが次のプログラムです。

#include "DxLib.h" // WinMain関数 int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow ) { int BallX , BallY , BallGraph ; int SikakuX , SikakuY , SikakuMuki , SikakuGraph ; int ShotX , ShotY , ShotFlag , ShotGraph ; // 画面モードの設定 SetGraphMode( 640 , 480 , 16 ) ; // DXライブラリ初期化処理 if( DxLib_Init() == -1 ) return -1; // グラフィックの描画先を裏画面にセット SetDrawScreen( DX_SCREEN_BACK ) ; // ボール君のグラフィックをメモリにロード&表示座標をセット BallGraph = LoadGraph( "Ball.png" ) ; BallX = 288 ; BallY = 400 ; // 四角君のグラフィックをメモリにロード&表示座標をセット SikakuGraph = LoadGraph( "Sikaku.png" ) ; SikakuX = 0 ; SikakuY = 50 ; // 弾のグラフィックをメモリにロード ShotGraph = LoadGraph( "Shot.png" ) ; // 弾が画面上に存在しているか保持する変数に『存在していない』を意味する0を代入しておく ShotFlag = 0 ; // 四角君の移動方向をセット SikakuMuki = 1 ; // 移動ルーチン while( 1 ) { // 画面を初期化(真っ黒にする) ClearDrawScreen() ; // ボール君の操作ルーチン { // ↑キーを押していたらボール君を上に移動させる if( CheckHitKey( KEY_INPUT_UP ) == 1 ) BallY -= 3 ; // ↓キーを押していたらボール君を下に移動させる if( CheckHitKey( KEY_INPUT_DOWN ) == 1 ) BallY += 3 ; // ←キーを押していたらボール君を左に移動させる if( CheckHitKey( KEY_INPUT_LEFT ) == 1 ) BallX -= 3 ; // →キーを押していたらボール君を右に移動させる if( CheckHitKey( KEY_INPUT_RIGHT ) == 1 ) BallX += 3 ; // スペースキーを押していて、且弾が撃ち出されていなかったら弾を発射する if( CheckHitKey( KEY_INPUT_SPACE ) == 1 && ShotFlag == 0 ) { int Bw, Bh, Sw, Sh ; // ボール君と弾の画像のサイズを得る GetGraphSize( BallGraph , &Bw , &Bh ) ; GetGraphSize( ShotGraph , &Sw , &Sh ) ; // 弾の位置をセット、位置はボール君の中心にする ShotX = ( Bw - Sw ) / 2 + BallX ; ShotY = ( Bh - Sh ) / 2 + BallY ; // 弾は現時点を持って存在するので、存在状態を保持する変数に1を代入する ShotFlag = 1 ; } // ボール君が画面左端からはみ出そうになっていたら画面内の座標に戻してあげる if( BallX < 0 ) BallX = 0 ; // ボール君が画面右端からはみ出そうになっていたら画面内の座標に戻してあげる if( BallX > 640 - 64 ) BallX = 640 - 64 ; // ボール君が画面上端からはみ出そうになっていたら画面内の座標に戻してあげる if( BallY < 0 ) BallY = 0 ; // ボール君が画面下端からはみ出そうになっていたら画面内の座標に戻してあげる if( BallY > 480 - 64 ) BallY = 480 - 64 ; // ボール君を描画 DrawGraph( BallX , BallY , BallGraph , FALSE ) ; } // 自機の弾の移動ルーチン( 存在状態を保持している変数の内容が1(存在する)の場合のみ行う ) if( ShotFlag == 1 ) { // 弾を16ドット上に移動させる ShotY -= 16 ; // 画面外に出てしまった場合は存在状態を保持している変数に0(存在しない)を代入する if( ShotY < -80 ) { ShotFlag = 0 ; } // 画面に弾を描画する DrawGraph( ShotX , ShotY , ShotGraph , FALSE ) ; } // 四角君の移動ルーチン { // 四角君の座標を移動している方向に移動する if( SikakuMuki == 1 ) SikakuX += 3 ; if( SikakuMuki == 0 ) SikakuX -= 3 ; // 四角君が画面右端からでそうになっていたら画面内の座標に戻してあげ、移動する方向も反転する if( SikakuX > 576 ) { SikakuX = 576 ; SikakuMuki = 0 ; } // 四角君が画面左端からでそうになっていたら画面内の座標に戻してあげ、移動する方向も反転する if( SikakuX < 0 ) { SikakuX = 0 ; SikakuMuki = 1 ; } // 四角君を描画 DrawGraph( SikakuX , SikakuY , SikakuGraph , FALSE ) ; } // 裏画面の内容を表画面にコピーする ScreenFlip() ; // Windows 特有の面倒な処理をDXライブラリにやらせる // -1 が返ってきたらループを抜ける if( ProcessMessage() < 0 ) break ; // もしESCキーが押されていたらループから抜ける if( CheckHitKey( KEY_INPUT_ESCAPE ) ) break ; } DxLib_End() ; // DXライブラリ使用の終了処理 return 0 ; // ソフトの終了 }

<実行図>

弾の絵

 実行してスペースキーを押してみましょう、弾が一個飛んでいくはずです。
 上のサンプルプログラムでいう『撃ち出されているか』の状態を保持している変数は、ShotFlag
なります。
 スペースキーが押され、かつ弾がまだ撃ち出されていない場合は、弾の座標をセットし、『撃ち出されて
いるか
』の状態を保持する ShotFlag 変数にを代入します。
 次に『自機の弾の移動ルーチン』の部分では ShotFlagでない場合は弾の移動処理も、描画処理も
行わないわけです。

 なお、まだ四角君に当たったときのプログラムは何もしていませんので、当たって
もなにも起きませんのであしからず。(^^;
 さて、フラグ的な変数の使い方、おわかりいただけたでしょうか?

 次は今は一個しか飛んでいない弾を今度は沢山飛ばせるようにしてみたいと思います。

戻る