using System; using System.Collections.Generic; using Animation; using Unity.VisualScripting; using UnityEngine; using UnityEngine.AI; using UnityEngine.InputSystem; public partial class PlayerController : MonoBehaviour { private AnimatorManager _mAnimator; private NavMeshAgent _agent; private Rigidbody _rigidbody; private Status_Player _status; private Vector2 _screenPos; private Vector3 _currentVelocity; private Vector3 _velocitySmoothDampRef; private float _runTriggerRatio = 0.6f; [SerializeField] private float _rotationSpeed = 10f; // --- Enum 정의 --- enum AnimatorParam { speed, atk_speed, attack, run, } enum PlayerBehavior { Idle, Move, Attack, Die } // rigidbody와 NavMeshAgent를 함께 사용할 때의 물리엔진 상 문제가 생겨서 그거를 구분하기 위한 부분 // NavMeshAgent가 뇌, rigidbody가 몸 역할을 하게 됨 public enum ControlMode { Player, AI } private ControlMode _controlMode = ControlMode.Player; private PlayerBehavior _behavior = PlayerBehavior.Idle; private PlayerBehavior Behavior { get { return _behavior; } set { _behavior = value; switch (_behavior) { case PlayerBehavior.Die: case PlayerBehavior.Idle: _mAnimator.SetValue(AnimatorParam.speed, 0); break; case PlayerBehavior.Move: _mAnimator.SetValue(AnimatorParam.attack, false); break; case PlayerBehavior.Attack: _mAnimator.SetValue(AnimatorParam.attack, true); break; } } } // --- 초기화 --- private void Awake() { _mAnimator = new AnimatorManager(GetComponent()); _agent = gameObject.GetComponent(); _rigidbody = gameObject.GetComponent(); _status = gameObject.GetOrAddComponent(); _currentVelocity = Vector3.zero; if(_agent != null) _agent.updateRotation = false; } void Start() { _status.Data = Manager.Data.LoadSingle("Data/PlayerData"); Manager.Input.MoveAction -= OnMove; Manager.Input.MoveAction += OnMove; SetAnimator(); if (_agent != null) { _agent.updatePosition = false; _agent.updateRotation = false; } } void SetAnimator() { if (_status != null) { _mAnimator.SetValue(AnimatorParam.atk_speed, _status.AtkSpeed); } } // --- 매 프레임 실행 --- void Update() { if (_controlMode == ControlMode.AI) { if(_agent.pathPending || !_agent.hasPath) return; _rigidbody.linearVelocity = Vector3.zero; // 회전 if (_agent.desiredVelocity.sqrMagnitude > 0.1f) { Quaternion targetRotation = Quaternion.LookRotation(_agent.desiredVelocity.normalized); transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, Time.deltaTime * _rotationSpeed); } if (_agent.remainingDistance <= _agent.stoppingDistance) { _rigidbody.linearVelocity = Vector3.zero; SetControlMode(ControlMode.Player); } } // if (_agent != null && _movement != null) _mAnimator.SetValue(AnimatorParam.speed, _movement.GetCurrentSpeed()); // // if (_behavior == PlayerBehavior.Move) // { // if (!_movement.IsMoving()) Behavior = PlayerBehavior.Idle; // else _mAnimator.SetValue(AnimatorParam.speed, _movement.GetCurrentSpeed()); // } } private void LateUpdate() { if(_agent.enabled) _agent.nextPosition = _rigidbody.position; } public void SetControlMode(ControlMode mode) { _controlMode = mode; if (_controlMode == ControlMode.Player) if(_agent != null && _agent.isOnNavMesh) _agent.isStopped = true; } void OnInput(Define.InputEvent evt) { switch (evt) { case Define.InputEvent.Click: break; case Define.InputEvent.Down: break; case Define.InputEvent.Up: break; case Define.InputEvent.Press: break; } } public void NavigateTo(Vector3 target) { SetControlMode(ControlMode.AI); if (_agent != null) { _agent.isStopped = false; // 목적지 설정 전 에이전트가 멈춰있지 않도록 합니다. _agent.SetDestination(target); _agent.speed = _status.MoveSpeed; } } void OnMove(Vector2 direction) { SetControlMode(ControlMode.Player); float magnitude = direction.magnitude; bool isRun = direction.magnitude > _runTriggerRatio ? true : false; float speed = 0f; // 입력이 거의 없을 때 if (magnitude < 0.1f) speed = 0f; // 걷기 구간일 때 else if (magnitude <= _runTriggerRatio) speed = Mathf.Lerp(0, _status.MoveSpeed, (magnitude/_runTriggerRatio)); // 달리기 구간일 때 else { float runPercentage = (magnitude - _runTriggerRatio) / (1.0f - _runTriggerRatio); speed = Mathf.Lerp(_status.MoveSpeed, _status.MoveSpeed * 2.0f, runPercentage); } _agent.speed = speed; _mAnimator.SetValue(AnimatorParam.run, isRun); _mAnimator.SetValue(AnimatorParam.speed , speed); if (magnitude < 0.1f) { _rigidbody.linearVelocity = Vector3.zero; return; } // if (direction == Vector2.zero) // { // if (_agent != null) // { // _agent.velocity = _currentVelocity; // _agent.isStopped = true; // } // return; // } Vector3 camForward = Camera.main.transform.forward; Vector3 camRight = Camera.main.transform.right; camForward.y = 0; camRight.y = 0; camForward.Normalize(); camRight.Normalize(); Vector3 moveDir = (camForward * direction.y + camRight * direction.x).normalized; if (moveDir != Vector3.zero) { Quaternion targetRotation = Quaternion.LookRotation(moveDir); transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, _rotationSpeed * Time.deltaTime); } _rigidbody.linearVelocity = transform.forward * speed; // if (_agent != null && _status != null) // { // _agent.isStopped = false; // _agent.velocity = moveDir * speed; // _agent.velocity = transform.forward * direction.magnitude * speed; // } } private void OnDestroy() { } // void MoveCharacter(Define.InputEvent evt) // { // if(Behavior == PlayerBehavior.Die) return; // // Vector3 destination = MeasureDestination(); // // switch (evt) // { // case Define.InputEvent.Click: // case Define.InputEvent.Down: // _movement.SetDestination(destination); // Behavior = PlayerBehavior.Move; // break; // case Define.InputEvent.Press: // if (Behavior == PlayerBehavior.Move) _movement.SetDestination(destination); // break; // } // } // // Vector3 MeasureDestination() // { // RaycastHit hit; // Ray ray = Camera.main.ScreenPointToRay(_screenPos); // // int layerMask = LayerMask.GetMask("Ground"); // if (!Physics.Raycast(ray, out hit, 100.0f, layerMask)) // return Vector3.zero; // // return hit.point; // } // // void OnPoint(Vector2 point) // { // _screenPos = point; // } // // void OnMouseClicked(Define.MouseEvent evt) // { // if (Behavior == PlayerBehavior.Die) return; // // RaycastHit hit; // Ray ray = Camera.main.ScreenPointToRay(Mouse.current.position.ReadValue()); // // int layerMask = LayerMask.GetMask("Ground"); // if (!Physics.Raycast(ray, out hit, 100.0f, layerMask)) // return; // // _destPos = hit.point; // // switch (evt) // { // case Define.MouseEvent.Click: // case Define.MouseEvent.Down: // _movement.SetDestination(_destPos); // Behavior = PlayerBehavior.Move; // break; // case Define.MouseEvent.Press: // if (Behavior == PlayerBehavior.Move) _movement.SetDestination(_destPos); // break; // } // } // // void OnKeyboardInput() // { // // 키보드 입력이 필요할 경우 여기에 로직 구현 // } } // 애니메이션의 이벤트 함수 확인 부분 - 후에 따로 뺄 것 public partial class PlayerController { public void Hit() { _mAnimator.SetValue(AnimatorParam.attack, false); Debug.Log("Knight Hit!"); } public void FootR() { } public void FootL() { } }