Zombie FBX를 클릭후 Rig탭을 눌러보며
Assets폴더아래 Animation폴더를 만들어서 우클릭후 Create>Animation>Animator Controller를 만들어
Zombie의 Animator 컴포넌트의 Controller에 끌어다 놓습니다.
ZombieAnim을 더블클릭하면 animator edit window가 나타납니다.
그래프 위를 우클릭하고 Empty를 만듭니다.
Z_idle을 끌어다 Inspector의 Motion에 놓고 이름을 idle로 변경합니다.
우클릭 Empty를 추가하고 Move로 이름 바꾸고 Z_Run_InPlace를 끌어다 놓습니다.
Idle과 Move를 연결하기 위해 Idle를 우클릭후 MakeTransition을 선택하 나타나는 화살표를 Move와 연결합니다.
Animation Editor 좌상 +를 눌러 Trigger를 선택하고 이름을 IdleTo Move로 합니다.
트랜지션을 선택해 Inspector에서 Condition의 +를 누르면 List에 IdleToMove가 생성되고 스크립트에서 사용할수 있습니다.
HasExitTime을 언체크해 조건 Trigger시 이전 애니메이션이 끝나지 않아도 바로 전환됩니다.
EnemyFSM.cs를 다음과 같이 수정합니다.
Animator anim; // Animation 컴포넌트에 접근하기 위해서
void Start()
{
생략
anim = GetComponentInChildren<Animator>();
}
void Idle()
{
if (Vector3.Distance(transform.position, player.position) < findDistance)
{
생략
anim.SetTrigger("IdleToMove");
}
}
void Move()
{
if(Vector3.Distance(transform.position, originPos) > moveDistance)
{
생략
}
else if (Vector3.Distance(transform.position, player.position) > attackDistance)
{
생략
transform.foward = dir;
}
else
{
}
}
Move->Idle로 Transition을 만들고 +를 눌러 MoveToIdle Trigger를 만들고 트랜지션 화살표를 선택후 Conditions +를 눌러 MoveToIdle을 추가후
즉시 실행될수 있도록 HasExitTime을 언체크 합니다.
복귀이동은 EnemyFSM .Return()함수 입니다.
MoveToIdle을 트리거 시켜주고 애니메이션을 원점으로 다 돌아간후 Start()에서 저장한 원래 향했던 방향쪽으로 향하게 합니다.
Vector3 originPos;
Quaternion originRot;
void Start()
{
originPos = transform.position;
originRot = transform.rotation;
}
void Return()
{
if (Vector3.Distance(transform.position, originPos) > 0.1f)
{
생략
transform.position = originPos;
transform.rotation = originRot;
}
else
{
생략
anim.SetTrigger("MoveToIdle");
}
}
공격을 위한 애니메이션을 만들기 위해 State를 2개 추가하고 Attack, Attack Delay로 이름을 변경하고 Move->Attack Delay로 Transition을 연결합니다.
Attack에는 Z_Attack animation을 Attack Dealy에는 Z_Idel을 연결해 줍니다. Move->Attck->Move 스테이트 사이의 급격한 애니메이션 변화를 방지하기 위해서 입니다.
MoveToAttackDealy Parameter를 만들고
Condition+ 추가후 선택해주고, Has Exit Time을 언체크 합니다.
Move()함수에서 Attack로 State가 변경될때 MoveToAttackDealy를 Trigger합니다.
void Move()
{
if(Vector3.Distance(transform.position, originPos) > moveDistance)
{ 생략
}
else if (Vector3.Distance(transform.position, player.position) > attackDistance)
{ 생략
}
else
{
생략
m_State = EnemyState.Attack;
anim.SetTrigger("MoveToAttackDelay");
}
}
Attack Dealy <-> Attack State 사이 Transition을 만들고
StartAttack Trigger Parameter를 만듭니다.
Attack Dealy -> Attack 화살표를 선택하고 컨디션을 설정합니다.
Attack은 한번만 실행하게 하기 위해 Z_Attack을 선택하고 Inspector의 LoopTime을 Uncheck합니다
Attack()함수내에서 플레이어와의 거리가 공격거리 이내로 접근하면 StartAttack을 Trigger 시킵니다.
void Attack()
{
if (Vector3.Distance(transform.position, player.position) < attackDistance)
{
currentTime += Time.deltaTime;
if (currentTime > attackDelay)
{
생략
anim.SetTrigger("StartAttack");
}
생략
}
}
Attack -> Attack Dealy transition화살표를 선택하고 조건이 없는 상태에서 Has Exit Time을 놔두면 자동으로 실행됩니다.
공격중이나 공격대기 상태에서도 플레이어가 공격거리 이상 멀어지면 Move상태로 되기 위해 Move로의 Transition을 연결합니다
AttackToMove파라미터를 만들고 Move로 향하는 Transition을 다음과 같이 설정합니다.
Attack()함수에서 AttackToMove Trigger를 실행시킵니다.
void Attack()
{
if (Vector3.Distance(transform.position, player.position) < attackDistance)
{
생략
}
else
{
생략
anim.SetTrigger("AttackToMove");
}
}
Animation Editor 우클릭후 Create Sub-State Machine을 클릭합니다. 이름을 Attack Process로 변경합니다.
Attack와 Attack Delay를 동시에 선택한후 Attack Process로 끌면 +가 나타납니다. 마우스를 놓으면 Attack Process안으로 합쳐집니다.
좀비가 공격하기도 전 화면이 붉게 변합니다. 좀비가 손을 휘두를때 화면이 붉게 변하게 히보겠습니다.
Z_Attack를 더블 클릭하면 Animator가 나타납니다.
플레이바를 움직여도 좀비 애니메이션 프리뷰를 볼수 없습니다. 씬의 좀비를 선택합니다.
이제서야 프리뷰가 활성화되는데 애니메이션 클립이 바껴 다시 선택해 줍니다.
플레이바를 움직여 보면 좀비가 공격을 타격하는 지점이 대충 10프레임입니다.
애니메이터 좌측 Add Event를 + 누르면 10프레임에 작은 이벤트가 추가 됩니다. 파란색 이벤트를 크릭하면 펑션을 지정할수 있습니다.
지정할 펑션으로 사용할 스크립트를 만들겠습니다. HitEvent.cs 스크립트를 만듭니다. 애니메이션이 실행되는 Zombe게임오브젝트에 컴포넌트로 추가합니다.
EnemyFSM의 공격코드를 주석처리 합고 새로운 함수 public void AttackAction()로 옮겨줍니다. HitEvent.cs에서 실행시켜주기 위해서입니다.
void Attack()
{
if (Vector3.Distance(transform.position, player.position) < attackDistance)
{
currentTime += Time.deltaTime;
if (currentTime > attackDelay)
{
//player.GetComponent<PlayerMove>().DamageAction(attackPower);
}
}
}
public void AttackAction()
{
player.GetComponent<PlayerMove>().DamageAction(attackPower);
}
HitEvent.cs에서 EnemyFSM의 AttackAction을 실행시켜줍니다.
using UnityEngine;
public class HitEvent : MonoBehaviour
{
public EnemyFSM efsm;
public void PlayerHit()
{
efsm.AttackAction();
}
}
하이라키에서 efsm의 변수에 Enemy 게임 오브젝트를 끌어다 할당 합니다.
이제 Z_Attack 애니메이션에 이벤트에 함수를 지정합니다. 잘지정되었다면 이벤트 위에 마우스를 올리면 함수명을 확인할수 있습니다.
플레이 해보니 공격이 좀 늦어서 Attack Delay->Attack transition duration을 짧게 해주었습니다. 꺼도 될것 같습니다.
다음은 피격 애니메이션을 구현하겠습니다. 피격은 어떤 상태에서도 일어나야하므로 Any State를 활용하겠습니다.
Empty State를 만들어 Any와 연결하겠습니다.
피격 애니메이션은 인생유니티 카페에서 다운 받습니다.
fbx를 애니메이션으로 옮기고 클릭해서 Rig탭에서 애니메이션 Type 을 Humanoid로 바꿉니다.
fbx 옆 화살표를 열어서 애니메이션이 있는데 전 mixamo.com이라고 되어 있네요 이걸 Damaged에 Motion에 끌어다 놓습니다.
Trigger시키기 위해 Damaged 파라미터를 만들고 Transition조건으로 설정합니다.
Damage Animation이 끝나면 자동적으로 Move로 갈수 있게 연결해 줍니다.
Has Exit Time은 체크해주고 Conditions는 없습니다.
EnemyFSM.cs의 HitEnemy() 함수안에 anim.SetTrigger("Damaged"); 를 추가해 줍니다.
public void HitEnemy(int hitPower)
{
if(m_State == EnemyState.Damaged || m_State == EnemyState.Die || m_State == EnemyState.Return)
{
return;
}
hp -= hitPower;
if (hp > 0)
{
m_State = EnemyState.Damaged;
추가-> anim.SetTrigger("Damaged");
Damaged();
statusPrint();
}
else
{
m_State = EnemyState.Die;
statusPrint();
Die();
}
}
좀비를 총으로 쏴보면 피격 애니메이션이 끝나기 전에 움직입니다.
피격 애니메이션을 열어보면 길이가 2초 60프레임 입니다. Damaged State를 선택해 Speed를2로 변경해서 재생시간을 1초로 줄여줍니다.
EnemyFSM의 DamageProcess()에서 waitForSeconds()를 1초로 변경해 맞춥니다.
IEnumerator DamageProcess()
{
yield return new WaitForSeconds(1f);
m_State = EnemyState.Move;
statusPrint();
}
Die State를 만들어 Any와 연결하겠습니다 Z_FallingForward를 끌어다 Motion에 놓습니다.
Die Parameter를 Trigger로 만들고 트랜지션에 컨디션으로 설정하고 Has Exit Time을 꺼줍니다.
EnemyFSM HitEnemy()함수에 Die Trigger를 추가해 줍니다.
public void HitEnemy(int hitPower)
{
생략
if (hp > 0)
{
생략
}
else
{
m_State = EnemyState.Die;
추가-->anim.SetTrigger("Die");
Die();
statusPrint();
}
}
'인생유니티 > FPS게임' 카테고리의 다른 글
플레이어 애니메이션 (0) | 2025.04.23 |
---|---|
플레이어 모델링 교체 (0) | 2025.04.23 |
모델링 교체와 애니메이션 - 알파 (1) | 2025.04.22 |
UI - Proto (0) | 2025.04.22 |
Enemy 제작 (0) | 2025.04.22 |