【Delphi / C++Builder Starter チュートリアルシリーズ】 第10回 ‟シューティングゲーム スコアとゲームオーバーを付けよう„ [JAPAN]

Posted by on in Programming

【Delphi / C++Builder Starter チュートリアルシリーズ】

第10回 ‟シューティングゲーム スコアとゲームオーバーを付けよう„

10月24日より始まりました 「Delphi / C++Builder Starter チュートリアルシリーズ」。全10回、12月26日まで、毎週17時より30分間で、無料でダウンロード&利用できる開発環境のDelphi / C++Builder Starter エディションを使用して、ゲームを作るまで一通り、セミナーを実施してまいります。

 

なお、前回および初回分の内容に関するブログ記事は以下のリンクからお読み頂けます。

<< 第9回 ‟シューティングゲーム 敵を攻撃しよう„ 

<< 第1回 ‟無料で始めよう アプリ作成„ 

 

[アジェンダ]

  • スコア表示
  • プレーヤー / 敵の爆発
  • ゲームオーバー画面

 

[開発環境インストール] 

[Delphi / C++Builder Starter チュートリアルシリーズ]  第1回 ‟無料で始めよう アプリ作成„をご参考になり、開発環境をインストールしてください。 

 

 [シューティングゲーム用ドット絵フリー素材] 

http://mfstg.web.fc2.com/material/index.html 
上記サイトの画像を使わせて頂きました。(ありがとうございます)

 

[スコア表示]

敵を倒した回数の表示と、ゲームを開始してからの時間を表示する為にまずは

2つのグローバル変数が必要となります。

 

敵を倒した回数

スコア変数を作成しておきます。

////
//Delphiコード
var 
 FiTotal:Integer := 0; //スコア変数を追加
////
//C++コード
 int FiTotal{0}; 	//スコア変数を追加

第8-9回で作成したプレーヤー側ミサイルアニメーションOnFinishで

敵を倒した場合の処理にスコア加算コードを追加します。

////
//Delphiコード
procedure TfmShooting_main.FloatAnimation_missileFinish(Sender: TObject);
begin
  Button_missile.Enabled    := True;  //ミサイルボタンを有効にする
  Rectangle_missile.Visible := False; //ミサイルを非表示
  if Assigned(KanokeBuff) then        //敵撃破変数に敵存在するか確認
  begin
    Inc(FiTotal);//スコアに+1する処理
    KanokeBuff.Visible  := False;     //敵を非表示にする
  end;
  KanokeBuff          := nil;         //敵撃破変数を空にする
end;
////
//C++コード
void __fastcall TfmShooting_main::FloatAnimation_missileFinish(TObject *Sender)
{
	Button_missile->Enabled   	= true;
	Rectangle_missile->Visible 	= false;
	if (KanokeBuf != nullptr) {
		FiTotal++;//スコア変数を+1
		KanokeBuf->Visible     	   = false;
	}
             KanokeBuf = nullptr;
}

 

スタートからのトータル時間表示用の変数も用意します

////
//Delphi コード
var 
 FdtPlay: TDateTime=0; //トータル時間変数を追加
////
//C++コード
 TDateTime FdtPlay{0}; //トータル時間変数を追加

スタート画面の「START」した後に今の時間を入れる

////
//Delphi コード
procedure TfmShooting_main.FloatAnimation_player_xFinish(Sender: TObject);
begin
  Button_missile.Visible        := True;
  Button_up.Visible             := True;
  Button_down.Visible           := True;
  Timer_Enms.Enabled            := True;
  Timer_Enms_laserbeam.Enabled  := True;
  FdtPlay                       := Now;
end;

////
//C++ コード
void __fastcall TfmShooting_main::FloatAnimation_player_xFinish(TObject *Sender)
{
	Button_missile->Visible         = true;
	Button_up->Visible		    = true;
	Button_down->Visible	    = true;
	Label_score->Visible	    = true;
	Timer_Enms->Enabled     	    = true;
	Timer_Enms_laserbeam->Enabled   = true;

	FdtPlay = Now();
}

トータル時間とスコアを表示する。

TLabelを使って表示する場所を作成する 

敵の攻撃用に作成したTimer_Enms_laserbeamタイマーが05秒Intervalでしたので

Timer_Enms_laserbeamのOnTimerイベント内のコード後に

スコア表示のコードを追記します。

////
//Delphi コード
procedure TfmShooting_main.Timer_Enms_laserbeam_Timer(Sender: TObject);
Begin
  (敵がレーザービームを発射部分 省略)

  Label_score.Text  := Format('Time %s / Total Score %0.9d', [
      FormatDateTime('hh:nn:ss', Now - FdtPlay), FiTotal
    ]);
end;

////
//C++コード
void __fastcall TfmShooting_main::Timer_Enms_laserbeamTimer(TObject *Sender)
{
	(敵がレーザービームを発射部分 省略)

	Label_score->Text	= Format(L"Time %s / Total Score %0.9d", ARRAYOFCONST((
		FormatDateTime("hh:nn:ss", Now() - FdtPlay), FiTotal))
	);
}

 

[プレーヤー / 敵の爆発]

プレーヤー(戦闘機)が敵に衝突したり敵がミサイルに敵にヒットした場合アニメを使って爆発させています

TRectangleとTBitmapAnimationを応用して爆発を作ります。爆発に使う画像は7枚です。

爆発っぽく見えればいいので TBitmapAnimationをネストさせました。

TRectangleのFill画像にTBitmapAnimationを割り当て

割り当てたTBitmapAnimation.StopValueにさらにTBitmapAnimationを割当てています

爆発用TRectangle+TBitmapAnimationオブジェクトを

敵用とプレーヤー(戦闘機)用2つ用意します。

  • Rectangle_player_Bomb1(プレーヤー用TRectangle)
    • ScaleのXとYを2として敵爆発に比べて倍の大きさにしています。
  • Rectangle_enm_Bomb1(敵用TRectangle)

としました。

 

Rectangle_player_Bomb1(プレーヤー側)

 

爆発させる為の関数を用意します

////
//Delphiコード
procedure TfmShooting_main.Bomb_Start;
begin
  //プレーヤー(戦闘機)の爆破アニメーション実行
  Rectangle_player_Bomb1.Position.Y := Rectangle_player.Position.Y - 30;
  Rectangle_player_Bomb1.Visible  := True;
  BitmapAnimation_player_Bomb1.Start; //ネストしているアニメをすべてスタートさせます
  BitmapAnimation_player_Bomb2.Start;
  BitmapAnimation_player_Bomb3.Start;
  BitmapAnimation_player_Bomb4.Start;
  BitmapAnimation_player_Bomb5.Start;
  BitmapAnimation_player_Bomb6.Start;
end;
////
//C++コード
void __fastcall TfmShooting_main::Bomb_Start()
{
	//戦闘機の爆破アニメーション実行
	Rectangle_player_Bomb1->Position->Y	= Rectangle_player->Position->Y - 30;
	Rectangle_player_Bomb1->Visible	= true;
	BitmapAnimation_player_Bomb1->Start();
	BitmapAnimation_player_Bomb2->Start();
	BitmapAnimation_player_Bomb3->Start();
	BitmapAnimation_player_Bomb4->Start();
	BitmapAnimation_player_Bomb5->Start();
	BitmapAnimation_player_Bomb6->Start();
}

Rectangle_player_Bomb1(プレーヤー側)イベント側で爆発関数実行

////
//Delphiコード
procedure TfmShooting_main.Timer_gameoverTimer(Sender: TObject);
begin
  //(省略)
 if atari_ then
  begin
    //(省略)
    Bomb_Start;
    ShowMessage('ゲームオーバー');
  end
  else
    Timer_gameover.Enabled  := True;
end;
////
//C++コード
void __fastcall TfmShooting_main::Timer_gameoverTimer(TObject *Sender)
{
	(省略)
	if (atari_)//敵に衝突した
	{
		Bomb_Start(); 
		Rectangle_player->Visible  = false;
		ShowMessage("ゲームオーバー");
		game_reset(); //ゲームをリセットする
	}
	else
		Timer_gameover->Enabled	= true;
}

BitmapAnimation_player_Bomb6のOnFinishで爆発を消火する

////
//Delphiコード
procedure TfmShooting_main.BitmapAnimation_player_Bomb6Finish(Sender: TObject);
begin
  Rectangle_player_Bomb1.Visible  := False; //戦闘機爆破アニメ非表示
    Rectangle_player.Visible        := False; //戦闘機非表示
end;
////
//C++コード
void __fastcall TfmShooting_main::BitmapAnimation_player_Bomb6Finish(TObject *Sender)

{
	Rectangle_player_Bomb1->Visible	= false;	//戦闘機爆破アニメ非表示
	Rectangle_player->Visible		= false;	//戦闘機非表示
}

Rectangle_enm_Bomb1(敵側)爆発させる為の関数を用意します

////
//Delphiコード
procedure TfmShooting_main.Bomb_Enm;
begin
  //敵の爆破アニメーション実行
  Rectangle_enm_Bomb1.Visible  := True;
  BitmapAnimation_enm_Bomb1.Start;
  BitmapAnimation_enm_Bomb2.Start;
  BitmapAnimation_enm_Bomb3.Start;
  BitmapAnimation_enm_Bomb4.Start;
  BitmapAnimation_enm_Bomb5.Start;
  BitmapAnimation_enm_Bomb6.Start;
end;

 

プレーヤーミサイルアニメOnFinishイベント側で爆発関数実行

////
//Delphiコード
procedure TfmShooting_main.FloatAnimation_missileFinish(Sender: TObject); 
begin
  if Assigned(KanokeBuff) then        //敵撃破変数に敵存在するか確認
  begin
    Inc(FiTotal);
    Rectangle_enm_Bomb1.Position  := KanokeBuff.Position;
    Bomb_Enm;
    KanokeBuff.Visible  := False;     //敵を非表示にする
  end;
  KanokeBuff          := nil;         //敵撃破変数を空にする
end;

 

BitmapAnimation_enm_Bomb6のOnFinishで爆発を消火する

////
//Delphiコード
procedure TfmShooting_main.BitmapAnimation_enm_Bomb6Finish(Sender: Tobject);
Begin
  Rectangle_enm_Bomb1.Visible  := False; //敵爆破アニメ非表示
    Rectangle_enm.Visible        := False; //敵非表示
end;
////
//C++コード
void __fastcall TfmShooting_main::BitmapAnimation_enm_Bomb6Finish(TObject *Sender)

{
	Rectangle_enm_Bomb1->Visible	 = false;	//敵爆破アニメ非表示
	Rectangle_enm->Visible	 = false;	//敵非表示
}

 

[ゲームオーバー画面]

ゲームオーバー画面はスタート画面のように画面サイズに合わせてTRectangleで作成します

  • TRectangle
  • Tlabelを3つ
  • TFloatAnimation

 

Timer_gameover (TTimer)イベントの敵と衝突した判定部で

 

ゲームオーバー画面をアニメーションで出す

////
//Delphiコード
procedure TfmShooting_main.Timer_gameoverTimer(Sender: TObject); 
Begin
 (省略)
 if atari_ then
  begin
    Bomb_Start;//爆発
    Rectangle_gameoverscene.Position.Y  := -480;  	//ゲームオーバー画面の準備
    Rectangle_gameoverscene.Visible := True;
    Label_gameover_score1.Text      := Label_score.Text;  //スコア文字列コピー
    FloatAnimation_Gameover1.Start;                       //ゲームオーバーアニメスタート
//    ShowMessage('ゲームオーバー');
  end
  else
    Timer_gameover.Enabled  := True;
end;
////
//C++コード
void __fastcall TfmShooting_main::Timer_gameoverTimer(TObject *Sender)
{
	(省略)
	if (atari_)
	{
		Bomb_Start();//爆発
		Rectangle_gameoverscene->Position->Y	= -480;             //ゲームオーバー画面の準備
		Rectangle_gameoverscene->Visible	= true;
		Label_gameover_score1->Text		= Label_score->Text;//スコア文字列コピー
		FloatAnimation_Gameover1->Start();                     	 //ゲームオーバーアニメスタート
//		Rectangle_player->Visible  = false;
//		ShowMessage("ゲームオーバー");
	}
	else
		Timer_gameover->Enabled	= true;
}

Rectangle_gameoversceneのOnClickにて 再度スタート画面

第9回でTimer_gameoverタイマーイベントにあったgame_reset()関数を使います

////
//Delphiコード
procedure TfmShooting_main.Rectangle_gameoversceneClick(Sender: TObject);
begin
  game_reset; //ゲームをリセットする
end;
////
//C++コード
void __fastcall TfmShooting_main::Rectangle_gameoversceneClick(TObject *Sender)
{
    game_reset();   //ゲームをリセットする
}

 

[githubにソースを公開しております]

https://github.com/mojeld/embarcadero_jp_shooting_game

 

<<第9回 ‟シューティングゲーム 敵を攻撃しよう„



About
Gold User, No rank,
Delphi / C++Builder blogger

Comments

Check out more tips and tricks in this development video: