こんにちは、ともくんです!
この記事は全14回で完成を目指すシリーズ
「初めてのUnityで2Dシューティングゲームを作ってみよう!」
の第7回目となります。
[前回の記事]
【Unity】2Dシューティングゲームの作り方⑥:スクロールと敵の攻撃処理
前回で、いよいよステージが動きだし、敵も攻撃を仕掛けてくるようになりました。
しかし、まだプレイヤーはダメージを受けないので、当たっても痛くもかゆくもありません。
そこで、今回はプレイヤーがダメージを受ける仕組みと、プレイヤーがやられてしまった時に最初からやり直せる「リトライ処理」を作っていきます!
このリトライ処理って、これまでのゲームの作り方と少し違うから「どうやって作るんだ?」って思っちゃいますよね。
実は、SceneManagerというクラス(魔法の機能)を使って、シーンファイルを再読み込みさせてあげることで、リトライ処理を作ることができるんです。
リトライが作れると、これまで一度きりでゲームオーバーだったものが、再挑戦できるようになって楽しくなりますね!
シーンの設定は複雑な部分も多いので、ゆっくりと自分のペースで設定していきましょう!
敵の弾にColliderコンポーネントを付ける
まずは、敵の弾のオブジェクトに当たり判定を付けるため、Colliderコンポーネントを設定していきましょう。
Prefab化してあるEnemyBulletを選択して、インスペクターウィンドウの「Add Component」をクリックします。

Physics 2Dの中の「Circle Collider 2D」を選択します。

Prefabオブジェクトなので、インスペクターウィンドウの上のOpenを押して、オブジェクトの編集を開きます。

操作ツールでColliderの編集ボタンを押して、大きさや範囲をマウスで調整していきます。

Colliderの範囲が決まったら、インスペクターウィンドウのCircle Collider 2Dの項目で、「Is Trigger」にチェックを入れておきます。

これで、敵の弾のオブジェクトにColliderコンポーネントを付けることができました。
なお、Colliderコンポーネントについては以下の記事でも解説していますので、参考にしてみてください。
プレイヤーにColliderとRigidbodyを付ける
次に、プレイヤーのオブジェクトにColliderコンポーネントとRigidbodyコンポーネントを付けていきます。
まず、playerを選択してインスペクターウィンドウの「Add Component」を押して、Physics 2Dから「Polygon Collider 2D」を選択します。

そして、シーンビューのCollider編集ボタンを押して、プレイヤーのオブジェクトに合わせてコライダーの範囲を設定していきます。

範囲の設定が終わったら、先ほどの弾のオブジェクトと同じくPolygon Collider 2Dの項目にある「Is Trigger」にチェックを入れておきます。

次に、Rigidbodyコンポーネントを付けるので、もう一度インスペクターウィンドウの「Add Component」を押して、Physics 2Dから「Rigidbody 2D」を選択します。

Rigidbodyを付けると、重力機能がデフォルトでオンになっているので、Rigidbodyの項目からBody Typeを「Kinematic」に変更しておきます。

これでプレイヤーのオブジェクトに、ColliderコンポーネントとRigidbodyコンポーネントを付けることができました。
なお、RigidbodyコンポーネントやKinematicについては、以下の記事でも解説していますので、参考にしてみてください。
プレイヤーにダメージを与えて消去する処理
それぞれのオブジェクトに当たり判定を付ける設定が完了したので、次はプレイヤーに弾のダメージを与える処理を行っていきます。
今回は、プレイヤーに一度弾が当たったら消去するといった処理にしたいので、HPなどの変数は作らずに書いていきます。
プレイヤーの処理を決めるスクリプトであるPlayerControllerに、以下のスクリプトを書いていきます。
using UnityEngine;
public class PlayerController : MonoBehaviour
{
// ~~~~~ 一部省略 ~~~~~
void OnTriggerEnter2D(Collider2D collision) // 他のオブジェクトとの当たり判定の処理
{
if (collision.gameObject.name == "EnemyBullet" || // 敵の弾に当たった場合
collision.gameObject.tag == "Enemy") // 敵のオブジェクトに触れた場合
{
this.gameObject.SetActive(false); // オブジェクトを消去する
}
}
}8行目で、OnTriggerEnter2Dメソッドを使って当たり判定の処理を書いていきます。
敵のオブジェクトと敵の弾のオブジェクトと当たった時にダメージを与える処理にしたいので、10と11行目でif文を使って敵のオブジェクトと敵の弾のオブジェクトに当たったかどうかを条件指定しています。
そして、当たり判定があった場合は、プレイヤーを消去させるようにしたいので、13行目でSetActive関数を使ってfalseでプレイヤーを非表示にさせています。
これで実際にゲームを実行してみると、

敵の弾に当たるとプレイヤーが消えるという処理を作れました。
敵の弾を破壊する処理
先ほどプレイヤーが倒れる処理を作りましたが、プレイヤーの弾が敵に当たる際の処理と同じく、敵の弾のオブジェクトが当たったら消えるという処理を加えていきます。
敵の弾の処理を作っているのは、EnemyBulletMoveというスクリプトだったので、これに以下のスクリプトを追加していきます。
using UnityEngine;
public class EnemyBulletMove : MonoBehaviour
{
// ~~~~~ 一部省略 ~~~~~
void OnTriggerEnter2D(Collider2D collision) // 他のオブジェクトと当たった場合の処理
{
if (collision.gameObject.name == "player") // オブジェクト名が「player」の場合
{
Destroy(gameObject); // 弾を破壊する処理
}
}
}8行目でOnTriggerEnter2Dメソッドで当たり判定の処理を作り、10行目で当たった相手のオブジェクトが「player」の時にだけ条件を絞っています。
そして、12行目でDestroyメソッドを使い、敵の弾を破壊する処理を作っています。
これでもう一度ゲームを実行してみると、

ちゃんと弾が消えるようになりました。
プレイヤーがいなければ弾を発射しない処理を加える
敵の弾がプレイヤーに当たり、破壊されるようになりましたが、プレイヤーがいなくなった後も敵の弾が発射されてしまっています。
また、プレイヤーがいないことで、プレイヤーの座標取得ができず、弾が移動されないことになってしまっています。
そこで、プレイヤーがいなくなった場合は、敵が弾を発射しないという処理を加えていきたいと思います。
敵が弾を発射する処理を行っているのは、EnemyShootのスクリプトだったので、このスクリプトに対して以下のように変更を加えていきます。
using UnityEngine;
public class EnemyShoot : MonoBehaviour
{
public GameObject enemyBullet; // GameObject型の変数を宣言する
GameObject player; // playerを参照する
float span = 2.0f; // 弾を撃つ間隔を指定
float delta = 2.0f; // 加算用の変数を宣言
void Start()
{
player = GameObject.Find("player"); // playerのオブジェクトを取得する
}
void Update()
{
if (player.activeSelf == true) // playerのステータスが「アクティブ」の場合
{
this.delta += Time.deltaTime; // フレーム間の差をdelta変数に加算している
if (this.delta > this.span) // delta変数がspanで指定した間隔を上回った場合
{
this.delta = 0; // 0に戻す処理
GameObject cloneObject = Instantiate(enemyBullet, this.transform.position, Quaternion.identity); // 弾を表示させて座標を移動させる処理
cloneObject.name = "EnemyBullet"; // Cloneの名前を削除する処理
}
}
}
}
6行目でplayerのオブジェクトを参照する変数を宣言して、Startメソッド内でFind関数を使いplayerのオブジェクトを代入しています。
このFind関数は、
GameObject.Find(引数);と書くことで、引数に設定したオブジェクトを探してくる処理を行ってくれるので、これを使ってオブジェクトを代入しています。
プレイヤーに弾が当たった際は、SetActive関数で非表示にする処理を作っていたので、21行目でactiveSelfを使ってプレイヤーがアクティブかどうかをチェックしています。
activeSelfは、オブジェクトがアクティブかどうかを読み取るためのメソッドとなっていて、アクティブならtrue、非アクティブならfalse、とbool型で値を返してくれます。

これでプレイヤーがいなくなったら、敵が弾を発射しないという処理を作ることができました。
リトライの処理を加える
このままだと、プレイヤーが倒れたままゲームが続いてしまうので、プレイヤーが消去されてしまったらリトライするという処理を作っていきます。
リトライ処理は、あとで別のリトライシーンを作りもう少し処理を加えていくことになるので、ここでは一旦リトライされる処理だけを作っておきます。
リトライの処理を作るのは、「RetryDirector」というスクリプトを作ってその中で処理を行っていきます。
スクリプトを作成し、新しい空オブジェクトにアタッチしておきます。

using UnityEngine;
using UnityEngine.SceneManagement; // LoadSceneメソッドを使うのに必要
public class RetryDirector : MonoBehaviour
{
GameObject player; // playerを参照する
void Start()
{
player = GameObject.Find("player"); // playerのオブジェクトを取得する
}
void Update()
{
if (player.activeSelf == false) // playerのステータスが「非アクティブ」の場合
{
SceneManager.LoadScene("MainScene"); // シーンを読み込んでリトライする
}
}
}先ほどのプレイヤーのアクティブ状態で敵の発射するかしないかを決めたのと同じく、まず6行目と10行目でplayerのオブジェクトを取得しています。
15行目でactiveSelfを使ってplayerが非アクティブ状態の条件指定を作っています。
そして、17行目にリトライされるようにLoadSceneメソッドを使って同じシーンである「MainScene」を読み込む処理を行っています。
LoadSceneメソッドは、引数に指定したシーンを設定しておくことで、そのシーンを読み込むことが出来るメソッドです。
このLoadSceneメソッドは、SceneManagerが管理しているので、2行目でSceneManagerを使用する処理を書いておく必要があります。(バージョンによっては、自動で追加されます。)
実際にゲームを実行して、敵の攻撃を受けてみましょう。

敵の攻撃を受けたらプレイヤーが消去されて、再度始めからシーンが読み込まれて、リトライすることができました。
まとめ
プレイヤーが敵にやられてしまっても、その都度リトライするようになったでしょうか?
これで不死身のプレイヤーの出来上がりです!
今回の大きなポイントは、以下のようになります。
プレイヤーも敵も「動く・撃つ・倒す・やられる」というシューティングゲームの根本を作ることができました!
といっても、もちろんこれで完成ではなく、もっとゲームを盛り上げていく仕組みを作っていきます。
次は、まだ一体しかいない敵を増産したり、敵の種類を増やしてあげて、不死身のプレイヤーを追いつめてやりましょう!
最後までお読みいただきまして、ありがとうございました!













コメント