주말에 구현해보기로 시도해볼 것으로 몬스터의 플레이어 탐지 방식에 대한 것을 시도해보고자, 우선은 몬스터의 애니메이션부터 넣어보기로 했다.
아직 몬스터의 공격은 구현하지 않았지만, 우선은 이와 같은 흐름으로 구현해보고자 하였다.
여기서 몬스터가 탐지하는 조건을 Trigger 영역으로 설정하고, 노멀몬스터 코드에 해당 내용을 반영했다.
또한 트리거 영역을 설정하여 트리거 영역 코드도 만들었다.
추가한 트리거 영역에 대한 코드를 아래와 같이 작성했다.
using UnityEngine;
public class DetectArea : MonoBehaviour
{
private bool _canTracking = false;
public bool CanTracking { get { return _canTracking; } }
private Transform _targetTransform = null;
public Transform TargetTransform { get { return _targetTransform; } }
private void OnTriggerEnter(Collider other)
{
if (other.CompareTag("Player"))
{
_canTracking = true;
_targetTransform = other.transform;
}
}
private void OnTriggerExit(Collider other)
{
if(other.CompareTag("Player"))
{
_canTracking = false;
_targetTransform = null;
}
}
}
노멀 몬스터 코드 수정은 아래와 같이 되었다.
using DesignPattern;
using UnityEngine;
using UnityEngine.AI;
public class NormalMonster : Monster, IDamageable
{
private bool _isActivateControl = true;
//private bool _canTracking = true;
[SerializeField] private int MaxHp;
private ObservableProperty<int> CurrentHp = new();
private ObservableProperty<bool> IsMoving = new();
private ObservableProperty<bool> IsAttacking = new();
private ObservableProperty<bool> IsAlive = new();
private Animator _animator;
[SerializeField] private DetectArea _detectArea;
[Header("Config Navmesh")]
private NavMeshAgent _navMeshAgent;
//[SerializeField] private Transform _targetTransform;
private void Awake() => Init();
private void Update() => HandleControl();
private void Init()
{
_navMeshAgent = GetComponent<NavMeshAgent>();
_navMeshAgent.isStopped = true;
_animator = GetComponent<Animator>();
CurrentHp.Value = MaxHp;
IsAlive.Value = true;
}
private void HandleControl()
{
if (!_isActivateControl) return;
HandleMove();
Death(IsAlive.Value);
}
private void HandleMove()
{
if (_detectArea.TargetTransform == null) return;
if (_detectArea.CanTracking)
{
_navMeshAgent.SetDestination(_detectArea.TargetTransform.position);
}
_navMeshAgent.isStopped = !_detectArea.CanTracking;
IsMoving.Value = _detectArea.CanTracking;
_animator.SetBool("IsMove", _detectArea.CanTracking);
}
public void TakeDamage(int value)
{
CurrentHp.Value -= value;
if (CurrentHp.Value <= 0)
{
IsAlive.Value = false;
}
}
private void Death(bool value)
{
_animator.SetBool("IsAlive", value);
}
}
이와 같이 작성하여 몬스터가 움직이고 죽는 것은 1차적으로 구현하였다. 하지만 이와 같은 문제점이 발견되었다.
- 몬스터가 한 번 움직이기 시작했을 때 다시 멈추지 않는다.
- 몬스터가 죽고 나서도 그 시체가 플레이어를 쫓아온다.
- 몬스터의 총격 피격 영역이 이상하다.
우선 위 3 가지 문제를 기준으로 수정과정이 어떻게 진행됐는지 서술해보고자 한다.
이 경우는 단순했다. 애초에 몬스터가 감지되지 않을 때 애니메이션 변경이 되지 않았기 때문이었다.
HandleMove() 함수의 코드 내용을 return 부분을 없애는 것으로 수정했다.
private void HandleMove()
{
if (_detectArea.TargetTransform == null)
_animator.SetBool("IsMove", _detectArea.CanTracking);
if (_detectArea.CanTracking)
{
_navMeshAgent.SetDestination(_detectArea.TargetTransform.position);
}
_navMeshAgent.isStopped = !_detectArea.CanTracking;
IsMoving.Value = _detectArea.CanTracking;
_animator.SetBool("IsMove", _detectArea.CanTracking);
}
이 경우가 생각보다 생각이 꼬이기 좋았다. 처음에는 단순히 Death 부분의 코드를 아래와 같이 수정했었다.
private void Death(bool value)
{
_animator.SetBool("IsAlive", value);
_isActivateControl = false;
}
하지만 이와 같이 작성하니 몬스터가 죽고 난 뒤에 몬스터가 죽는 애니메이션이 출력되지 않았다. 혹은 처음부터 몬스터가 가만히 서 있는 채로 변하는 바가 없었다.
지금 보면 아주 단순한 문제지만 _isActivateControl을 들어갈 때 조건이 없기 때문에 발생한 문제였다.
Death는 업데이트 문에서 실행되는 내용인데 아무 조건도 없이 바로 컨트롤이 비활성화가 되기 때문에 발생한 문제였다. 따라서 아래와 같이 코드를 수정했다.
private void Death(bool value)
{
_animator.SetBool("IsAlive", value);
if (IsAlive.Value == false)
{
_isActivateControl = false;
}
}
이제는 몬스터가 죽으면 더 이상 이동하지 않게 되었다. 하지만 한 가지 문제가 더 생겼다.
몬스터가 죽으면 살짝 더 전방으로 움직인 다음에 죽는 것이다.
처음에 Rigidbody를 끄는 방식도 생각하긴 했지만 그건 리스크가 너무 클 것 같아 이동 속도를 0으로 바꾸는 방식을 생각해 보았다.
private void Death(bool value)
{
_animator.SetBool("IsAlive", value);
if (IsAlive.Value == false)
{
_isActivateControl = false;
_navMeshAgent.speed = 0;
}
}
네비메쉬 상으로 이동하고 있던 속도를 0으로 만들어주니 몬스터가 그 자리에서 정상적으로 죽는 것을 확인했다.
상당히 골머리를 앓고 있으며 아직까지 해결하지 못한 문제이다.
테스트 내내 발생했던 문제가, 캐릭터가 조준 모드를 하면 중앙에 나타나는 ArrowHead를 기준으로, 몬스터를 공격해도 몬스터가 피격을 받지 않는 이상한 상황을 경험했다.
한참을 테스트해보고 Ray를 쏴본 끝에 이것이 ArrowHead의 위치와 카메라에서 쏘는 Ray의 방향이 일치하지 않아 발생하는 문제라는 것을 확인했고, 이를 위해서 카메라 각도를 정밀하게 조정해보는 시도도 하였다.
하지만 이마저도 결국 다른 거리나 위치에서 몬스터를 조준하면 카메라 각도가 다시 빗나가서 몬스터가 맞지 않는 현상이 일어났다.
이 부분에 대해서 어떻게 해결할 지에 대해서 고민하고 있으나, 아직까지는 해결 방법을 찾지 못하였다.
이 부분에 대한 고민을 좀 더 해 봐야 할 것으로 보인다.
구현 내용
트리거 영역에 들어오면 몬스터가 플레이어를 추격하는 방식 구현.
트리거 영역 밖으로 나가면 몬스터는 추격을 멈추고 다시 그 자리에 멈춰선다.
몬스터의 Idle, Run, Death 애니메이션 구현
몬스터가 총에 의해 데미지를 받고, HP가 0이 되면 죽는 모션을 구현
버그 내용