kidoOooOoooOOom

IT系で開発やってます

Space Shooterにボス敵を追加&ハイスコア管理追加

公式チュートリアルのSpace Shooterでは隕石が飛んでくるだけの状態で終わって寂しいので、勉強がてらボス敵を追加してみた。

今日できたところまでのボスの仕様は下記の通り。

  • ボスにはHPがある
  • HPがある程度へったら攻撃パターンが変わる
  • ボスの弾を当てたらエフェクト&スコア加算
  • ボスのHPを0にしたらエフェクト&スコア加算&ゲームクリア演出
  • ボスは画面上部からフェードインして登場する
  • ボスはくるくる回転している

かなり汚いが、下記のようなスクリプトをボスのPrefabに追加した。

using UnityEngine;
using System.Collections;

public class BossController : MonoBehaviour
{
    public Vector3 fixPosition;
    public float speed;
    public GameObject player;
    public GameObject explosion;
    public GameObject playerExplosion;
    public GameObject hitBulletExplosion;
    private int maxHitpoint;
    public int hitpoint;
    public int hitScoreValue;
    public int destoryScoreValue;
    private GameController gameController;
    public GameObject shot;
    public GameObject headShotSpawn;
    public float headShotFireRate;
    private float nextFire;

    void Start()
    {
        GameObject gameControllerObject = GameObject.FindWithTag("GameController");
        if (gameControllerObject != null)
        {
            gameController = gameControllerObject.GetComponent <GameController>();
        }
        if (gameController == null)
        {
            Debug.Log("Cannot find GameController script");
        }
        maxHitpoint = hitpoint;
    }

    void OnTriggerEnter(Collider other)
    {
        if (other.tag == "Boundary" || other.tag == "Asteroid")
        {
            return;
        }

        if (other.tag == "Player")
        {
            Instantiate(playerExplosion, other.transform.position, other.transform.rotation);
            gameController.GameOver();
            Destroy(other.gameObject);
        }

        if (other.tag == "Bullet")
        {
            Destroy(other.gameObject);
            gameController.AddScore(hitScoreValue);
            hitpoint = hitpoint - 1;

            if (hitpoint <= 0)
            {
                gameController.AddScore(destoryScoreValue);

                Instantiate(explosion, transform.position, transform.rotation);
                Destroy(gameObject);
                gameController.GameClear();
            }
            else
            {
                Instantiate(hitBulletExplosion, other.transform.position, other.transform.rotation);
            }
        }

    }

    void Update()
    {
        if (transform.position.z > fixPosition.z)
        {
            transform.position -= new Vector3(0, 0, 1) * speed * Time.deltaTime;
        }

        transform.Rotate(0, 1, 0);

        if (Time.time > nextFire)
        {
            nextFire = Time.time + headShotFireRate;

            if (hitpoint <= maxHitpoint / 2)
            {
                // random 7WAY shot
                int randomRotate = Random.Range(-40, 40);
                for (float i = -60f; i <= 60f; i += 20f)
                {
                    Instantiate(shot, headShotSpawn.transform.position, Quaternion.Euler(0, i + randomRotate, 0));
                }
                audio.Play();
            }
            else
            {
                // 3WAY shot
                for (float i = -20f; i <= 20f; i += 20f)
                {
                    Instantiate(shot, headShotSpawn.transform.position, Quaternion.Euler(0, i, 0));
                }
                audio.Play();
            }
        }
    }
}

苦労した点としては、

  • ボスを回転させるために、transform.Rotate(0, 1, 0); を実行している。最初はtransform.rotationを直接触ろうとして挫折し、Rotateに気付いたときにもrigidbodyを有効にしていないと動かなくてハマった。
  • ボスの弾を発生させるところ。Prefab化したオブジェクトをhierarchyに置いて編集してもPrefab自体には反映されないのと、間違えてPrefabを空のオブジェクトで上書きしてUndoができなくてまた最初からやり直したところ。バックアップはこまめにやらないと死ぬ。
  • ボスの弾の角度をつけるところも、普通のQuaternionのコンストラクタだとうまくいかず(というか四元数がまだ理解できていない)、Quaternion.Eulerを使うといい感じに角度がつけられた(ここもまだちゃんと理解していない)。

あと、ハイスコア管理にはPlayerPrefsを使った。これはJavaのMapのようにさくっと使えて楽だ。