DEG-16 [UPDATE] PlayerState 구현

This commit is contained in:
Jay 2025-04-18 13:17:30 +09:00
parent 1a7b282bd8
commit 7c526a1f70
19 changed files with 316 additions and 37 deletions

View File

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:8f4cdb374bd0572e763220b0e51ca6989957a7c65c0be176f5ee5e00068419e3 oid sha256:08d59f4f15437f527ada2d57db2db6ad8fa7d0dc8446934f0d18a2a590021068
size 4269 size 4267

BIN
Assets/JAY/Character Test Scene.unity (Stored with Git LFS)

Binary file not shown.

View File

@ -2,60 +2,104 @@ using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using UnityEngine; using UnityEngine;
public enum PlayerState { None, Idle, Move, Attack, Hit, Dead }
public class PlayerController : CharacterBase public class PlayerController : CharacterBase
{ {
// 외부 접근 가능 변수 // 외부 접근 가능 변수
[Header("플레이어 관련")] [Header("Movement")]
public VariableJoystick joystick;
public Animator PlayerAnimator { get; private set; }
[SerializeField] private float rotationSpeed = 10f; [SerializeField] private float rotationSpeed = 10f;
[Header("Attach Points")]
[SerializeField] private Transform rightHandTransform;
[SerializeField] private Transform headTransform;
// 내부에서만 사용하는 변수 // 내부에서만 사용하는 변수
private CharacterController _characterController; private CharacterController _characterController;
private Vector3 gravityVelocity; private bool _isBattle;
private GameObject weapon;
// 상태 관련
private PlayerStateIdle _playerStateIdle;
private PlayerStateMove _playerStateMove;
// 외부에서도 사용하는 변수
public VariableJoystick joystick { get; private set; }
public PlayerState CurrentState { get; private set; }
private Dictionary<PlayerState, IPlayerState> _playerStates;
public Animator PlayerAnimator { get; private set; }
public CharacterController CharacterController => _characterController;
private void Awake() private void Awake()
{ {
PlayerAnimator = GetComponent<Animator>(); PlayerAnimator = GetComponent<Animator>();
_characterController = GetComponent<CharacterController>(); _characterController = GetComponent<CharacterController>();
if (joystick == null)
{
joystick = FindObjectOfType<VariableJoystick>();
}
}
private void Start()
{
// 상태 초기화
_playerStateIdle = new PlayerStateIdle();
_playerStateMove = new PlayerStateMove();
_playerStates = new Dictionary<PlayerState, IPlayerState>
{
{ PlayerState.Idle, _playerStateIdle },
{ PlayerState.Move, _playerStateMove },
};
PlayerInit();
} }
private void Update() private void Update()
{ {
HandleMovement(); // 이동 처리 if (CurrentState != PlayerState.None)
{
_playerStates[CurrentState].Update();
}
} }
#region #region
private void HandleMovement() private void PlayerInit()
{ {
float x = joystick.Horizontal; SetState(PlayerState.Idle);
float z = joystick.Vertical;
Vector3 moveDir = new Vector3(x, 0, z); InstantiateWeapon();
Vector3 move = moveDir.normalized * moveSpeed; weapon.SetActive(_isBattle);
// 회전
if (moveDir.magnitude > 0.1f)
{
Quaternion toRotation = Quaternion.LookRotation(moveDir, Vector3.up);
transform.rotation = Quaternion.Slerp(transform.rotation, toRotation, Time.deltaTime * 10f);
}
// 중력 처리
if (_characterController.isGrounded && gravityVelocity.y < 0)
{
gravityVelocity.y = -0.1f;
}
gravityVelocity.y += gravity * Time.deltaTime;
Vector3 finalMove = (move + gravityVelocity) * Time.deltaTime;
_characterController.Move(finalMove);
PlayerAnimator.SetFloat("Move", _characterController.velocity.magnitude);
} }
private void InstantiateWeapon()
{
if (weapon == null)
{
GameObject weaponObject = Resources.Load<GameObject>("Player/Weapon/Chopstick");
weapon = Instantiate(weaponObject, rightHandTransform);
// .GetComponent<WeaponController>();
}
}
#endregion #endregion
public void SetState(PlayerState state)
{
if (CurrentState != PlayerState.None)
{
_playerStates[CurrentState].Exit();
}
CurrentState = state;
_playerStates[CurrentState].Enter(this);
}
public void SwitchBattleMode()
{
_isBattle = !_isBattle;
weapon.SetActive(_isBattle);
}
} }

View File

@ -0,0 +1,71 @@
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
[CustomEditor(typeof(PlayerController))]
public class PlayerControllerEditor : Editor
{
public override void OnInspectorGUI()
{
// 기본 인스펙터를 그리기
base.OnInspectorGUI();
// 타겟 컴포넌트 참조 가져오기
PlayerController playerController = (PlayerController)target;
// 여백 추가
EditorGUILayout.Space();
EditorGUILayout.LabelField("상태 디버그 정보", EditorStyles.boldLabel);
EditorGUILayout.BeginVertical(EditorStyles.helpBox);
EditorGUILayout.LabelField("현재 상태", playerController.CurrentState.ToString(),
EditorStyles.boldLabel);
EditorGUILayout.EndVertical();
// 지면 접촉 상태
GUI.backgroundColor = Color.white;
EditorGUILayout.Space();
EditorGUILayout.LabelField("캐릭터 위치 디버그 정보", EditorStyles.boldLabel);
// GUI.enabled = false;
// EditorGUILayout.Toggle("지면 접촉", playerController.IsGrounded);
// GUI.enabled = true;
// 강제로 상태 변경 버튼
EditorGUILayout.BeginHorizontal();
if (GUILayout.Button("Idle"))
playerController.SetState(PlayerState.Idle);
if (GUILayout.Button("Move"))
playerController.SetState(PlayerState.Move);
if (GUILayout.Button("BattleMode"))
playerController.SwitchBattleMode();
// if (GUILayout.Button("Attack"))
// playerController.SetState(PlayerState.Attack);
// if (GUILayout.Button("Hit"))
// playerController.SetState(PlayerState.Hit);
// if (GUILayout.Button("Dead"))
// playerController.SetState(PlayerState.Dead);
EditorGUILayout.EndHorizontal();
}
private void OnEnable()
{
EditorApplication.update += OnEditorUpdate;
}
private void OnDisable()
{
EditorApplication.update -= OnEditorUpdate;
}
private void OnEditorUpdate()
{
if (target != null)
Repaint();
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: b0b2ffd1e9824f71ac899076fa692425
timeCreated: 1744940250

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: a4bf902c969a48439357a75159718385
timeCreated: 1744942105

View File

@ -0,0 +1,9 @@
public interface IPlayerState
{
// 해당 상태로 진입했을 때 호출되는 메서드
void Enter(PlayerController playerController);
// 해당 상태에 머물러 있을 때 Update 주기로 호출되는 메서드
void Update();
// 해당 상태에서 빠져 나갈 때 호출되는 메서드
void Exit();
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 80d0d284b37a49eeb7376c3b07207f0c
timeCreated: 1744941077

View File

@ -0,0 +1,30 @@
using UnityEngine;
public class PlayerStateIdle : MonoBehaviour, IPlayerState
{
private PlayerController _playerController;
public void Enter(PlayerController playerController)
{
_playerController = playerController;
// _playerController.Animator.SetBool("Idle", true);
}
public void Update()
{
float inputHorizontal = _playerController.joystick.Horizontal;
float inputVertical = _playerController.joystick.Vertical;
// 이동
if (inputHorizontal != 0 || inputVertical != 0)
{
_playerController.SetState(PlayerState.Move);
return;
}
}
public void Exit()
{
_playerController = null;
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 9da273f1a9ed4537b36c546a1c9cc390
timeCreated: 1744942131

View File

@ -0,0 +1,66 @@
using UnityEngine;
public class PlayerStateMove : MonoBehaviour, IPlayerState
{
private static readonly int Move = Animator.StringToHash("Move");
private PlayerController _playerController;
private Vector3 _gravityVelocity;
public void Enter(PlayerController playerController)
{
_playerController = playerController;
_playerController.PlayerAnimator.SetBool(Move, true);
}
public void Update()
{
float inputHorizontal = _playerController.joystick.Horizontal;
float inputVertical = _playerController.joystick.Vertical;
// 이동
if (inputHorizontal != 0 || inputVertical != 0)
{
HandleMovement();
return;
}
else
{
_playerController.SetState(PlayerState.Idle);
}
}
public void Exit()
{
_playerController.PlayerAnimator.SetBool(Move, false);
_playerController = null;
}
private void HandleMovement()
{
float inputHorizontal = _playerController.joystick.Horizontal;
float inputVertical = _playerController.joystick.Vertical;
Vector3 moveDir = new Vector3(inputHorizontal, 0, inputVertical);
Vector3 move = moveDir.normalized * _playerController.moveSpeed;
// 회전
if (moveDir.magnitude > 0.1f)
{
Quaternion toRotation = Quaternion.LookRotation(moveDir, Vector3.up);
_playerController.transform.rotation = Quaternion.Slerp(_playerController.transform.rotation, toRotation, Time.deltaTime * 10f);
}
// 중력 처리
if (_playerController.CharacterController.isGrounded && _gravityVelocity.y < 0)
{
_gravityVelocity.y = -0.1f;
}
_gravityVelocity.y += _playerController.gravity * Time.deltaTime;
Vector3 finalMove = (move + _gravityVelocity) * Time.deltaTime;
_playerController.CharacterController.Move(finalMove);
// _playerController.PlayerAnimator.SetFloat("Move", _playerController.CharacterController.velocity.magnitude);
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 1399a67446d14e10bbee938def76d41a
timeCreated: 1744942268

BIN
Assets/Prefabs/Player.prefab (Stored with Git LFS) Normal file

Binary file not shown.

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: b2775e44f9b29414faf17cc5025f9478
PrefabImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

8
Assets/Resources.meta Normal file
View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: efccde2839c637a42809d0fd5f3c1076
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 82aa723a5da5571418a09a8f1878011d
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 6f2f1e17292ba234781708b9b427c3dc
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

BIN
Assets/Resources/Player/Weapon/Chopstick.prefab (Stored with Git LFS) Normal file

Binary file not shown.

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 5a4adbb52d0166745b4b6344ac5191e7
PrefabImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant: