안녕하세요. 인텔리원스튜디오(IntelliOneStudio)입니다.
오늘은 GPT-4, GPT-4o 활용해서 Unity에서 애니메이션과 게임 로직을 통합해볼께요.
[오늘의 목표] GPT-4, GPT-4o 활용해서 Unity에서 애니메이션과 게임 로직 통합하기
[참고]
2024.06.03 - [디지털노마드] - [챗GPT게임개발43] GPT-4, GPT-4o 활용해서 Unity에서 애니메이션과 게임 로직 통합을 위한 개념 이해
※ ChatGPT 답변 내용 중 제가 별도로 표시한 파란색 내용을 기준으로 읽으시면 좀 더 이해가 쉽게 될거예요.
※ 이 글은 Unity 에서 제공한 2D Game Kit을 활용했어요.
상태와 동작을 연결하는 스크립트 살펴보기
먼저 애니메이션 상태와 그 상태에 맞게 동작을 연결하는 스크립트를 살펴볼께요.
using UnityEngine;
using UnityEngine.Animations;
namespace Gamekit2D
{
public class SceneLinkedSMB<TMonoBehaviour> : SealedSMB
where TMonoBehaviour : MonoBehaviour
{
protected TMonoBehaviour m_MonoBehaviour;
bool m_FirstFrameHappened;
bool m_LastFrameHappened;
public static void Initialise (Animator animator, TMonoBehaviour monoBehaviour)
{
SceneLinkedSMB<TMonoBehaviour>[] sceneLinkedSMBs = animator.GetBehaviours<SceneLinkedSMB<TMonoBehaviour>>();
for (int i = 0; i < sceneLinkedSMBs.Length; i++)
{
sceneLinkedSMBs[i].InternalInitialise(animator, monoBehaviour);
}
}
protected void InternalInitialise (Animator animator, TMonoBehaviour monoBehaviour)
{
m_MonoBehaviour = monoBehaviour;
OnStart (animator);
}
public sealed override void OnStateEnter(Animator animator, AnimatorStateInfo stateInfo, int layerIndex, AnimatorControllerPlayable controller)
{
Debug.Log("OnStateEnter called");
m_FirstFrameHappened = false;
OnSLStateEnter(animator, stateInfo, layerIndex);
OnSLStateEnter (animator, stateInfo, layerIndex, controller);
}
public sealed override void OnStateUpdate(Animator animator, AnimatorStateInfo stateInfo, int layerIndex, AnimatorControllerPlayable controller)
{
if(!animator.gameObject.activeSelf)
return;
if (animator.IsInTransition(layerIndex) && animator.GetNextAnimatorStateInfo(layerIndex).fullPathHash == stateInfo.fullPathHash)
{
OnSLTransitionToStateUpdate(animator, stateInfo, layerIndex);
OnSLTransitionToStateUpdate(animator, stateInfo, layerIndex, controller);
}
if (!animator.IsInTransition(layerIndex) && m_FirstFrameHappened)
{
OnSLStateNoTransitionUpdate(animator, stateInfo, layerIndex);
OnSLStateNoTransitionUpdate(animator, stateInfo, layerIndex, controller);
}
if (animator.IsInTransition(layerIndex) && !m_LastFrameHappened && m_FirstFrameHappened)
{
m_LastFrameHappened = true;
OnSLStatePreExit(animator, stateInfo, layerIndex);
OnSLStatePreExit(animator, stateInfo, layerIndex, controller);
}
if (!animator.IsInTransition(layerIndex) && !m_FirstFrameHappened)
{
m_FirstFrameHappened = true;
OnSLStatePostEnter(animator, stateInfo, layerIndex);
OnSLStatePostEnter(animator, stateInfo, layerIndex, controller);
}
if (animator.IsInTransition(layerIndex) && animator.GetCurrentAnimatorStateInfo(layerIndex).fullPathHash == stateInfo.fullPathHash)
{
OnSLTransitionFromStateUpdate(animator, stateInfo, layerIndex);
OnSLTransitionFromStateUpdate(animator, stateInfo, layerIndex, controller);
}
}
public sealed override void OnStateExit(Animator animator, AnimatorStateInfo stateInfo, int layerIndex, AnimatorControllerPlayable controller)
{
m_LastFrameHappened = false;
OnSLStateExit(animator, stateInfo, layerIndex);
OnSLStateExit(animator, stateInfo, layerIndex, controller);
}
/// <summary>
/// Called by a MonoBehaviour in the scene during its Start function.
/// </summary>
public virtual void OnStart(Animator animator) { }
/// <summary>
/// Called before Updates when execution of the state first starts (on transition to the state).
/// </summary>
public virtual void OnSLStateEnter(Animator animator, AnimatorStateInfo stateInfo, int layerIndex) { }
/// <summary>
/// Called after OnSLStateEnter every frame during transition to the state.
/// </summary>
public virtual void OnSLTransitionToStateUpdate(Animator animator, AnimatorStateInfo stateInfo, int layerIndex) { }
/// <summary>
/// Called on the first frame after the transition to the state has finished.
/// </summary>
public virtual void OnSLStatePostEnter(Animator animator, AnimatorStateInfo stateInfo, int layerIndex) { }
/// <summary>
/// Called every frame after PostEnter when the state is not being transitioned to or from.
/// </summary>
public virtual void OnSLStateNoTransitionUpdate(Animator animator, AnimatorStateInfo stateInfo, int layerIndex) { }
/// <summary>
/// Called on the first frame after the transition from the state has started. Note that if the transition has a duration of less than a frame, this will not be called.
/// </summary>
public virtual void OnSLStatePreExit(Animator animator, AnimatorStateInfo stateInfo, int layerIndex) { }
/// <summary>
/// Called after OnSLStatePreExit every frame during transition to the state.
/// </summary>
public virtual void OnSLTransitionFromStateUpdate(Animator animator, AnimatorStateInfo stateInfo, int layerIndex) { }
/// <summary>
/// Called after Updates when execution of the state first finshes (after transition from the state).
/// </summary>
public virtual void OnSLStateExit(Animator animator, AnimatorStateInfo stateInfo, int layerIndex) { }
/// <summary>
/// Called before Updates when execution of the state first starts (on transition to the state).
/// </summary>
public virtual void OnSLStateEnter(Animator animator, AnimatorStateInfo stateInfo, int layerIndex, AnimatorControllerPlayable controller) { }
/// <summary>
/// Called after OnSLStateEnter every frame during transition to the state.
/// </summary>
public virtual void OnSLTransitionToStateUpdate(Animator animator, AnimatorStateInfo stateInfo, int layerIndex, AnimatorControllerPlayable controller) { }
/// <summary>
/// Called on the first frame after the transition to the state has finished.
/// </summary>
public virtual void OnSLStatePostEnter(Animator animator, AnimatorStateInfo stateInfo, int layerIndex, AnimatorControllerPlayable controller) { }
/// <summary>
/// Called every frame when the state is not being transitioned to or from.
/// </summary>
public virtual void OnSLStateNoTransitionUpdate(Animator animator, AnimatorStateInfo stateInfo, int layerIndex, AnimatorControllerPlayable controller) { }
/// <summary>
/// Called on the first frame after the transition from the state has started. Note that if the transition has a duration of less than a frame, this will not be called.
/// </summary>
public virtual void OnSLStatePreExit(Animator animator, AnimatorStateInfo stateInfo, int layerIndex, AnimatorControllerPlayable controller) { }
/// <summary>
/// Called after OnSLStatePreExit every frame during transition to the state.
/// </summary>
public virtual void OnSLTransitionFromStateUpdate(Animator animator, AnimatorStateInfo stateInfo, int layerIndex, AnimatorControllerPlayable controller) { }
/// <summary>
/// Called after Updates when execution of the state first finshes (after transition from the state).
/// </summary>
public virtual void OnSLStateExit(Animator animator, AnimatorStateInfo stateInfo, int layerIndex, AnimatorControllerPlayable controller) { }
}
//This class repalce normal StateMachineBehaviour. It add the possibility of having direct reference to the object
//the state is running on, avoiding the cost of retrienving it through a GetComponent every time.
//c.f. Documentation for more in depth explainations.
public abstract class SealedSMB : StateMachineBehaviour
{
public sealed override void OnStateEnter(Animator animator, AnimatorStateInfo stateInfo, int layerIndex) { }
public sealed override void OnStateUpdate(Animator animator, AnimatorStateInfo stateInfo, int layerIndex) { }
public sealed override void OnStateExit(Animator animator, AnimatorStateInfo stateInfo, int layerIndex) { }
}
}
[쉽게 설명하기 : GPT-4, GPT-4o]
이 코드는 Unity의 애니메이션 시스템에서 상태를 관리하고 특정 게임 오브젝트의 동작과 애니메이션 상태를 연결하는 패턴을 구현한 것입니다. 쉽게 말해, 이 패턴을 통해 특정 MonoBehaviour(게임 오브젝트의 동작을 정의하는 클래스)와 애니메이터 상태를 효율적으로 결합하여 다양한 동작을 구현할 수 있습니다.
쉽게 설명하면
- SceneLinkedSMB<TMonoBehaviour>는 특정 상태에서 실행할 코드를 MonoBehaviour와 연결하는데 사용됩니다.
- Initialise 메서드는 애니메이터와 MonoBehaviour를 연결합니다.
- OnStateEnter, OnStateUpdate, OnStateExit 메서드는 상태 전환 시 호출되어 특정 동작을 수행합니다.
- 하위 클래스는 이 메서드들을 재정의하여 상태별로 다른 동작을 정의할 수 있습니다.
이 패턴을 통해 상태별로 구체적인 동작을 정의하고, 이 동작을 애니메이터와 게임 오브젝트의 동작에 쉽게 연결할 수 있습니다.
이 스크립트는 플레이어의 상태별로 구체적인 동작을 정의할 수 있다는 내용만 기억하면 되요.
이제 어떻게 사용되는 지 볼께요.
게임 시작 시 플레이어 동작 정의하기
위 스크립트를 활용해서 아래 기능이 어떻게 동작하는 지 살펴볼께요.
게임 시작 시 PlayerCharacter의 이동 벡터를(0, 0)으로 설정하여 플레이어를 정지 시키기
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace Gamekit2D
{
public class RespawnSMB : SceneLinkedSMB<PlayerCharacter>
{
public override void OnSLStateEnter(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
{
base.OnSLStateEnter(animator, stateInfo, layerIndex);
m_MonoBehaviour.SetMoveVector(Vector2.zero);
}
}
}
- RespawnSMB 클래스는 SceneLinkedSMB<PlayerCharacter>를 상속받아요.
- OnSLStateEnter 메서드는 리스폰 상태에 들어갈 때 호출되며, PlayerCharacter의 이동 벡터를 (0, 0)으로 설정하여 플레이어를 정지시켜요.
위 스크립트를 저장하고 아래 영상과 같이 설정 후 실행하면 되요.
영상에서와 같이 게임 시작 시 Spawn 상태가 실행되고 그 상태에서 원하는 동작이 되는 것을 볼 수 있어요.
조금 어려울 수 있지만 조금 천천히 살펴보면 이해가 될거예요.
오늘은 GPT-4, GPT-4o 활용해서 Unity에서 애니메이션과 게임 로직을 통합해봤어요.
지금까지,
언제나 성장하는 인텔리원스튜디오(IntelliOneStudio)입니다.
감사합니다.
'디지털노마드' 카테고리의 다른 글
[챗GPT게임개발46] GPT-4, GPT-4o 활용해서 Unity UI Toolkit을 사용하여 버튼 추가 및 씬에 표시하기 (5) | 2024.06.05 |
---|---|
[챗GPT게임개발45] GPT-4, GPT-4o 활용해서 Unity에서 Blend Tree 설정 알아보기 (3) | 2024.06.04 |
[챗GPT게임개발43] GPT-4, GPT-4o 활용해서 Unity에서 애니메이션과 게임 로직 통합을 위한 개념 이해 (2) | 2024.06.03 |
[챗GPT게임개발42] GPT-4, GPT-4o 활용해서 Unity Timeline에서 Cinemachine 클립 간의 부드러운 전환 설정 방법 (3) | 2024.05.31 |
[챗GPT게임개발40] GPT-4, GPT-4o 활용해서 카메라 줌 인 구현하기 (29) | 2024.05.29 |