본문 바로가기
GGM/엔진

20230313 - 엔진 - 애니메이션, 인풋 바꿈

by DDongYeop 2023. 3. 13.
728x90

 

모델링의 리깅의 Animation Type을 설정해줄 수 있다. 

Lagacy은 말 그대로 예전에 쓰던 것이다. 가장 빠르기에 쓰기도 하지만 거의 안 쓴다. 

Generic은 거미나 사족보행 동물 등 이것저것에 쓰인다. 다만 모델링에 맞는 애니메이션이 필요하다. 

Humanoid은 말 그대로 인간형 모델링을 의미한다. 인간에게 필요한 모든 관절이 있어야 사용할 수 있다. 

 

다음은 애니메이션 Transition에 대한 설명이다. 

Has Exit Time 토글은 어느시점에서 나가게 하는 것을 킬 것인지 적용시키는 것이다.

Exit Time은 특정 위치에서 나가게 하는 것이다. 0.6이면 이 애니메이션이 60% 실행된 후 애니메이션을 변경 시켜주는 것이다.

Transition Duration은 애니메이션끼리 변경이 될때 어느정도의 시간을 줄 것인지 적어주는 곳이다. 

 

AgentAnimator스크립트를 만들어주었다. 

우선 int형 변수를 생성하여 아까 Animator에서 생성한 해쉬값을 가져온다. 이런 방식을 사용하면 조금 더 메모리에 좋다. 

그리고 public으로 함수 두개를 만들어서 다른 스크립트에서도 변경할 수 있도록 해준다. 

using UnityEngine;

public class AgentAnimator : MonoBehaviour
{
    private readonly int _speedHash = Animator.StringToHash("speed");
    private readonly int _isAirboneHash = Animator.StringToHash("is_airbone");

    private Animator _animator;
    public Animator Animator => _animator;

    private void Awake()
    {
        _animator = GetComponent<Animator>();
    }

    public void SetSpeed(float value)
    {
        _animator.SetFloat(_speedHash, value);
    }

    public void SetAirbone(bool value)
    {
        _animator.SetBool(_isAirboneHash, value);
    }
}

 

Awake에서 _stateDictionary에 StateType, IState를 가지고 있는 Dictionary을 넣어준다. 

이후 플레이어 아래있는 States오브젝트를 찾아서 넣어주고, StateType에 있는 모든 상태를 _stateDictionary에 넣어준다. 

그러던 중 stateScript에 있는 SetUp함수를 지금 transform을 넣어서 적용시켜준디. 

using Core;
using System;
using System.Collections.Generic;
using UnityEngine;

public class AgentController : MonoBehaviour
{
    private Dictionary<StateType, IState> _stateDictionary = null;  //가지고 있는 상태들 저장
    private IState _currentState; //현재 상태 저장

    private void Awake()
    {
        _stateDictionary = new Dictionary<StateType, IState>();
        Transform stateTrm = transform.Find("States");

        foreach( StateType state in Enum.GetValues(typeof (StateType)) )
        {
            IState stateScript = stateTrm.GetComponent($"{state}State") as IState;
            if(stateScript == null)
            {
                Debug.LogError($"There is no script : {state}");
                return;
            }
            stateScript.SetUp(transform);
            _stateDictionary.Add(state, stateScript);
        }
    }
    private void Start()
    {
        ChangeState(StateType.Normal);
    }

    private void ChangeState(StateType type)
    {
        _currentState?.OnExitState(); //현재 상태 나가고
        _currentState = _stateDictionary[type];
        _currentState?.OnEnterState(); //다음상태 시작
    }

    private void Update()
    {
        _currentState.UpdateState();
    }
}

 

AgentInput 스크립트를 만들어 인풋을 받아주고 Action형 변수를 만들어서 실행시킨다.

그러고 AgentMovement에서 인풋 받은 것을 대체해준다. 

using System;
using UnityEngine;

public class AgentInput : MonoBehaviour
{
    public event Action<Vector3> OnMovementKeyPress = null;

    private void Update()
    {
        UPdateMoveInput();
    }

    private void UPdateMoveInput()
    {
        float horizontal = Input.GetAxisRaw("Horizontal");
        float vertical = Input.GetAxisRaw("Vertical");
        OnMovementKeyPress?.Invoke(new Vector3(horizontal, 0, vertical));
    }
}

 

이후 IState를 만들어서 특정 함수들을 만들어둔다. 

using UnityEngine;

public interface IState
{
    public void OnEnterState();
    public void OnExitState();
    public void UpdateState();
    
    public void SetUp(Transform agentRoot);
}

 

이후 IState를 상속 받는 추상클래스 CommonState를 만들어준다. 

using UnityEngine;

public abstract class CommonState : MonoBehaviour, IState
{
    public abstract void OnEnterState();
    public abstract void OnExitState();
    public abstract void UpdateState();

    protected AgentAnimator _animator;
    protected AgentInput _agentInput;
    protected AgentController _agentController;

    public virtual void SetUp(Transform agentRoot)
    {
        _animator = agentRoot.Find("Visual").GetComponent<AgentAnimator>();
        _agentInput = agentRoot.GetComponent<AgentInput>();
        _agentController = agentRoot.GetComponent<AgentController>();
    }

    //피격처리시 사용할 것
    public void OnHitHandle(Vector3 hitPoint, Vector3 Normal)
    {

    }
}

 

이후 CommonState를 상속 받는 NormalState를 만들어주고 

특정 스테이트에서 해야할 것을 넣어준다. 

using UnityEngine;

public class NormalState : CommonState
{
    protected AgentMovement _agentMovement;

    public override void OnEnterState()
    {
        _agentMovement?.StopImmediately();
        _agentInput.OnMovementKeyPress += OnMovementHandle;
    }

    public override void OnExitState()
    {
        _agentMovement?.StopImmediately();
        _agentInput.OnMovementKeyPress -= OnMovementHandle;
    }

    private void OnMovementHandle(Vector3 obj)
    {
        _agentMovement?.SetMovementVelocity(obj);
    }

    public override void SetUp(Transform agentRoot)
    {
        base.SetUp(agentRoot);
        _agentMovement = agentRoot.GetComponent<AgentMovement>();
    }

    public override void UpdateState()
    {
        
    }
}
728x90

댓글