2019年12月09日

ActiveBasicとDXライブラリでゲームプログラミング!~第14回・シューティングゲームを作ろう!その6

n88_reon.gif
玲音:どうもこんにちは! この講座も、いよいよ今回で最終回! 頑張っていきましょう!

n88_kaede.gif
楓:こんにちは、楓です! だけど、先輩に引きずり込まれて始まったこの講座もいよいよ最後だと思うとさびしいですよね。


n88_reon.gif
だから、引きずり込んだんじゃないってー。さてさて、今回はタイトルやゲームオーバー画面、それにBGMや効果音を入れて、ゲームを完成させていくよ! よろしくね!

~タイトルとゲームオーバー画面を入れよう!

n88_reon.gif
さて。それでは、まずはタイトル画面の処理から入れて行こう! さっそく問題。タイトル画面の処理かどこに書くかな?

n88_kaede.gif
はーい! Titleサブプロシージャです!

n88_reon.gif
はい、正解。さて、ここに書いていくわけだけど、書いていくのは次の処理です。
・タイトル画面を表示する
・スペースキーが押されたら、変数funcにFUNC_PLAYINITを入れて、サブプロシージャPlayInitに処理をうつす

n88_kaede.gif
ふむふむ。

n88_reon.gif
それじゃ、まずはタイトル画像をハンドルに読み込む……前に、Case FUNC_TITLEの下の
func = FUNC_PLAYINIT
を消しておこう。そうしないと、すぐにサブプロシージャPlayInitに進んじゃうからね。

n88_kaede.gif
なるほど!

n88_reon.gif
さて、それが済んだところで、いよいよ処理を作っていこうか。まずはタイトルのハンドル用の変数の定義ね。
''※このほかにも必要な変数があればこの下に追加してください
の行と、
''メイン関数
の行との間に、次の一行を入れてね。

abdx1912-l01.JPG

n88_reon.gif
続いて、MaterialLoadサブプロシージャに、次の一行を追加。

abdx1912-l02.JPG

abdx1912-p01.JPG
▲追加した後のMaterialLoad(赤枠が追加した部分)

n88_reon.gif
そして、Titleサブプロシージャに、次のコードを書いてね。

abdx1912-l03.JPG

n88_reon.gif
プログラムの内容は、さっき話した通り。DX_PAD_INPUT_Mは、スペースキーを表してるよ。

n88_kaede.gif
ふむふむ。

n88_reon.gif
それじゃ続いて、ゲームオーバー処理も作っていこう。まずは、ゲームオーバー画面のハンドル用変数の定義からね。これは、
''※このほかにも必要な変数があればこの下に追加してください
の行と、
''メイン関数
の行との間に書いてね。

abdx1912-l04.JPG

n88_reon.gif
そして、ゲームオーバー画面を読み込む処理。こちらは、MaterialLoadサブプロシージャに。

abdx1912-l05.JPG

abdx1912-p02.JPG
▲ 追加後のMaterialLoadサブプロシージャ(赤枠が追加した部分

n88_reon.gif
そして、肝心のゲームオーバーの処理。これは、GameOverサブプロシージャに書いてね。

abdx1912-l06.JPG

n88_reon.gif
コードはほとんど、タイトル画面と同じ。違うのは、表示させてるのがゲームオーバー画面ということと、変数funcにFUNC_TITLEを入れてるところだけかな。

n88_kaede.gif
なるほどっ。

n88_reon.gif
ついでだから、スコアの処理も入れちゃおう! まず、
''※このほかにも必要な変数があればこの下に追加してください
の行と、
''メイン関数
の行との間に、次の一行を書いてね。

abdx1912-l07.JPG

n88_reon.gif
そして、PlayInitサブプロシージャに次の一行を追加。

abdx1912-l08.JPG

abdx1912-p03.JPG
▲ 追加した後のPlayInitサブプロシージャ(赤枠が追加した部分

n88_reon.gif
続いて、AtariJikiTamaToTekiサブプロシージャにこれを追加。
これは、自機の弾が敵に当たった時に、スコアを加算する処理だよ。

abdx1912-l09.JPG

abdx1912-p04.JPG
▲ 追加した後のAtariJikiTamaToTekiサブプロシージャ
(赤枠が追加した部分)

n88_reon.gif
そして最後に、スコアを表示する処理を作ろう!
処理はサブプロシージャにして、タイトル画面、実際のゲーム中、そしてゲームオーバーのどこからでも見れるようにするよ。

abdx1912-l09b.JPG

n88_reon.gif
そして、このサブプロシージャを呼び出すための次のコードを、Title、GameMain、GameOverの各プロシージャに追加するよ。

abdx1912-l10.JPG

abdx1912-p05.JPG
▲ 追加した後のTitleサブプロシージャ
(赤枠が追加した部分)

abdx1912-p06.JPG
▲ 追加した後のGameMainサブプロシージャ
(赤枠が追加した部分)

abdx1912-p07.JPG
▲追加した後のGameOverサブプロシージャ
(赤枠が追加した部分)

n88_reon.gif
これで出来上がりだよ!

n88_kaede.gif
おー! スコアが表示されてます!

~BGMと効果音を入れよう!

n88_reon.gif
さて。次はBGMと効果音だけど……素材の著作権の問題で、素材のファイルは掲載しません。適当なBGMや効果音を、インターネットからダウンロードしてきて用意してね。
ここでは、BGMのファイル名を、「bgm.mp3」「shot.mp3」「bomb.mp3」として進めていくよ。それぞれ、BGM、ショットの発射音、そして敵の爆発音の素材だよ。

n88_kaede.gif
はーい

n88_reon.gif
まず、DXライブラリでは、画像と同じように、ロードして、そのハンドルを使って再生したりします。
ということで、まず音声ファイルのハンドルを入れる変数の定義からね。
''※このほかにも必要な変数があればこの下に追加してください
の行と、
''メイン関数
の行との間に、次のコードを書いてね。

abdx1912-l11.JPG

n88_reon.gif
次に読み込む処理。MaterialLoadサブプロシージャに追加してね。
音声ファイルを読み込むには、dxLoadSoundMem関数を使うんだよ。

abdx1912-l12.JPG

abdx1912-p08.JPG
▲ 追加した後のMaterialLoadサブプロシージャ
(赤枠が追加した部分)

n88_reon.gif
続いて、BGMを演奏するサブプロシージャ、BGMの演奏を終了するサブプロシージャ、そして効果音を鳴らすサブプロシージャを作ろう。サブプロシージャを呼び出すようにすれば、プログラムがすっきりするからね。

abdx1912-l13.JPG
▲ BGMを演奏するBGMPlayサブプロシージャ、BGMの演奏を終了するBGMStopサブプロシージャ、効果音を鳴らすSEPlayサブプロシージャ

n88_reon.gif
さて、ここで新しくdxPlaySoundMem関数と、dxStopSoundMem関数が出てきたね。これについても説明しちゃおうか。
dxPlaySoundMemは、指定したハンドルの音声ファイルを再生する関数、dxStopSoundMemは、指定したハンドルの音声ファイルの再生を止める関数だよ。それぞれ、このように書くんだ。

dxPlaySoundMem(ハンドルの変数, 再生モード)
dxStopSoundMem(ハンドルの変数)

n88_kaede.gif
この再生モードには、何を入れたらいいんですか?

n88_reon.gif
うん。ここに入れるのは、DX_PLAYTYPE_BACKとDX_PLAYTYPE_LOOPの二つ。もうひとつ、DX_PLAYTYPE_NORMALというのもあるけど、これを使うと再生するたびに処理が止まっちゃうから、あまり使うことはないかな。

n88_reon.gif
さて。前者を入れると、普通に一回だけ再生、後者を入れると、何度でもループ再生するよ。その場合、止めるのはdxStopSoundMem関数を使うの。

n88_kaede.gif
なるほどー。

n88_reon.gif
さて、話を戻すね。サブプロシージャができたら、PlayInitサブプロシージャ、GameOverサブプロシージャ、JikiMoveサブプロシージャ、そしてAtariJikiTamaToTekiを、次のように変更してね。

abdx1912-p09.JPG
▲ 変更後のPlayInitサブプロシージャ。(赤枠が追加した部分)

abdx1912-p10.JPG
▲ 変更後のGameOverサブプロシージャ。(赤枠が追加した部分)

abdx1912-p11.JPG
▲ 変更後のJikiMoveサブプロシージャ。(赤枠が追加した部分)

abdx1912-p12.JPG
▲ 変更後のAtariJikiTamaToTekiサブプロシージャ。(赤枠が追加した部分)

n88_reon.gif
これで出来上がり。実行すると、BGMや効果音付きでゲームが楽しめるよ。

n88_kaede.gif
わー、ほんとだー!


n88_reon.gif
これでも、まだまだ課題は多いよ。今はゲームオーバーの時にスペースキーを押しっぱなしにするとすぐにゲームが始まっちゃうからそれを解消するとか、爆発を表示するとか、ボスキャラを入れるとか色々。そこは自分で、いろいろ工夫してやってみてね。

n88_kaede.gif
はーい。

n88_reon.gif
それでは、この講座はこれでおしまいです!
皆さん、ActiveBasicとDXライブラリで、一杯ゲームプログラミングを楽しんでくださいね!



==========
※次の更新は『師匠Tのチャレンジ・ARSゲーム!』の予定です。お楽しみに!

2019年11月11日

ActiveBasicとDXライブラリでゲームプログラミング!~第13回・シューティングゲームを作ろう!その5

n88_reon.gif
玲音:こんにちは! 玲音です! ……あれ? 楓ちゃん、何か書いてるの?

n88_kaede.gif
楓:な、なんでもありませんよ! 見ないでくださいっ。

n88_reon.gif
なになに……。「きょうもかえでは、せんぱいにこうざにひきずりこまれました」
もう、楓ちゃんったら~。

n88_kaede.gif
えへへ……。それで先輩。確か今回は、当たり判定をするんでしたよね?

n88_reon.gif
うん、そうだよ。今回は、自機の弾と敵、自機と敵、自機と敵の弾の当たり判定を作って、当たった時に敵が消えたり、ゲームオーバーになったりする処理をやっていくよ。それじゃ、さっそく初めてみよう!

~関数を作ろう!

n88_reon.gif
それじゃ、まずはモノとモノとの当たり判定を行う関数を作っていこう!

n88_kaede.gif
関数、ですか?

n88_reon.gif
うん。そしてこの関数を、それぞれ(自機の弾と敵の時、自機と敵の時、自機と敵の弾の時)で使いまわすようにしていくんだ。そうすれば、処理がシンプルになるでしょ?

abdx1911-g01a.jpg

abdx1911-g01b.jpg

n88_kaede.gif
なるほどっ。さすが、私のこの講座に引きずり込んだ先輩ですっ。

n88_reon.gif
だから、引きずり込んだんじゃないってばぁ……。こほん、それじゃ続いて、当たり判定の考え方ね。
まずはこの図をみて。

abdx1911-g02.jpg

n88_reon.gif
これが当たっている状態ね。これを見て、何か気づかないかな?

n88_kaede.gif
あっ! 当たっている状態というのは、中心同士の距離が、二つのものの幅の半分の合計より小さい状態なんですね!

n88_reon.gif
そういうこと。こうなっているかどうか判定して、条件が成立したら、当たっているという判定を返せばいいんだよ。というわけで、それを関数にしたものがこちらです!

abdx1911-l01.jpg

n88_reon.gif
まず、p〇1とついているのは物体(自機や弾、敵など)1の位置や大きさの情報。p〇2とついてるのは物体2の情報だよ。
そして、まず12行目から16行目まで(赤枠の部分)では、各物体の中心の位置を計算しているよ。
そして18行目からがいよいよ本番。中心の間の距離と、幅(高さ)の半分の合計を計算し(青枠の部分)、そしてこれを比べて、当たっていれば、1を返し、そうでなければ0を返すようにしてるんだ(緑枠の部分)。

n88_kaede.gif
なるほどー。あ、先輩、このAbsっていうのはなんなんですか?

n88_reon.gif
うん。それは、引数の絶対値を返す関数だよ。簡単に言うと、値のマイナスを取って返してくれるもの。

n88_reon.gif
これを使わないと、比較するために、値が正の数かどうかチェックして、負の数だったら正の数に直す手間がかかるからね。

n88_kaede.gif
なるほどー。

n88_reon.gif
さて、それじゃ、次はこの関数を使って行こう!

~関数を使おう!

n88_reon.gif
まずは、自機の弾と敵との当たり判定ね。考え方は簡単。全ての自機弾と敵のデータをチェックして、双方ともある組み合わせの時のみ、判定の関数を呼び出して判定する、という形。というわけで、そのためのサブプロシージャがこちら!

abdx1911-l02.JPG

n88_reon.gif
続いて、自機と敵、自機と敵の弾の当たり判定だよ。こちらも考え方は、さっきと同じ。ただ、自機は一機しかいないし、自機に当たったらゲームオーバー画面に行くので、自機があるかどうかの判定はしてないところが違うの。

abdx1911-l03.JPG

abdx1911-l04.JPG

n88_reon.gif
これができたところで、これらの関数をGameMainサブプロシージャに組み込もうか。次のコードをGameMainサブプロシージャに付け加えてね。

abdx1911-l05.JPG

abdx1911-l06.jpg
↑書き直した後のGameMainがこちら。(赤枠が追加した部分です)

n88_reon.gif
なお今回は、ゲームオーバーの処理は作ってないから、敵や弾に当たったら画面が黒くなるだけになってる。そこらへんは次回にやっていくよ。では実行してみよう!




n88_kaede.gif
おー! こちらの弾で敵を倒せたり、弾や敵に当たったら画面が黒くなるようになりましたよ!

n88_reon.gif
それでは今回はここまで。次回はいよいよラスト。スコアをいれたり、タイトルやゲームオーバー画面を入れたり、BGMを入れたりしていくよ。よろしくね!

==========

※次の更新は、『師匠TのチャレンジARSゲーム』の予定です。お楽しみに!

2019年10月14日

ActiveBasicとDXライブラリでゲームプログラミング!~第12回・シューティングゲームを作ろう!その4

n88_reon.gif
玲音:こんにちは! 玲音です!

n88_kaede.gif
楓:こんにちは! 気づいたら、この講座に引きずり込まれてた、玲音先輩の後輩の楓です!
今月もよろしくお願いします!

n88_reon.gif
あ、言われちゃった。しまったなぁ。だから、引きずり込んだんじゃないってばぁ……。

n88_kaede.gif
えへへ、それで先輩。今回は、弾の発射処理を作るんでしたよね?


n88_reon.gif
うん。その通り。今回は、弾の発射角度の計算から、そこから弾の移動量を計算する処理、そして実際の弾の移動をやっていくよ。張り切っていこう!

n88_kaede.gif
はーい!


~まずするべきことは?

n88_reon.gif
さてさて。弾の処理を作る前にするべきことがあります。それはなんでしょう?

n88_kaede.gif
はーい! 弾の変数を用意して初期化し、そして弾の画像を読み込んでおくことでーす!

n88_reon.gif
それでは、まずは弾の変数の定義からやっていこうー!
''メイン関数 の前あたりに、次の文を書いてね。

abdx1910c01.JPG

n88_kaede.gif
新しい配列変数、bVX()とbVY()が登場しましたね。これはどんな役割をする変数なんですか?

n88_reon.gif
うん。この二つは、弾の移動量を保存しておく変数だよ。bVX()がX(横)方向、bVY()がY(縦)方向。この分だけ、弾を動かすようにするんだ。

n88_kaede.gif
なるほどー。

n88_reon.gif
bFlag()はその弾が存在しているかどうかを表す変数、bX()、bY()が位置を表す変数だよ。

n88_kaede.gif
hnbBalletは、弾の画像のハンドルが入る変数ですよね。

n88_reon.gif
その通り。そして、BALLETSは弾の数を表す定数だよ。では続いて、弾の初期化をする関数を作っていこう!
こちらだよ。

abdx1910c02.JPG

n88_kaede.gif
そんなに難しくないですね。

n88_reon.gif
そうだね。For~Nextで回して、配列変数bFlag()に0を入れてるだけだからね。
あ、そうだ。敵キャラの情報を初期化するサブプロシージャも作らないとね。こちらだよ。

abdx1910c03.JPG

n88_reon.gif
では、これらを呼び出す命令も入れていこう。サブプロシージャStageInitの中にこれを書いてね。

abdx1910c04.JPG

abdx1910l01.JPG
↑入れた後のStageInitはこうなります。(赤枠が追加した文)

n88_reon.gif

続いて、画像を読み込む部分も書いていこうか。サブプロシージャMaterialLoadにこれを追加して。


abdx1910c05.JPG

abdx1910l02.JPG
↑入れた後のMaterialLoadはこうなります。(赤枠が追加した文)

n88_reon.gif
さて、ここまでできたら準備はOK! いよいよ本番だよ!

n88_kaede.gif
はーい!


~弾を作るために必要なものは?

n88_reon.gif
さて、弾を作る処理を作る前に、一つ作らなければならない処理があります。それはなんでしょう?

n88_kaede.gif
うーん、なんでしょうか? わからないですー。

n88_reon.gif
くすくす。それは、弾を撃つ敵機と自機との角度を求めることと、その角度を元に移動量を計算することでーす。
ということで、まずは角度を計算する関数を作ろう。まずは、次のファイルをダウンロードして、解凍したAtan2.dllをプログラムのフォルダに入れてね。


n88_reon.gif
それが済んだら、次の行をプログラムの一行目に追加してください。

abdx1910c06.JPG

n88_reon.gif
それができたら、いよいよ関数を作っていきましょう! こちらです!

abdx1910c07.JPG

n88_reon.gif
まず、最初に追加したDeclareから始まる文は、ActiveBasicに、Atan2.Dllの中に入っている_Atan2という関数を使いますよ、と教えている文だよ。これを書くことによって、この関数を使えるようになるの。

n88_kaede.gif
ふむふむ。

n88_reon.gif
そして関数の中身だけど、ちょっと難しいから細かいことは省略するね。やっていることは、自機と敵機の間の角度を求めている、というもの。なお、求めているのは普通の角度ではなくてラジアンだよ。

n88_kaede.gif
ラジアン?

n88_reon.gif
ラジアンというのは、(180÷π)度を1ラジアンとする、特別な角度の単位で、コンピュータの世界ではよく使われるんだよ。さて、続いて、弾を作る処理をやっていこうか。まずは、空いている弾を探す関数ね。

abdx1910c08.JPG

n88_reon.gif
これについて難しくないよね。今までやってきたのと同じだから。

n88_kaede.gif
はいっ。

n88_reon.gif
それでは続いて、弾を作る処理です!

abdx1910c09.JPG

n88_reon.gif
ここは、基本的には、敵やショットを作るときと同じ。弾の位置を決める方法が違うのと、移動量を決めているのが違いだね。

n88_kaede.gif
弾の位置を決める時には、どうして16を足して、5を引く、というようなことをしてるんですか?

n88_reon.gif
それは、弾の初期位置が敵の中心にしているのと、そしてdxDrawGraphを使うとき、指定するのは画像の左上隅の座標だからだよ。敵の画像サイズは32×32だから、その半分の16を足して、敵の中心の位置を計算して、そこから弾のサイズの10の半分である5を引いて、弾の左上の座標を計算してるんだ。
Angle関数の中で、敵の位置に16を足しているのも同じ理由だし、自機の位置に数値を足してるのも同じ。

n88_kaede.gif
なるほどー。

n88_reon.gif
さて、そしたら後は弾の処理だね。まずは弾の移動!

abdx1910c10.JPG

n88_reon.gif
弾は、いろんな方向に飛ぶから、ここでは上下左右について、画面外に出たかどうかをチェックしているよ。そして出たら弾を消している、と。では続いて、弾の描画処理です!

abdx1910c11.JPG

n88_reon.gif
そして、これらの処理を呼び出すBalletMainサブプロシージャです!

abdx1910c12.JPG

n88_reon.gif
そして、弾を発射するコードを、MoveEnemyサブプロシージャ内に書きましょう!
配列関数eTimeCnt()を1ずつ増やしていき、eFireTime()と同じ値になったら、BalletCreateサブプロシージャを呼び出して、eTimeCnt()を0にする、ということをしているよ。

abdx1910c13.JPG
↑処理を追加した後のMoveEnemyはこうなります。(赤枠が追加した部分)

n88_reon.gif
そして、後は、GameMainサブプロシージャに次の一行を書き加えればOKだよ。できたら実行してみてね。

abdx1910c14.JPG

abdx1910l03.JPG
↑入れた後のGameMainはこうなります。(赤枠が追加した文)

n88_kaede.gif
おー! 敵が弾を撃ってくるようになりましたよ!




n88_reon.gif
それでは、今回はここまで。次回は自機と敵、自機と敵弾、敵とショットの当たり判定を作っていくよ! また次回!

n88_reon.gif
そうそう、今回から、その回までのソースファイルを公開することにしたよ。こちらからダウンロードしてね!


==========

※次の更新は、『師匠TのチャレンジARSゲーム!』の予定です。お楽しみに!

2019年09月09日

ActiveBasicとDXライブラリでゲームプログラミング!~第11回・シューティングゲームを作ろう!その3

n88_reon.gif
玲音:どうも玲音です! さてさて、楓ちゃんに変なこと言われる前に、講座を始めていきましょう!
今回は、敵の表示と移動について説明していきますよ!

n88_kaede.gif
楓:先手打たれちゃったー。どうも、楓です。今日もよろしくお願いしますっ。

n88_reon.gif
ふふん、私だって、いつもやられてばかりじゃないよー。それじゃ初めていきましょう!


~敵に必要な変数は?~

n88_reon.gif
さて、まずは敵の移動や表示に関係する変数の定義から始めていこうか。
''メイン関数 の前のあたりに、次のコードを書いてね。

abdx1909-c01.JPG

n88_kaede.gif
あの、先輩。このeFlagって配列変数はなんですか?

n88_reon.gif
うん。それは、その番号の敵が出現しているかどうかを表すフラグだよ。これが1になってる敵だけを表示、移動させるようにするんだ。

n88_kaede.gif
なるほどー。

n88_reon.gif
それと、eFireTimeは、出現してから弾を発射するまでの時間。eTimeCntは出現してから経過した時間だよ。
eTimeCntがeFireTimeと同じになったら、弾を発射するようにする予定。

~敵を作ろう!~

n88_reon.gif
さて。それでは、まずは敵を出現させる処理から作っていこうか。でもその前に一つやっておかなくちゃならないことがあるの。わかる?

n88_kaede.gif
しなくちゃならないこと? うーん……。

n88_reon.gif
それは、まだ使われていない番号を探すこと。使われている番号を使ってしまうと、移動中の敵が、突然別のところに出現した!ってことになっちゃうでしょ?

n88_kaede.gif
あぁ、なるほどっ。

n88_reon.gif
ということでさっそく、使われていない敵の番号を探す関数、FindEmptyEnemyを作りましょう。これですっ!

abdx1909-c02.JPG

n88_reon.gif
といっても、やってることは前回作ったGetShotIDと同じだけどね。

n88_kaede.gif
ふむふむ。これを使って、見つけた番号に敵を作っていくわけですね!

n88_reon.gif
うん、その通り。それでは改めて、敵を作るサブプロシージャ『CreateEnemy』を作っていきましょう! とはいっても、やってることはCreateShotとほぼ同じだけどね。

abdx1909-c03.JPG

n88_reon.gif
出現するX座標と弾を発射するまでの間隔は、乱数(でたらめな数)で決めてるよ。dxGetRand関数は、0から()の中までの乱数を返すものだってことは、前の講座で話したよね。

n88_kaede.gif
はいっ。

n88_reon.gif
13行目の

eFireTime(id) = 40 + dxGetRand(20)

にも注目。
このような書き方をすることで、例えばこの例だと40から60までの乱数を取り出すことができるよ。

n88_kaede.gif
なるほどー。

n88_reon.gif
さて、次は移動と表示の処理も作っていこうか。と言っても、することは難しくないよ。For~Nextのループで敵の番号を回して、eFlagが1のものだけを移動、そして表示させてるだけ。そして移動の結果、敵が画面外に出たら、eFlagを0に戻してる、と。

n88_kaede.gif
ふむふむ。

n88_reon.gif
では、まずは画像の読み込みからやっていこうか。
サブプロシージャMaterialLoadに、次のコードを書いてね。

abdx1909-c04.JPG

abdx1909-r01.JPG
↑追加後のMaterialLoadはこうなります。(赤枠で囲まれたのが追加したところ)

n88_reon.gif
続いて、敵の移動を処理するサブプロシージャMoveEnemyだよ。

abdx1909-c05.JPG

n88_reon.gif
そして、こちらが敵の描画を処理するサブプロシージャDrawEnemy。やっているのが移動か描画の違いだけで、ほとんど、MoveEnemyと同じだけどね。

abdx1909-c06.JPG
n88_reon.gif
そして、この二つのサブプロシージャを実行し、さらに敵の出現の制御を行う、いわば上記二つのサブプロシージャの親玉というべきサブプロシージャ、EnemyMainだよ。

abdx1909-c07.JPG
n88_reon.gif
ここでは、MoveEnemyとDrawEnemyを呼び出す他にも、totalTimeをカウントアップして、30の倍数になるごとに、CreateEnemyを呼び出して敵を作ることもやっているよ。Mod演算子は、割った余りを計算する演算子なんだけど、このように使えば、一定の値ごとに処理を呼び出す処理を作ることができるんだ。

n88_kaede.gif
なるほどー。

n88_reon.gif
さて、ではこのEnemyMainサブプロシージャを、GameMainの中に組み込もう! GameMainの中に、次のコードを付け加えてね。

abdx1909-c08.JPG

abdx1909-r02.JPG
↑付け加えた後のGameMain。(赤枠内が追加されたコード)

n88_reon.gif
できたら実行してみて。

n88_kaede.gif
はーい。おおっ! 画面の上から敵キャラが下に移動していきますっ!

n88_reon.gif
では今回はここまで。次回は、弾を撃つ処理をやっていくよ。よろしくね!

==========

※次の更新は、『師匠TのチャレンジARSゲーム!』の予定です。お楽しみに!

2019年08月12日

ActiveBasicとDXライブラリでゲームプログラミング!~第10回・シューティングゲームを作ろう!その2

n88_reon.gif
玲音:どうもこんにちは! B-Maga編集部の紅一点・玲音です!

n88_kaede.gif
楓:こんにちは! その玲音先輩に講座に引きずり込まれた、後輩の楓です!

n88_reon.gif
だから、引きずり込んだんじゃないってばぁ……。
さてさて、シューティング編第2回は、自機の移動と、弾の発射をやっていきますよー。

n88_kaede.gif
はーいっ。

~その前に……

n88_reon.gif
その前に……ごめんなさいっ。
前回説明した準備と、プログラムについて、いくつか間違いがありましたので、訂正させていただきますっ。

n88_kaede.gif
まず準備についてですが、画像を入れる他に、することがあったのでした。下のファイルをダウンロードして、解凍してできた二つのファイルを、プロジェクトのフォルダにコピーしてください。


n88_kaede.gif
なお、このファイルは、配布元のサイト様が閉鎖されてしまったので、やむを得ずこちらで代理公開させていただいてます。ご了承ください。

n88_reon.gif
さて、それができたら、元型のプログラムの一行目を次のように直してくださいね。

(旧)
#include "../DxLib.sbp"

(新)
#include "./DxLib.sbp"

n88_reon.gif
これができればOKですよ。この説明が抜けていたこと、改めて謝罪させていただきます。申し訳ありませんっ。

n88_kaede.gif
さて、それでは本題にいきましょうー。

~キャラを表示させてみよう

n88_reon.gif
さて。それでは、まずは自機のキャラを表示させてみようか。
まずは……

''※このほかにも必要な変数があればこの下に追加してください

n88_reon.gif
この行の下に、次の一行を追加してね。

abdx1908-l01.JPG

n88_kaede.gif
自機キャラのグラフィックのハンドルを入れる変数を用意してるんですよねっ。

n88_reon.gif
その通り。その下のpX、pYは自機の座標を入れる変数だよ。
では、そのグラフィックを読み込む処理を書いていこうっ。サブプロシージャMaterialLoadに、次の一行を書いてね。

abdx1908-l02.JPG

n88_reon.gif
そしてそれが済んだら、新しい関数、JikiDraw()を作りましょう。内容はこの通りだよ。

abdx1908-l03.JPG

n88_kaede.gif
(変数pX, 変数pY)の位置に、自機を表示させてるんですね。あっ、先輩、でもまだpXとpYの値を決めてませんよ?

n88_reon.gif
あっ、そうだったね。それじゃ、サブプロシージャPlayInitに次の行を書き加えよう。

abdx1908-l04.JPG

n88_reon.gif
さて、ここで元型にもともと備わってる定数について説明するね。
SCREEN_XとSCREEN_Yは、ゲーム画面の右上の座標だよ。

n88_kaede.gif
どうして、(0, 0)に固定しないんですか?

n88_reon.gif
それは、ゲームによっては画面を全部使わずに、画面の中央あたりにゲームの画面を置いて、その外にスコアなどの情報を置く場合があるからだよ。そういう画面構成にすることも考えて、画面左上の位置も変えられるようにしてあるんだよ。

n88_kaede.gif
なるほどー。

n88_reon.gif
それと、SCREEN_WとSCREEN_Hは、ゲーム画面の幅と高さを表す定数だよ。

n88_kaede.gif
なるほどっ。

n88_reon.gif
それじゃ後は、サブプロシージャGameMainに、さっき作ったJikiDrawを呼び出すコードを書きましょう。このコードを書いてね。

abdx1908-l05.JPG

n88_kaede.gif
できましたーっ。……あれ? 先輩。実行しても、何も起こりませんよ?

n88_reon.gif
え? あっ……! ごめんごめん。臨時的に、Title()と書かれた行の下に、次の命令を書いてくれるかな?

abdx1908-l06.JPG

n88_reon.gif
元型では、タイトル画面でスペースキーを押してゲームスタートする前提になっているので、この行が抜けていたの。もちろん今回も、タイトル画面の処理をいれたら、この行は消すからね。

n88_kaede.gif
はーい。

n88_reon.gif
それじゃ続いて、このキャラクターを移動させよう!

~自機を動かそう!

n88_reon.gif
ではまず、自機を動かすためのサブプロシージャを作ろう。名前はJikiMoveにしておこう。

abdx1908-l07a.JPG
abdx1908-l07b.JPG

n88_reon.gif
それができたら、サブプロシージャGameMainに、JikiMoveを呼び出すコードを書き加えましょう。JikiDraw()の前に、次の行を書き加えるんだよ。

abdx1908-l08.JPG

n88_reon.gif
ここまでできたら、実行してみてね。

n88_kaede.gif
おぉっ! 自機がカーソルキーで動かせますよ!

n88_reon.gif
このサブプロシージャの前半部分(赤枠の部分)は説明しなくてもいいよね。押されたカーソルキーによって、位置を表す変数の値を変えているだけ。ここのコツは後半部分(青枠の部分)だよ。

n88_kaede.gif
前半部と同じく、IF文がたくさん並んでますね。ここでは何をしてるんですか?

n88_reon.gif
ここでは、キャラクターがゲーム画面をはみ出ていないかをチェックして、もしはみ出ていたらはみ出ないように位置を修正しているんだよ。具体的には、X位置が画面の幅の範囲を超えていないか、Y位置が画面の高さの範囲を超えていないかをチェックしてるの。

abdx1908-z01.jpg

n88_kaede.gif
なるほどー。

n88_reon.gif
さて、次は弾を発射させるよ!

~弾を発射しよう!

n88_reon.gif
さて、次は弾を発射するわけだけど、弾には位置だけでなく、存在しているかどうかのフラグが必要になるよね。

n88_kaede.gif
あ、そうですね。

n88_reon.gif
その考えをさらに進めて、存在しているフラグの立っている弾だけ移動させて、表示させるようにしようと思います。そして、発射ボタンを押した時に、フラグが立っていない弾のフラグを立てて、弾が画面外に出たか敵に当たった時にフラグを倒す、と。

n88_kaede.gif
なるほどー。

n88_reon.gif
それでは、まずは弾の情報からだね。

''※このほかにも必要な変数があればこの下に追加してください

n88_reon.gif
この行の下あたりに、次の行を追加してね。

abdx1908-l09.JPG

abdx1908-r01.JPG
▲ 入れた後はこうなります(青枠が追加した部分です)

n88_kaede.gif
hndShotは、弾の画像のハンドルが入る変数ですよね。

n88_reon.gif
うん、そうだよ。そして、ShotFlag、ShotX、ShotYはそれぞれ、フラグ、X座標、Y座標を入れる配列変数ね。ではまずは、画像をロードする処理を書こうか。このコードを、サブプロシージャMaterialLoadに書いてね。

abdx1908-l10.JPG

abdx1908-r02.JPG
▲ 入れた後のMaterialLoad(枠が追加した部分です)

n88_reon.gif
ここは難しいところはないよね。それじゃ続いて、フラグを全部0にするサブプロシージャも作っておくよ。
こちらです!

abdx1908-l11.JPG

n88_reon.gif
できたら続いて、サブプロシージャStageInitに、今のサブプロシージャを呼び出すコードを書いてね。

abdx1908-l12.JPG

n88_kaede.gif
あの、先輩。どうしてこんなことをするんですか?

n88_reon.gif
やられたりした後、ゲームをやり直す時のことを考えてみて。弾を消さないでおくと、再会した時に、前のプレイの時の弾が残っちゃうでしょ?

n88_kaede.gif
あぁ、なるほどー。

n88_reon.gif
さて、次に、弾を移動させ、表示するサブプロシージャを作りましょう。こちらです!

abdx1908-l13.JPG

n88_reon.gif
やっていることは難しくないよ。まず、4行目と17行目のForとNextで、弾の数だけ繰り返し、もしチェックする弾のフラグが1だったら、7行目でその弾を上に移動。9~11行目では、もし弾が画面の上端を超えたら、フラグを0に戻してます。そしてその後再び、フラグが1だったら、弾を表示する、ということを13~15行目でやっています。

n88_kaede.gif
なるほどっ。

n88_reon.gif
では、このサブプロシージャを呼び出すコードを、GameMainに書き加えましょう。

abdx1908-l14.JPG

abdx1908-r03.JPG
▲ 入れた後のGameMain(枠が追加した部分です)

n88_reon.gif
最後は、弾を発射する処理だね。まずは、存在していない弾の番号を取得する関数を作りましょう。こちらです!

abdx1908-l15.JPG

n88_reon.gif
やってることは難しくないよ。ただ、フラグが0になっている(つまり存在していない)弾の番号を変数に入れて、その変数の値を返しているだけ。全部埋まっているときは-1を返しているよ。

n88_kaede.gif
ふむふむ。

n88_reon.gif
では続いて、弾を作る処理も作っちゃいましょう。これもやっていることは難しくないよ。さっきの関数から番号を受け取り、その番号のフラグを1にして、位置をセットしているだけ。位置は、ちょうど横位置が自機の中間地点、そして縦位置がちょうど自機の真上になるようにしているよ。

abdx1908-l16.JPG

n88_reon.gif
さて。最後に、ボタンを押したらショットを発射する処理だけど、ここはちょっと面倒。まずは、

''※このほかにも必要な変数があればこの下に追加してください

n88_reon.gif
の行の下のところに、次の文を書いてね。

abdx1908-l17.JPG

abdx1908-r04.JPG
▲ 入れた後はこうなります。(青枠の部分が追加したところです)

n88_reon.gif
そして次に、サブプロシージャJikiMoveの一番後ろあたりに、このコードをいれます。

abdx1908-l18.JPG

abdx1908-r05a.JPG
abdx1908-r05b.JPG
▲ 入れた後のJikiMoveはこうなります。(枠の部分が追加したところです)


n88_reon.gif
ここでは、発射ボタンを押してる間、カウンタの変数を加算していって、その値が、定数RAPIDの数ごとに、CreateShot()を呼び出して、弾を発射してるんだよ。

n88_kaede.gif
先輩。どうしてそんなことを?

n88_reon.gif
このようにしないと、押している間、弾が途切れなく発射されて、一本の線みたいになっちゃうんだ。だから、一定間隔ごとに発射するようにしているんだよ。

n88_kaede.gif
なるほどー。

n88_reon.gif
ここでのポイントは、2行目と4行目だよ。まず2行目は、このようにmod演算子(余りを計算する演算子)を使うことで、0~ある数を繰り返すようになるんだよ。

n88_kaede.gif
ふむふむ。

n88_reon.gif
そして4行目。このようにすることで、一定数ごとに処理をすることができるんだよ。例えば今回の例だと、RAPIDの値、つまり10の倍数になるごとにCreateShotを呼び出すことになってるんだね。

n88_kaede.gif
なるほどー。とてもためになるテクニックです!


n88_reon.gif
さて。長くなったけど、今回はここまでっ。次回は、敵の移動の処理を作っちゃいますよ! それでは……。

n88_kaede.gif
また次回~!

==========

※次の更新は、『師匠TのチャレンジARSゲーム!』の予定です。お楽しみに!