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のようにさくっと使えて楽だ。