実装の流れ
- とりあえず全部のpublic変数を直す
- 衝突判定をPlayer経由でGameManagerで行う
→ここでGameOverも移行される - UIをGameManagerに移行
- 衝突判定をTagからGetComponentに変更する
- SpawnerをジェネリクスにしてPlayerのFindWithTagをやめる
→合わせて生成可能なものだけに制限する - カウント処理をSpawnerに移譲する
課題後のコード
EnemyBase.cs
csharp1using UnityEngine; 2using UnityEngine.AI; 3 4public class EnemyBase : MonoBehaviour 5{ 6 public event Action DestroyNotify; 7 [SerializeField] private NavMeshAgent agent; 8 [SerializeField] private float targetChangeDistance = 1.0f; 9 [SerializeField] protected Transform target; 10 11 // Update is called once per frame 12 void Update() 13 { 14 if (target != null) agent.SetDestination(target.position); 15 float distance = Vector3.Distance(transform.position, target.position); 16 if (distance < targetChangeDistance) 17 { 18 ChangeTarget(); 19 } 20 } 21 22 protected virtual void ChangeTarget() 23 { 24 25 } 26 27 public void SetTarget(Transform target) 28 { 29 this.target = target; 30 } 31 32 private void OnDestroy() 33 { 34 DestroyNotify?.Invoke(); 35 } 36}
FollowEnemy.cs
csharp1public class FollowEnemy : EnemyBase 2{ 3}
PortalEnemy.cs
csharp1using UnityEngine; 2 3public class PatrolEnemy : EnemyBase 4{ 5 [SerializeField] private Transform[] patrolPoints; 6 private int currentPointIndex; 7 8 public void Start() 9 { 10 currentPointIndex = 0; 11 target = patrolPoints[currentPointIndex]; 12 } 13 14 protected override void ChangeTarget() 15 { 16 currentPointIndex++; 17 if (currentPointIndex >= patrolPoints.Length) 18 { 19 currentPointIndex = 0; 20 } 21 target = patrolPoints[currentPointIndex]; 22 } 23}
Item.cs
csharp1using System; 2using UnityEngine; 3 4public class Item : MonoBehaviour 5{ 6 public event Action DestroyNotify; 7 8 private void OnDestroy() 9 { 10 DestroyNotify?.Invoke(); 11 } 12}
SpawnerBase.cs
csharp1using UnityEngine; 2 3public abstract class SpawnerBase<T> : MonoBehaviour where T : MonoBehaviour 4{ 5 [SerializeField] protected T prefab; 6 [SerializeField] private int maxInstanceNum = 3; 7 [SerializeField] private float interval = 5.0f; 8 private float timer; 9 protected int instanceNum; 10 11 // Update is called once per frame 12 void Update() 13 { 14 timer += Time.deltaTime; 15 if (timer > interval && instanceNum < maxInstanceNum) 16 { 17 Spawn(); 18 timer = 0; 19 } 20 } 21 protected abstract void Spawn(); 22}
EnemySpawner.cs
csharp1using UnityEngine; 2 3public class EnemySpawner : SpawnerBase<EnemyBase> 4{ 5 [SerializeField] private Transform[] spawnPoints; 6 private Transform targetTransform; 7 8 public void Initialize(Transform targetTransform) 9 { 10 this.targetTransform = targetTransform; 11 } 12 13 14 protected override void Spawn() 15 { 16 int spawnIndex = Random.Range(0, spawnPoints.Length); 17 Transform spawnPoint = spawnPoints[spawnIndex]; 18 EnemyBase enemy = Instantiate(prefab, spawnPoint.position, Quaternion.identity); 19 enemy.SetTarget(targetTransform); 20 instanceNum++; 21 enemy.DestroyNotify += DestroyEnemy; 22 } 23 24 private void DestroyEnemy() 25 { 26 instanceNum--; 27 } 28}
ItemSpawner.cs
csharp1using UnityEngine; 2 3public class ItemSpawner : SpawnerBase<Item> 4{ 5 [SerializeField] private Vector2 areaRangeMin; 6 [SerializeField] private Vector2 areaRangeMax; 7 8 protected override void Spawn() 9 { 10 float x = Random.Range(areaRangeMin.x, areaRangeMax.x); 11 float z = Random.Range(areaRangeMin.y, areaRangeMax.y); 12 Vector3 pos = new Vector3(x, transform.position.y, z); 13 Item item = Instantiate(prefab, pos, Quaternion.identity); 14 instanceNum++; 15 item.DestroyNotify += ItemDestroy; 16 } 17 18 private void ItemDestroy() 19 { 20 instanceNum--; 21 } 22}
PlayerController.cs
csharp1using System; 2using UnityEngine; 3using UnityEngine.InputSystem; 4 5public class PlayerController : MonoBehaviour 6{ 7 public event Action<GameObject> OnCollision; 8 9 [SerializeField] private Rigidbody rigidbody; 10 [SerializeField] private float moveSpeed = 5.0f; 11 12 // Update is called once per frame 13 void Update() 14 { 15 Keyboard keyboard = Keyboard.current; 16 Vector3 moveDirection = Vector3.zero; 17 18 if (keyboard.wKey.isPressed) 19 { 20 moveDirection += Vector3.forward; 21 } 22 else if (keyboard.aKey.isPressed) 23 { 24 moveDirection += Vector3.left; 25 } 26 else if (keyboard.sKey.isPressed) 27 { 28 moveDirection += Vector3.back; 29 } 30 else if (keyboard.dKey.isPressed) 31 { 32 moveDirection += Vector3.right; 33 } 34 35 rigidbody.linearVelocity = moveDirection * moveSpeed; 36 } 37 38 private void OnCollisionEnter(Collision collision) 39 { 40 OnCollision?.Invoke(collision.gameObject); 41 } 42 43 private void OnTriggerEnter(Collider other) 44 { 45 OnCollision?.Invoke(other.gameObject); 46 } 47}
GameManager.cs
csharp1using UnityEngine; 2using TMPro; 3using UnityEngine.SceneManagement; 4 5public class GameManager : MonoBehaviour 6{ 7 [SerializeField] private EnemySpawner enemySpawner; 8 [SerializeField] private PlayerController playerController; 9 [SerializeField] private TextMeshProUGUI hpText; 10 [SerializeField] private TextMeshProUGUI pointText; 11 12 public static int point; 13 private int hp = 3; 14 15 void Start() 16 { 17 point = 0; 18 hpText.SetText("HP : " + hp); 19 pointText.SetText("Point : " + point); 20 enemySpawner.Initialize(playerController.transform); 21 playerController.OnCollision += PlayerCollision; 22 } 23 24 private void PlayerCollision(GameObject other) 25 { 26 EnemyBase enemy = other.GetComponent<EnemyBase>(); 27 if (enemy != null) 28 { 29 EnemyCollision(enemy); 30 return; 31 } 32 Item item = other.GetComponent<Item>(); 33 if (item != null) 34 { 35 ItemCollision(item); 36 } 37 } 38 39 private void EnemyCollision(EnemyBase enemy) 40 { 41 hp -= 1; 42 hpText.SetText("HP : " + hp); 43 Destroy(enemy.gameObject); 44 45 if (hp <= 0) 46 { 47 SceneManager.LoadScene("Result"); 48 } 49 } 50 51 private void ItemCollision(Item item) 52 { 53 point++; 54 pointText.SetText("Point : " + point); 55 56 Destroy(item.gameObject); 57 } 58}
ResultSceneManager.cs
csharp1using UnityEngine; 2using UnityEngine.UI; 3using UnityEngine.SceneManagement; 4using TMPro; 5 6public class ResultSceneManager : MonoBehaviour 7{ 8 public TextMeshProUGUI pointText; 9 public Button retryButton; 10 11 // Start is called once before the first execution of Update after the MonoBehaviour is created 12 void Start() 13 { 14 pointText.SetText("Get Point : " + GameManager.point); 15 retryButton.onClick.AddListener(Retry); 16 } 17 18 private void Retry() 19 { 20 SceneManager.LoadScene("InGame"); 21 } 22}