StateMachineBehaviour란?
StateMachineBehaviour는 Unity의 애니메이션 상태 기계(State Machine)에서 특정 상태나 전이(Transition)에 대해 스크립트를 작성할 수 있게 해주는 클래스이다.
애니메이터 컨트롤러 내의 각 상태(State) 또는 전이에 특정 동작을 수행하는 코드를 추가하고 싶을 때 사용한다.
쉽게 말해, 애니메이터가 작동할 때 이벤트를 호출해 주는 기능을 한다.
StateMachineBehaviour 사용 방법
StateMachineBehaviour를 사용하기 위해서는 먼저 새로운 스크립트를 생성하고, MonoBehaviour가 아닌 StateMachineBehaviour를 상속받아야 한다.
이를 통해 애니메이션 상태와 연관된 다양한 이벤트에 대한 메서드를 오버라이드할 수 있다.
StateMachineBehaviour 스크립트 생성
우선은 Idle 애니메이션에 적용 시켜 보겠다.
public class PlayerIdle : StateMachineBehaviour
{
// 우선 스크립트 먼저 생성
}
스크립트를 만들었다면 해당 스크립트를 애니메이터의 State에다가 붙여준다.
StateMachineBehaviour 주요 메서드
이제 생성한 스크립트에 각각 상태의 변화에 따라 override 하여 원하는 코드를 작성 할 수 있다.
OnStateEnter | 상태가 시작될 때 호출된다. |
OnStateUpdate | 상태가 업데이트될 때 매 프레임마다 호출된다. |
OnStateExit | 상태가 종료될 때 호출된다. |
OnStateMove | 루트 모션(root motion)이 계산된 후에 호출된다. |
OnStateIK | 애니메이션 IK(Inverse Kinematics)가 계산된 후에 호출된다. |
StateMachineBehaviour 활용 예제
예제로 구현 할 내용은 우선 두가지다.
1. 공격시 무기가 손에서 나타나고 공격이 끝나면 무기가 사라진다.
2. 점프와 공격하고 숨고르기가 완료 될때 까지는 다른 행동을 막는다.
1. 공격시 무기 활성화/비활성화
PlayerController Script
public class PlayerController : MonoBehaviour
{
public Animator PlayerAnimator;
public GameObject SwordObject;
void Start()
{
// 필요한 State Machine Behaviour 스크립트를 가져온다
var jumpState = PlayerAnimator.GetBehaviour<PlayerJump>();
var attackState = PlayerAnimator.GetBehaviour<PlayerAttack>();
var refreshState = PlayerAnimator.GetBehaviour<PlayerRefresh>();
jumpState.controller = this;
attackState.controller = this;
refreshState.controller = this;
}
void Update()
{
if(Input.GetKeyDown(KeyCode.Mouse0))
{
PlayerAnimator.SetTrigger("Attack");
}
if(Input.GetKeyDown(KeyCode.Space))
{
PlayerAnimator.SetTrigger("Jump");
}
PlayerAnimator.SetFloat("Speed", 0);
if(Input.GetKey(KeyCode.W))
{
PlayerAnimator.SetFloat("Speed", 1);
}
}
}
PlayerJump Script
public class PlayerJump : StateMachineBehaviour
{
public PlayerController controller;
}
PlayerAttack Script
public class PlayerAttack : StateMachineBehaviour
{
public PlayerController controller;
public override void OnStateEnter(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
{
controller.SwordObject.SetActive(true);
}
public override void OnStateExit(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
{
controller.SwordObject.SetActive(false);
}
}
PlayerRefresh Script
public class PlayerRefresh : StateMachineBehaviour
{
public PlayerController controller;
}
공격시 무기 활성화/비활성화 영상
공격시에만 무기가 잘 나온다.
하지만 중간에 클릭을 더 해버리면 숨고르기가 끝난 후 바로 공격을 실행한다.
이 행동을 막기 위해 숨고르기가 끝난 후 부터 입력을 받도록 해보겠다.
2. 행동 중간에 입력 막기
PlayerController Script
public class PlayerController : MonoBehaviour
{
public Animator PlayerAnimator;
public GameObject SwordObject;
public bool CanAct = true; // 추가
void Start()
{
var jumpState = PlayerAnimator.GetBehaviour<PlayerJump>();
var attackState = PlayerAnimator.GetBehaviour<PlayerAttack>();
var refreshState = PlayerAnimator.GetBehaviour<PlayerRefresh>();
jumpState.controller = this;
attackState.controller = this;
refreshState.controller = this;
}
void Update()
{
// 추가
if(!CanAct)
return;
if(Input.GetKeyDown(KeyCode.Mouse0))
{
PlayerAnimator.SetTrigger("Attack");
}
if(Input.GetKeyDown(KeyCode.Space))
{
PlayerAnimator.SetTrigger("Jump");
}
PlayerAnimator.SetFloat("Speed", 0);
if(Input.GetKey(KeyCode.W))
{
PlayerAnimator.SetFloat("Speed", 1);
}
}
}
PlayerJump Script
public class PlayerJump : StateMachineBehaviour
{
public PlayerController controller;
// 추가
public override void OnStateEnter(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
{
controller.CanAct = false;
}
}
PlayerAttack Script
public class PlayerAttack : StateMachineBehaviour
{
public PlayerController controller;
public override void OnStateEnter(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
{
controller.CanAct = false; // 추가
controller.SwordObject.SetActive(true);
}
public override void OnStateExit(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
{
controller.SwordObject.SetActive(false);
}
}
PlayerRefresh Script
public class PlayerRefresh : StateMachineBehaviour
{
public PlayerController controller;
// 추가
public override void OnStateExit(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
{
controller.CanAct = true;
}
}
행동 중간에 입력 막기 영상
애니메이션 중에 입력을 해도 숨고르기 끝난 후 바로 연달아서 작동을 안한다.
결론
StateMachineBehaviour를 이용하면 애니메이션 상태에 따라 원하는 동작을 간편하게 구현할 수 있다.
이 예제는 간단하지만, StateMachineBehaviour의 활용 방법은 다양하다.
'Unity' 카테고리의 다른 글
Animator StringToHash 유니티 최적화 (0) | 2024.07.02 |
---|---|
ScriptableObject 사용 방법 (0) | 2024.06.26 |
Coroutine과 UniTask 비교 (0) | 2024.06.22 |
Coroutine 사용 방법 (0) | 2024.06.18 |
UniTask 사용 방법 (0) | 2024.06.17 |