Chapter 6-3. 애니메이션 : State 패턴
카테고리: Unity Lesson 2
태그: Unity Game Engine
인프런에 있는 Rookiss님의 [C#과 유니티로 만드는 MMORPG 게임 개발 시리즈] Part3: 유니티 엔진 강의를 듣고 정리한 필기입니다. 😀
🌜 강의 들으러 가기 Click
Chapter 6. 애니메이터
🚖 State 디자인 패턴
bool isFalling;
bool isJumping;
bool isSkillCasting;
bool isSkillChanneling;
if(isJumping)
{
}
else
{
if(isSkillChanneling && isFalling)
{
}
else
{
if(isSkillCasting)
{
}
}
}
이런식으로 bool
타입의 상태 flag 변수를 여러개 사용하면 너무 복잡하다. if - else
문이 너무 많아진다. 상태 flag 변수가 적은 갯수라면 괜찮지만 규모가 큰 게임일 수록 많이 필요하기 때문에 적합하지 않다.
해결 방법 👉 State 패턴 사용하기!
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerController : MonoBehaviour
{
float wait_run_ratio = 0;
[SerializeField]
float _speed = 10.0f;
Vector3 _destPos; // 목적지
void Start()
{
Managers.Input.MouseAction -= OnMouseClicked;
Managers.Input.MouseAction += OnMouseClicked;
}
public enum PlayerState
{
Die,
Moving,
Idle,
}
PlayerState _state = PlayerState.Idle;
void Update()
{
switch (_state)
{
case PlayerState.Die:
UpdateDie();
break;
case PlayerState.Moving:
UpdateMoving();
break;
case PlayerState.Idle:
UpdateIdle();
break;
}
}
void UpdateDie()
{
// 아무것도 못함
}
void UpdateMoving()
{
Vector3 dir = _destPos - transform.position;
if (dir.magnitude < 0.0001f) // 도착함
{
_state = PlayerState.Idle;
}
else // 도착 X
{
float moveDist = Mathf.Clamp(_speed * Time.deltaTime, 0, dir.magnitude);
transform.position = transform.position + dir.normalized * moveDist;
transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.LookRotation(dir), 10 * Time.deltaTime);
transform.LookAt(_destPos);
}
// 애니메이션
wait_run_ratio = Mathf.Lerp(wait_run_ratio, 1, 10.0f * Time.deltaTime);
Animator anim = GetComponent<Animator>();
anim.SetFloat("wait_run_ratio", wait_run_ratio);
anim.Play("WAIT_RUN");
}
void UpdateIdle()
{
// 애니메이션
wait_run_ratio = Mathf.Lerp(wait_run_ratio, 0, 10.0f * Time.deltaTime);
Animator anim = GetComponent<Animator>();
anim.SetFloat("wait_run_ratio", wait_run_ratio);
anim.Play("WAIT_RUN");
}
void OnMouseClicked(Define.MouseEvent evt)
{
if (_state == PlayerState.Die)
return;
if (evt != Define.MouseEvent.Click)
return;
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
Debug.DrawRay(Camera.main.transform.position, ray.direction * 100.0f, Color.red, 1.0f);
RaycastHit hit;
if (Physics.Raycast(ray, out hit, 100.0f, LayerMask.GetMask("Wall")))
{
_destPos = hit.point;
_state = PlayerState.Moving;
}
}
}
if (_state == PlayerState.Die)
//...
switch (_state)
{
case PlayerState.Die:
UpdateDie();
break;
case PlayerState.Moving:
UpdateMoving();
break;
case PlayerState.Idle:
UpdateIdle();
break;
}
enum
으로 상태들을 정의하고,if-else
문 혹은switch
문 사용하기!
- 대신
bool
상태 플래그 변수와는 다르게 동시에 두가지 상태를 가질 순 없음. 👉 이와 같은 특성 때문에 여러 동작이 꼬일 일이 없음. 동작 별로 분리해서 만들 수 있다는 장점.isJumping && isAttacking // 👉 가능 _state == PlayerState.Jump && _state == PlayerState.Attack // 👉 불가능
🌜 개인 공부 기록용 블로그입니다. 오류나 틀린 부분이 있을 경우
언제든지 댓글 혹은 메일로 지적해주시면 감사하겠습니다! 😄
댓글 남기기