【Delphi / C++Builder Starter チュートリアルシリーズ】 第8回 ‟シューティングゲーム 敵を動かしてみよう„ [JAPAN]

Posted by on in Programming

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

 

第8回 ‟シューティングゲーム 敵を動かしてみよう

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

 

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

<< 第7回 ‟シューティングゲーム キャラクターを貼り付けよう そして動かそう„ 

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


 

[アジェンダ]

  • TBitmapAnimationで敵を動かす
  • TTimerとRandom()を 使い敵を出現

 

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

 

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

 

[今回の仕様]

前回(第7回)ではプレーヤー(戦闘機)の上下移動と戦闘機から発射されるミサイル攻撃までをプログラミングしてきました。

今回は敵が出てきます。敵が出現し敵からレーザービーム発射される部分を作ります。

 

 [敵]

←的です

敵も前回と同じくTRectangleを使って、前回と同じようにFill.Bitmapに敵の画像を設定していきます

ここで新しくTBitmapAnimationが出てきます

  • Enabled = アニメーション開始
  • Duration = 開始値から終了値までの、アニメーションする時間(秒数)。
  • Loop =アニメーションを無制限に繰り返します。
  • StartValue =ビットマップ イメージから開始します。
  • StopValue =このビットマップ イメージに到達した際に、停止します。

 

[敵出現(動かす)]

敵は合計3つです。これを使いまわします。

出現の動きは全て1秒タイマーイベントでランダムに敵アニメーションを実行します

敵TRectangleのPosition.X(横軸)にTFloatAnimationを設定します。

TFloatAnimation設定方法は前回と同じです

1秒間のタイマーイベントでランダムに敵のTFloatAnimationをスタートさせます。

TTimerを使いInterval=1000とします。OnTimerで下記のように実装します

 

[TTimer OnTimer]

Delphi

////
procedure TfmShooting_main.Timer_EnmsTimer(Sender: TObject);
var
  iEnm:   Integer;  //乱数0~4敵番号を決定する変数
  iEnm_y: Integer;  //乱数敵Position.Yを決定する変数
  procedure enm_start(enm: TRectangle; ani: TFloatAnimation; bani: TBitmapAnimation);
  begin
    if not enm.Visible then             {敵が待機している場合}
    begin
      enm.Position.Y  := iEnm_y;        {敵のY座標を決定}
      enm.Visible     := True;          {敵を表示}
      ani.StartValue  := Width + 10;
      ani.StopValue   := -enm.Width -10;
      ani.Start;                        {Position.Xを左に移動開始}
      bani.Start;                       {敵ビットマップアニメ開始}
    end;
  end;
begin
  iEnm    := Random(5);                 {0~4決定}
  iEnm_y  := Random(Self.Height - 100); {Positon.Y決定}
  case iEnm of
    1:enm_start(Rectangle_Enm1, FloatAnimation_Enm1, BitmapAnimation_Enm1);
    2:enm_start(Rectangle_Enm2, FloatAnimation_Enm2, BitmapAnimation_Enm2);
    3:enm_start(Rectangle_Enm3, FloatAnimation_Enm3, BitmapAnimation_Enm3);
  end;
end;

C++Builderコード

////
void __fastcall TfmShooting_main::enm_start(TRectangle* enm, TFloatAnimation* ani, TBitmapAnimation* bani)
{
	std::uniform_int_distribution<int> enm_position( 0, this->Height-100 ) ;
	unsigned int iEnm_y = enm_position(randomize_); //
	if (! enm->Visible) {
		enm->Position->Y    = iEnm_y;
		enm->Visible        = true;
		ani->StartValue     = this->Width + 10;
		ani->StopValue      = -enm->Width - 10;
		ani->Start();
		bani->Start();
	}
}

void __fastcall TfmShooting_main::Timer_EnmsTimer(TObject *Sender)
{
	std::uniform_int_distribution<int> enm_num( 0, 4 ) ;
	unsigned int iEnm = enm_num(randomize_);
	switch(iEnm){
	case 1: enm_start(Rectangle_Enm1, FloatAnimation_Enm1, BitmapAnimation_Enm1);
        break;
	case 2: enm_start(Rectangle_Enm2, FloatAnimation_Enm2, BitmapAnimation_Enm2);
		break;
	case 3: enm_start(Rectangle_Enm3, FloatAnimation_Enm3, BitmapAnimation_Enm3);
	}
}

 

[敵のTFloatAnimation OnFinish]

Delphiコード

////
procedure TfmShooting_main.FloatAnimation_Enm1Finish(Sender: TObject);
begin
  Rectangle_Enm1.Visible  := False; {画面からフレームアウト後 敵1を非表示}
end;

procedure TfmShooting_main.FloatAnimation_Enm2Finish(Sender: TObject);
begin
  Rectangle_Enm2.Visible  := False; {画面からフレームアウト後 敵2を非表示}
end;

procedure TfmShooting_main.FloatAnimation_Enm3Finish(Sender: TObject);
begin
  Rectangle_Enm3.Visible  := False; {画面からフレームアウト後 敵3を非表示}
end;

C++Builderコード

////
void __fastcall TfmShooting_main::FloatAnimation_Enm1Finish(TObject *Sender)
{
	Rectangle_Enm1->Visible = false;	//画面からフレームアウト後 敵1を非表示
}
//---------------------------------------------------------------------------

void __fastcall TfmShooting_main::FloatAnimation_Enm2Finish(TObject *Sender)
{
	Rectangle_Enm2->Visible = false;    //画面からフレームアウト後 敵2を非表示
}
//---------------------------------------------------------------------------

void __fastcall TfmShooting_main::FloatAnimation_Enm3Finish(TObject *Sender)
{
	Rectangle_Enm3->Visible = false;    //画面からフレームアウト後 敵3を非表示
}
//---------------------------------------------------------------------------

void __fastcall TfmShooting_main::FloatAnimation_player_yFinish(TObject *Sender)
{
    Button_missile->Enabled = true;
}

 

[敵が攻撃]

敵から出力されるレーザービーム攻撃を作ります

 

レーザービームもTRectangleとPosition.XはTFloatAnimationです

TFloatAnimationのDurationは1.2秒にします。

 レーザービーム攻撃開始するための新しいタイマーを作ります

TTimerを使いこれもInterval=1000でTimer_Enms_laserbeamとしました。

 

[TTimer OnTimer]

Delphiコード

////procedure TfmShooting_main.Timer_Enms_laserbeam_Timer(Sender: TObject);
var
  iEnm: Integer;  //乱数0~4敵番号を決定する変数
  procedure MissileStat(enm: TRectangle);
  begin
    if (not Rectangle_Enm_laserbeam.Visible) and enm.Visible then
    begin
      Rectangle_Enm_laserbeam.Position.Y      := enm.Position.Y + 25;
      Rectangle_Enm_laserbeam.Visible         := True;
      FloatAnimation_Enm_laserbeam.StartValue := enm.Position.X - 20;
      FloatAnimation_Enm_laserbeam.StopValue  := FloatAnimation_Enm_laserbeam.StartValue - (Self.Width + 50);
      FloatAnimation_Enm_laserbeam.Start;
    end;
  end;
begin
  iEnm  := Random(5); //乱数0~4決定
  case iEnm of
  1:MissileStat(Rectangle_Enm1);
  2:MissileStat(Rectangle_Enm2);
  3:MissileStat(Rectangle_Enm3);
  end;
end;

C++Builderコード

void __fastcall TfmShooting_main::EnmlaserbeamStat(TRectangle* enm)
{
	if (!(Rectangle_Enm_laserbeam->Visible) && enm->Visible) {
		Rectangle_Enm_laserbeam->Position->Y  		= enm->Position->Y + 25;
		Rectangle_Enm_laserbeam->Visible      		= true;
		FloatAnimation_Enm_laserbeam->StartValue	= enm->Position->X -20;
		FloatAnimation_Enm_laserbeam->StopValue		= FloatAnimation_Enm_laserbeam->StartValue - (this->Width + 50);
		FloatAnimation_Enm_laserbeam->Start();
	}
}

void __fastcall TfmShooting_main::Timer_Enms_laserbeamTimer(TObject *Sender)
{
	std::uniform_int_distribution<int> enm_num( 0, 3 ) ;
	unsigned int iEnm = enm_num(randomize_);
	switch(iEnm){
	case 1:EnmlaserbeamStat(Rectangle_Enm1);
		break;
	case 2:EnmlaserbeamStat(Rectangle_Enm2);
		break;
	case 3:EnmlaserbeamStat(Rectangle_Enm3);
	}
}

 [レーザービーム TFloatAnimation OnFinish]

Delphiコード

////
procedure TfmShooting_main.FloatAnimation_Enm_laserbeamFinish(Sender: TObject);
begin
  {画面からフレームアウト後 レーザービーム1を非表示}
  Rectangle_Enm_laserbeam.Visible := False;
end;

C++Builderコード

////
void __fastcall TfmShooting_main::FloatAnimation_Enm_laserbeamFinish(TObject *Sender)

{
	Rectangle_Enm_laserbeam->Visible	= false;
}

 

 


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

https://github.com/mojeld/embarcadero_jp_shooting_game

 

■次回は12月19日(月)17:00より  “シューティングゲーム 敵を攻撃しよう„ をお送りします。

 

 

 

<< 第7回 ‟シューティングゲーム キャラクターを貼り付けよう そして動かそう„  

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



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

Comments

Check out more tips and tricks in this development video: