오늘은 팀프로젝트에서 필요한 수류탄을 만들어 볼 예정이다.
먼저 시작하기 앞서 수류탄이 어떻게 동작하는 지 생각해 볼 필요가 있다.
- 던지면 일정 시간 이후에 터진다.
- 터질 때 폭발 이펙트가 발생한다.
- 폭발범위 안에 있는 몬스터들에게 데미지를 입힌다.
- 폭발범위 안에 있더라도 몬스터가 장애물 뒤에 있으면 데미지를 입히지 않는다.
- 오브젝트와 폭발 이펙트를 제거한다.
이 중 4번을 어떻게 구현할 지 고민을 많이 했던 것 같다.
그렇게 나온 결론은 다음과 같다.
- 수류탄이 터질 때, 폭발 범위 안에 있는 오브젝트들과 충돌체크를 한다.
- 그 오브젝트들 중 수류탄 피격 가능한 Tag를 가지고 있는 오브젝트들의 collider를 리스트에 저장한다.
- 리스트에 저장한 모든 collider에 raycast를 쏜다.
- raycast에 충돌한 오브젝트의 Tag가 수류탄 피격 가능한 Tag면 데미지를 입힌다.
그림판에서 대충 그린 그림으로 설명하면 수류탄이 터질 때 폭발 범위만큼 몬스터를 체크해서 해당 몬스터들에게 전부 레이캐스트를 쏜다. 레이캐스트에 피격당하면 몬스터의 앞에 장애물이 없다는 뜻이므로 데미지를 입힌다.
| 설명 이미지 |
|---|
![]() |
| 빨간 원은 폭발범위, 빨간 선은 레이캐스트이다. |
중간에 기획이 바뀌어서 수류탄이 미사일이 됐지만, 폭발 타이밍 빼곤 동일하기에 처음 생각한대로 스크립트를 작성했다.
using System.Collections.Generic; using UnityEngine; public class Grenade : MonoBehaviour { public float explosionRange; public GameObject explosionParticle; private GameObject curParticle; private void Explosion() { curParticle = Instantiate(explosionParticle, transform.position, transform.rotation); Collider[] colliders = Physics.OverlapSphere(transform.position, explosionRange); List<Collider> enemyColliders = new List<Collider>(); foreach (var col in colliders) { if (col.CompareTag("Grenade_Target")) { enemyColliders.Add(col); } } foreach (var enemy in enemyColliders) { Vector3 direction = (enemy.transform.position - transform.position).normalized; RaycastHit hit; Debug.DrawRay(transform.position, direction * explosionRange, Color.red, 1f); if (Physics.Raycast(transform.position, direction, out hit, explosionRange)) { if (hit.collider.gameObject.CompareTag("Grenade_Target")) { Debug.Log(hit.collider.name + " 피격"); } } } gameObject.SetActive(false); Invoke("DelayDestroy", 3f); } private void DelayDestroy() { Destroy(curParticle); Destroy(this.gameObject); } private void OnDrawGizmos() { Gizmos.color = Color.red; Gizmos.DrawWireSphere(transform.position, explosionRange); } private void OnCollisionEnter(Collision collision) { Explosion(); } }