[TIL] Unity 최종프로젝트 몬스터 애니메이션(Animation Event)
2025.04.16 - [Unity] - [TIL] Unity 최종프로젝트 몬스터 HP바 만들기
[TIL] Unity 최종프로젝트 몬스터 HP바 만들기
2025.04.11 - [Unity] - [TIL] Unity 최종프로젝트 몬스터 AI 구현하기(오브젝트풀)_ 4일차 [TIL] Unity 최종프로젝트 몬스터 AI 구현하기(오브젝트풀)_ 4일차2025.04.10 - [Unity] - [TIL] Unity 최종프로젝트 몬스터 AI
unihee1.tistory.com
이제 이전에 임시로 적용했던 에셋말고 최종프로젝트 게임에 맞는 로우폴리 에셋을 적용해줄 것이다.
또한 여러가지 애니메이션을 추가하여 좀 더 생동감 있게 구현할 것이다.
오늘은 몬스터가 Chase 상태에 진입하기 전에 소리를 지르는 애니메이션을 재생하여 위압감을 줄 것이다.
1. Animation Event 사용하기
- Animation Event란?
애니메이션 클립의 특정 시점에 스크립트의 함수를 호출할 수 있게 해주는 기능으로 애니메이션과 코드 사이의 타이밍을 정밀하게 조절할 수 있게 해준다.
- Animation Event 추가하기
Animation Event를 추가할 애니메이션을 두번 클릭하여 Animation 창을 열어준다.
그런 다음 애니메이션이 끝나는 지점을 한 번 클릭하고 우클릭하여 Add Animation Event를 눌러준다.
Animation Event를 추가하고 나면 위의 사진과 같이 인스펙터 창에 나타난다.
Function 부분에 Event 함수명을 지정해준다.
이제 Function에서 지정한 함수명을 구현해줄 차례다.
- MonsterController 스크립트
using UnityEngine;
using UnityEngine.AI;
public class MonsterController : MonoBehaviour
{
[Header("Data")]
[SerializeField] private MonsterData originalData;
public MonsterData Data { get; private set; }
[Header("Components")]
public NavMeshAgent nav;
private Rigidbody rigid;
public Animator animator;
public MonsterHPUI hpUI;
private StateMachine stateMachine;
private TakeDamageState takeDamageState;
public Transform target { get; private set; }
private void OnEnable()
{
Data = Instantiate(originalData);
Data.monsterHP = Data.maxHP;
RefreshHealthUI();
if (stateMachine == null)
{
stateMachine = new StateMachine();
takeDamageState = new TakeDamageState(this, stateMachine);
}
stateMachine.ChangeState(new IdleState(this, stateMachine));
}
private void Start()
{
nav = GetComponent<NavMeshAgent>();
rigid = GetComponent<Rigidbody>();
animator = GetComponent<Animator>();
hpUI = GetComponentInChildren<MonsterHPUI>();
target = GameObject.FindWithTag("Test")?.transform;
if (Data != null)
{
nav.speed = Data.monsterRunSpeed;
}
}
private void Update()
{
stateMachine?.Update();
}
private void FixedUpdate()
{
FreezeVelocity();
}
private void FreezeVelocity()
{
rigid.velocity = Vector3.zero;
rigid.angularVelocity = Vector3.zero;
}
public void ApplyDamage(float damage)
{
takeDamageState.SetDamage(damage);
stateMachine.ChangeState(takeDamageState);
}
public void RefreshHealthUI()
{
if (hpUI != null)
{
hpUI.UpdateHP(Data.monsterHP);
}
}
public void OnScreamEnd()
{
stateMachine.ChangeState(new ChaseState(this, stateMachine));
}
}
Animation Event는 애니메이션이 끝나는 지점에 생성했기 때문에 OnScream 함수 안에 애니메이션이 끝나면 Chase상태로 변환될 수 있게 구현하였다.
- IdleState 스크립트
using UnityEngine;
public class IdleState : IState
{
[SerializeField] private MonsterController monster;
[SerializeField] private StateMachine stateMachine;
private float idleTime = 10f;
private float timer;
public IdleState(MonsterController monster, StateMachine stateMachine)
{
this.monster = monster;
this.stateMachine = stateMachine;
}
public void Enter()
{
monster.animator.SetBool("isIdle", true);
timer = 0f;
}
public void Update()
{
timer += Time.deltaTime;
float distanceToTarget = Vector3.Distance(monster.transform.position, monster.target.position);
if (distanceToTarget < monster.Data.monsterAttackRange)
{
stateMachine.ChangeState(new AttackState(monster, stateMachine));
}
else if (distanceToTarget < monster.Data.monsterDetectRange)
{
monster.animator.SetTrigger("isScream");
}
else if (timer > idleTime)
{
stateMachine.ChangeState(new WanderState(monster, stateMachine));
}
}
public void Exit()
{
monster.animator.SetBool("isIdle", false);
}
}
그럼 이제 기존에 있던 Chase상태로 변환하는 코드를 삭제해주고 그자리에 소리 지르는 애니메이션을 재생할 수 있게
monster.animator.SetTrigger("isScream");을 추가해주면 애니메이션이 재생되고 재생이 끝나면 MonsterController의 OnScream 함수를 통해 Chase 상태로 진입할 수 있다.
2. 실행해보기
몬스터가 소리 지르는 애니메이션이 끝나고 플레이어를 쫓아가는 것을 확인할 수 있다.
※ 애니메이션: 믹사모_ Zombie Scream, Zombie Idle, Zombie Run
※ 몬스터 에셋: POLYGON City Zombies - Low Poly 3D Art by Synty | Characters | Unity Asset Store