Unityで作る「シューティングゲーム」前回はデブリを作り、乱数で発生させるプログラムを作成しました。今回はこのデブリに当たったら、また前々回作った隕石にぶつかったら、プレイヤーがダメージを受ける、という動きを作ってみます。
では早速作っていきましょう!
Step:1 デブリ、隕石の修正と確認
プレイヤーがデブリ、または隕石と衝突した際、何らかのイベントをさせるためには、互いに「Collider」というコンポーネントを持っている必要があります。現在、隕石とデブリには「CircleCollider2D」「BoxCollider」というコンポーネントをつけていますね?
さらにこの「Collider」ですが、衝突判定と侵入判定をさせてあげることができます。衝突判定は文字通り、2つ以上のオブジェクト同士が衝突する際に信号を出力、衝突後は互いの動きに影響を与えます。
一方侵入判定は互いは物理的な影響を受けることはなく、オブジェクトの指定した領域に侵入したときに信号を出力するものです。Colliderコンポーネントの「IsTrigger」というパラメーターにチェックを入れることでこれが実現します。
では「Collider」をもったオブジェクトが複数あった時、特定の種類のオブジェクトのみに当たり判定をさせるにはどうすればよいでしょうか?この実現には「Tag」というものを活用します。説明が長くなりましたが、今回はこの「Tag」を使って衝突判定を行います。
①まずは「隕石」ですが、Inspector の確認を行います。
Tagに「Asteroid」が設定されてある。
「CircleCollider」の「IsTrigger」のチェックが外れいている(=衝突判定)
この2点を確認します。
いん石のスクリプトファイルですが、出現するタイミングが若干遅いようです。隕石が画面途中に突如出現するような動きになっていますね?出現時のY座標を修正しておきましょう。隕石の生成を管理しているのは「GameMangager」です。
「GameMangager.cs 」の 隕石生成の関数 void CriateAsteroid() の生成時のY座標の値を 20f に変更します。下のコードの赤文字の部分です。
void CriateAsteroid() //隕石生成
{
GameObject asteroid = Instantiate(asteroidPrefab);
asteroid.transform.position = new Vector3(Random.Range(-20, 20), 20f, 0);
}
さらに隕石のプレイヤーと衝突したときに爆発するように修正します。まずは Asteroid.csに以下のコードを追加しましょう。
この関数は、プレイヤーが隕石と衝突した際に、プレイヤー側から呼び出したいと思います。ということで、関数のアクセス修飾子には「public」を指定しておきます。
public void DestroyAsteroid() //隕石の爆発関数
{
Destroy(gameObject); //消滅
Instantiate(explosion, transform.position, Quaternion.identity); //爆発の生成
}
続いてデブリですが、現在Tagが デフォルト値 になっています。
②Tagに「Enemy」をセットします。作っていない場合は新たに作成しセットしましょう。
こちらは侵入判定で検知したいと思います。「BoxCollider」の「IsTrigger」にチェックが入っているのを確認しましょう。
デブリのプログラムですが、出現場所は問題ないのですが、クローンによっては途中で消滅してしまうようです。消えるまでの時間を調整します。
現状、Start()関数 に、
Destroy(gameObject,3f);
生成後3秒後に削除、というコードを記述していますが、これを削除します。
さらに Update()関数 に、Y座標が-15 を下回ったら削除、というコードを追加します。
Debris.cs を開いて、以下のコードを追加、修正します。
void Start()
{
debRenderer = GetComponent<SpriteRenderer>(); //記述済み
debRenderer.sprite = sprites[Random.Range(0, 6)]; //記述済み
GetComponent<Rigidbody2D>().velocity = new Vector2(Random.Range(-15, 15), Random.Range(-10, -2)); //記述済み
//Destroy(gameObject,3f); //削除
}
void Update()
{
if (transform.position.y < -15f)
{
Destroy(gameObject); //Y座標が-15を下回ったら削除
}
}
これで隕石とデブリの修正は完了です。
Step:2 プレイヤーのHP管理
まずはプレイヤーに変数「HP」を持たせ、初期値を10に指定します。
さらにPlayerの爆発演出も行いますので、爆発のプレハブを持たせる準備をします。
[SerializeField] GameObject Explosion; を記述
[SerializeField] GameObject Explosion; //爆発エフェクト
public int hp; //Player のHP
void Destroy() //消滅させる関数を作成
{
Instantiate(Explosion, transform.position, Quaternion.identity); //爆発生成
Destroy(gameObject); //消滅
}
void Start()
{
shot_speed = 800; //記述済み
playerRb2d = GetComponent<Rigidbody2D>(); //記述済み
transform.position = new Vector3(0, -5, 0); //記述済み
hp = 10; //HPの初期値を10に指定
}
void OnTriggerEnter2D(Collider2D collision) //侵入判定
{
if(collision.tag== "Enemy") //対象のタグが"Enemy"なら
{
hp--; //hpを1ずつ減らす
if (hp <= 0) Destroy(); //hpが0以下のときDestroy()関数発動
}
}
void OnCollisionEnter2D(Collision2D collision) //衝突判定
{
if (collision.gameObject.tag == "Asteroid") //対象のタグが"Asteroid"なら
{
hp-=2; //hpを2ずつ減らす
//衝突したオブジェクトからAsteroidクラスを取得、DestroyAsteroid() を発動
collision.gameObject.GetComponent<Asteroid>().DestroyAsteroid();
if (hp <= 0) Destroy(); //hpが0以下のときDestroy()関数発動
}
}
void Destroy()関数ではPlayer自身の爆発と消滅を指定しています。都度爆発と消滅を記述してもいいのですが、複数個所で使用する場合は、関数にしてしまった方が楽ですね?
Instantiate(Explosion, transform.position, Quaternion.identity);
Instantiate(第一引数:何を,第二引数:どこに,第三引数:向き)
Instantiate() 関数では第一引数に指定したオブジェクトを生成します。今回は爆発のプレハブを指定しています。同じエフェクトを使いまわしていますが、別のものを使ってもいいでしょう。各自好きなエフェクトをアセットストアから取得して指定してみてください。
第二引数の生成場所には自分の場所を指定しています。
第三引数の Quaternion.identity は「回転しない」という意味でしたね?
void OnTriggerEnter2D(Collider2D collision) は侵入判定です。
カッコの中は引数で、Collider2D型 の変数 collision には衝突した対象が渡されます。
if(collision.tag == "Enemy")
ifの中の collision には自分が侵入した対象が入ります。
"==" は比較演算子で「同じ」という意味を持ちます。ちなみに"=" イコールが一つだけだと、「代入」という意味になりますよね?
合わせると、侵入した対象が持っている Tag が"Enemy"ならという意味になります。
hp--;
"--" はデクリメント といいます。hp=hp-1 と同じ意味です。
侵入するたびにhpを1ずつ減らす、という意味になります。
if (hp <= 0) Destroy();
もしhpが0以下になったら、作成済みのDestroy()関数を呼び出す、という意味です。
void OnCollisionEnter2D(Collision2D collision) は衝突判定です。
先に説明したOnTriggerEnter2Dと基本の部分は同じになります。
if (collision.gameObject.tag == "Asteroid")
衝突した対象のゲームオブジェクトのタグが"Asteroid"なら、という意味です。
今回はTrigger でなく、オブジェクトなので、gameObject.と指定する必要があります。
先ほどと若干違いますので気を付けてください。
hp-=2;
hp = hp - 2 という意味になります。
わかりにくいかもしれませんが、hp という文字を1回しか書かなくても良いので楽です。
collision.gameObject.GetComponent<Asteroid>().DestroyAsteroid();
これが「オブジェクト指向」の入り口です。「PlayerController」というクラスから、別のクラス「Asteroid」の関数を起動させています。別クラスを参照する方法はいくつかありますが、まずはそのクラスを探し出すこと。今回は衝突したゲームオブジェクトが持っているスクリプトファイルがそのクラスだったので見つけることができました。
衝突した対象からGetComponent<Asteroid>() でスクリプトファイルを取得、その中のDestroyAsteroid()関数 を呼び出しました。
最後の部分、ちょっと難しいですよね?
説明が長くなりましたが、これでスクリプト部分は完成です。
最後はプレイヤーのインスペクターから、PlayerControllerの「Explosion」にExplosionプレハブを指定してあげましょう。
これで動かしてみてください。
大量のデブリがプレイヤーのマシンに衝突、10回当たるとプレイヤーは消滅すると思います。
hp が減少していくのがわかりにくいという場合は、hp が変化するタイミングでdebug()関数を発動させるのもいいかもしれませんね?
hp--; //この後に
Debug.Log(hp);
これでコンソールにhpの値が表示されると思います。
教室では実際に通って頂いての授業の他、Unityのオンライン授業やオンラインサポートも行っております。
お困りごとのある方、ご興味がある方は、ぜひお問い合わせください。
お問い合わせは こちら から。
体験授業のお申込みは こちら から。
過去の「Unityで作るシューティングゲーム」はこちらから。
Comments