제가 자주 사용하는 방식이라 한번 포스팅 해봅니다.
캐릭터의 동작에 맞춰 특정 함수를 실행시키고 싶을 때가 있습니다.
예를 들면 칼을 휘두르는 모션이 있으면, 모션 끝이나 중간에 함수를 실행시킨다던지 말이죠.
바로 delelgate를 이용해서 말입니다.
자주 사용하는 AnimationPlayer 클래스입니다.
public class AnimationPlayer : MonoBehaviour
{
System.Action _beginCallback = null;
System.Action _midCallback = null;
System.Action _endCallback = null;
public void Play(string trigger,
System.Action beginCallback = null,
System.Action midCallback = null,
System.Action endCallback = null
)
{
GetComponent<Animator>().SetTrigger(trigger);
_beginCallback = beginCallback;
_midCallback = midCallback;
_endCallback = endCallback;
}
//Animation Event
public void OnBeginEvent()
{
//if (null != _beginCallback)
// _beginCallback();
_beginCallback?.Invoke(); //위 주석부분처럼 작성해도 무관합니다.
}
public void OnMidEvent()
{
_midCallback?.Invoke();
}
public void OnEndEvent()
{
Debug.Log("Animaton End Event");
_endCallback?.Invoke();
}
}
System.Action은 크게 신경 쓰지 않아도 됩니다. Action 역시 delegate입니다.
원형을 보면
public delegate void Action();
인 걸 확인할 수 있습니다. 반환형이 void이고, 넘길 인자가 없을 때, 기본형으로 자주 사용합니다.
다시 돌아와서, 로직 어디선가 애니메이션을 플레이할 일이 온다면, AnimationPlayer의 Play 함수를 통해서 애니메이션을 재생시킬겁니다.
Play함수를 보면 트리거이름, 콜백1, 콜백2, 콜백3... 이런형식으로 되어있습니다.
애니메이션 플레이와 동시에 호출할 함수를 같이 넘겨주는 겁니다!
예시를 살펴보면서 이해해봅시다.
먼저 Animator와 함께 AnimationPlayer 스크립트를 오브젝트에 추가해줍니다.
그리고 공격 애니메이션 클립에서 원하는 부분에 이벤트를 추가하고, 인스펙터에서 AnimationPlayer에서 만든 OnStart, mid, endEvent함수를 이벤트에 등록해줍니다.
위 사진은 끝에 endEvent만 추가해줬는데 취향껏 여러개의 이벤트를 만들고, AnimationPlayer 클래스도 수정해 쓰시면 됩니다.
public class AttackState : State
{
override void Start()
{
_character.GetAnimPlayer().Play(GetTriggerName(lookAt), null, null,
() =>
{
//endEvent
_nextState = eStateType.IDLE;
});
}
}
캐릭터 공격 statemachine의 일부입니다.
endEvent부분에 람다식으로 실행할 내용을 전달하고 있습니다.
캐릭터가 공격을 시작하면 AnimationPlayer를 통해 공격 애니메이션을 재생합니다.
그리고 공격 애니메이션이 끝나면, 다음 상태를 idle 상태로 전환합니다.
결과
공격 애니메이션이 끝나면 정상적으로 IDLE 애니메이션이 재생되고(Idle state로 전환)
위에 확인을 위한 end event로그가 정상적으로 찍히는 것 역시 확인할 수 있습니다.
굳이 이렇게 쓸 필요가 있을까? 하는 분들을 위해 다시 보충설명을 하면
적1, 적2, 적3이 각기 다른 타이밍과 그 타이밍에 맞게 함수들을 호출해야 한다고 합시다.
그렇다면 적1Func.cs, 적2Func.cs... 를 만들어서 오브젝트에 추가해주고, 애니메이션 이벤트에 함수를 연결...
물론 이렇게 해도 결과는 같습니다. 하지만 적1Func.cs, 적2Func.cs... 들은 한번 쓰고 버려진다는 점이죠. 재활용성이 없고, 내용만 달라지지 같은 작업의 "반복"입니다.
하지만 AnimationPlayer를 추가하고, 필요한 로직을 람다식으로만 넘겨주면, 불필요한 스크립트도 생길 일이 없고
AnimatinoPlayer는 계속 다른 곳에서 추가만 해주면 손쉽게 사용할 수 있습니다.
이상 delegate를 활용한 AnimationPlayer 소개였습니다.
'유니티 > 팁, 정보 노트' 카테고리의 다른 글
[Unity]LayerMask 사용 예시 (0) | 2021.12.05 |
---|---|
[C#]delegate와 event 정리 (0) | 2021.12.05 |
C#) null 관련 연산자 (?.) (0) | 2020.02.19 |
씬 인덱스 or 이름 체크 (0) | 2020.01.31 |
[Unity]자꾸 실수하는 sprite 레이어 설정 (0) | 2019.10.20 |