가고일과 고스트 적을 추가했다.
이번에 게임에 추가한 새로운 적은 가고일과 고스트다. 각각의 적은 플레이어를 다른 방식으로 위협하며, 게임의 긴장감을 높이는 역할을 한다.
가고일
가고일은 고정된 위치에서 돌면서 주변을 감시하는 역할을 한다. 일정 시간마다 랜덤하게 왼쪽, 오른쪽, 또는 뒤쪽으로 회전하며 주변을 주시한다. 만약 가고일의 시야에 플레이어가 들어오면 주변에 있는 고스트들을 불러서 플레이어를 추격하게 만든다.
가고일 코드
public class Gargoyle : MonoBehaviour
{
[SerializeField] private GameObject[] Ghosts;
void Start()
{
StartCoroutine(ActivateGargoyle());
}
IEnumerator ActivateGargoyle()
{
while (true)
{
yield return new WaitForSeconds(5);
int direction = Random.Range(0, 3);
if (direction == 0)
StartCoroutine(RotateGargoyle(90, 1));
else if (direction == 1)
StartCoroutine(RotateGargoyle(-90, 1));
else
StartCoroutine(RotateGargoyle(180, 1));
}
}
IEnumerator RotateGargoyle(float angle, float duration)
{
Quaternion startRotation = transform.rotation;
Quaternion endRotation = transform.rotation * Quaternion.Euler(0, angle, 0);
float time = 0;
while (time < duration)
{
transform.rotation = Quaternion.Slerp(startRotation, endRotation, time / duration);
time += Time.deltaTime;
yield return null;
}
transform.rotation = endRotation;
}
void OnTriggerEnter(Collider other)
{
if (other.CompareTag("Player"))
{
foreach (GameObject ghost in Ghosts)
{
ghost.GetComponent<Ghost>().CallGhost();
}
Debug.Log("Player Entered Gargoyle's Trigger");
}
}
}
위 코드는 가고일이 일정 시간마다 랜덤으로 회전하며 플레이어를 감지할 때 고스트들을 호출하도록 했다.
고스트
고스트는 설정된 여러 웨이포인트를 랜덤으로 이동하며 순찰한다. 이동 후 잠시 대기했다가 다음 웨이포인트로 이동하며, 플레이어가 가까이 오면 그를 추적한다.
고스트의 이동에는 NavMesh를 사용했다.
NavMesh란?
NavMesh는 Unity에서 AI 캐릭터의 경로를 쉽게 설정할 수 있도록 돕는 기능이다. 복잡한 지형에서도 AI가 최적의 경로를 찾아 이동하도록 해준다.
고스트 코드
public class Ghost : MonoBehaviour
{
[SerializeField] private Transform[] Waypoints;
[SerializeField] private Transform playerTransform;
private Animator animator;
private NavMeshAgent agent;
private bool isChasing = false;
void Start()
{
agent = GetComponent<NavMeshAgent>();
animator = GetComponent<Animator>();
StartCoroutine(Patrol());
}
IEnumerator Patrol()
{
while (!isChasing)
{
int waypointIndex = Random.Range(0, Waypoints.Length);
animator.SetBool("IsWalking", true);
agent.SetDestination(Waypoints[waypointIndex].position);
yield return new WaitUntil(() => agent.remainingDistance < 0.1f);
animator.SetBool("IsWalking", false);
yield return new WaitForSeconds(3f);
}
}
void OnTriggerEnter(Collider other)
{
if (other.CompareTag("Player"))
{
isChasing = true;
StopCoroutine(Patrol());
StartCoroutine(ChasePlayer(5));
}
}
IEnumerator ChasePlayer(float chaseTime)
{
Debug.Log("Chasing Player");
float elapsedTime = 0f;
agent.speed = 3f;
animator.SetBool("IsWalking", true);
while (elapsedTime < chaseTime)
{
if (playerTransform != null)
{
agent.SetDestination(playerTransform.position);
}
elapsedTime += Time.deltaTime;
yield return null;
}
isChasing = false;
agent.speed = 2f;
animator.SetBool("IsWalking", false);
Debug.Log("Stopped Chasing Player");
yield return new WaitForSeconds(2f);
StartCoroutine(Patrol());
}
public void CallGhost()
{
if (isChasing)
return ;
isChasing = true;
StopCoroutine(Patrol());
StartCoroutine(ChasePlayer(15));
}
}
고스트는 웨이포인트를 설정하여 랜덤으로 이 웨이포인트로 이동하고 도착하면 잠시 대기후 다른 웨이포인트를 향하여 이동하게 하였다.
코드 설명
- Patrol 함수: 고스트가 웨이포인트를 순찰한다. 랜덤으로 다음 웨이포인트를 선택해 이동하며, 도착 후 잠시 대기한다.
- OnTriggerEnter 함수: 플레이어가 고스트의 감지 범위에 들어오면 추격이 시작된다.
- ChasePlayer 함수: 플레이어를 일정 시간 동안 추격하며, 추격이 끝나면 다시 순찰 상태로 돌아간다.
- CallGhost 함수: 가고일이 고스트를 호출할 때 사용되며, 일정 시간 동안 플레이어를 추적하도록 설정했다.
결론
가고일과 고스트를 추가하면서 게임에 더 많은 긴장감과 도전 요소를 추가할 수 있었다. NavMesh를 이용해 적의 이동을 더 자연스럽고 효율적으로 구현할 수 있었으며, 코루틴을 통해 다양한 동작을 부드럽게 처리했다. 이제 좀 게임같다!
이제 UI, 사운드 추가하면 끝이보인다..!
추가: 고스트의 감지 문제 해결
게임을 테스트하던 중, 고스트가 벽을 넘어 플레이어를 감지하는 문제를 발견했다. 이를 해결하기 위해 다음과 같은 함수를 추가해 한 번 더 감지 여부를 판별하게 했다.
bool IsPlayerVisible()
{
RaycastHit hit;
Vector3 direction = playerTransform.position - transform.position;
int layerMask = ~LayerMask.GetMask("Ghost");
if (Physics.Raycast(transform.position, direction.normalized, out hit, Mathf.Infinity, layerMask))
{
if (hit.collider.CompareTag("Player"))
{
return true;
}
}
return false;
}
이 함수는 고스트가 플레이어를 감지하려고 할 때, 고스트에서 플레이어로 레이를 쏴서 가장 먼저 맞는 오브젝트가 플레이어인지 확인하는 방식이다. 만약 레이캐스트가 플레이어가 아닌 다른 오브젝트에 먼저 맞는다면, 그 사이에 장애물이 있는 것으로 간주한다.
코드를 적용한 후, 고스트가 플레이어를 아예 감지하지 못하는 버그가 발생했다. 이는 고스트 내부에서 레이를 쏘다 보니 고스트 자신이 레이를 맞게 되는 문제 때문이었다. 이를 해결하기 위해 레이캐스트에서 고스트 레이어를 제외하는 방식으로 문제를 해결했다.
'Unity > John Lemon in Nightmareland' 카테고리의 다른 글
UnityPisine Module06 - 11. 끝! (0) | 2024.08.29 |
---|---|
Unity Piscine Module06 - 10. UI 추가 (3) | 2024.08.28 |
Unity Piscine Module06 - 8. Post Processing 적용 (0) | 2024.08.27 |
Unity Piscine Module06 - 7. 열쇠 수집 / 엔딩 애니메이션 구현 (0) | 2024.08.27 |
Unity Piscine Module06 - 6. 맵 구현 (0) | 2024.08.26 |