Practice_Unity/Assets/Scripts/Controllers/PlayerController.cs
Seonkyu.kim 488c0858ad 작업
1. UI 버튼 작업 했음
2. 칼, 방패 따로 붙이는 작업 헀음
3. 공격 모션에 이제 버튼 연동함

Todo
1. 공격시 화면 이상하게 흔들리는거 수정할 차례
2. 히트 박스 해서 몬스터 공격하는거 연동하기
2025-09-29 17:59:40 +09:00

342 lines
9.0 KiB
C#

using System;
using System.Collections;
using System.Collections.Generic;
using Animation;
using Unity.VisualScripting;
using UnityEngine;
using UnityEngine.AI;
using UnityEngine.InputSystem;
public partial class PlayerController : MonoBehaviour
{
private AnimatorManager<AnimatorParam> _mAnimator;
private NavMeshAgent _agent;
private Rigidbody _rigidbody;
private Status_Player _status;
public Status_Player Status
{
get { return _status; }
private set { _status = value;}
}
private Vector2 _screenPos;
private Vector3 _currentVelocity;
private Vector3 _velocitySmoothDampRef;
private float _runTriggerRatio = 0.6f;
private bool _isAttack = false;
[SerializeField] private float _rotationSpeed = 10f;
[SerializeField] private Transform _weaponSocket;
[SerializeField] private Transform _shieldSocket;
// --- 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<AnimatorParam>(GetComponent<Animator>());
_agent = gameObject.GetComponent<NavMeshAgent>();
_rigidbody = gameObject.GetComponent<Rigidbody>();
_status = gameObject.GetOrAddComponent<Status_Player>();
_currentVelocity = Vector3.zero;
if(_agent != null) _agent.updateRotation = false;
}
void Start()
{
_status.Data = Manager.Data.LoadSingle<PlayerDataLoader, Data_Status_Player>("Data/PlayerData");
SetAnimator();
if (_agent != null)
{
_agent.updatePosition = false;
_agent.updateRotation = false;
}
EquipWeapon(_weaponSocket, "Prefabs/Weapon");
EquipWeapon(_shieldSocket, "Prefabs/Shield");
SubmitAction();
}
void SubmitAction()
{
Manager.Input.MoveAction -= OnMove;
Manager.Input.MoveAction += OnMove;
if (Manager.Input.Buttons != null)
{
Manager.Input.Buttons.OnAttackButtonClicked -= OnAttack;
Manager.Input.Buttons.OnAttackButtonClicked += OnAttack;
Manager.Input.Buttons.OnSkillButtonClicked -= OnSkill;
Manager.Input.Buttons.OnSkillButtonClicked += OnSkill;
}
else
{
StartCoroutine(WaitForButtonsAndSubscribe());
}
}
private IEnumerator WaitForButtonsAndSubscribe()
{
// 버튼이 생성될 때까지 대기
while (Manager.Input.Buttons == null)
{
yield return null; // 한 프레임 대기
}
// 버튼이 생성되면 이벤트 등록
Manager.Input.Buttons.OnAttackButtonClicked -= OnAttack;
Manager.Input.Buttons.OnAttackButtonClicked += OnAttack;
Manager.Input.Buttons.OnSkillButtonClicked -= OnSkill;
Manager.Input.Buttons.OnSkillButtonClicked += OnSkill;
Debug.Log("버튼 이벤트 등록 완료");
}
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);
}
}
}
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;
}
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;
}
void EquipWeapon(Transform transform, string path)
{
GameObject newParts = Manager.Resource.Instantiate($"{path}");
newParts.transform.SetParent(transform);
newParts.transform.localPosition = Vector3.zero;
newParts.transform.localRotation = Quaternion.identity;
newParts.transform.localScale = Vector3.one;
}
private void OnAttack()
{
if (!_isAttack)
{
_isAttack = true;
Behavior = PlayerBehavior.Attack;
}
}
private void OnSkill(int index)
{
}
private void OnDestroy()
{
}
}
// 애니메이션의 이벤트 함수 확인 부분 - 후에 따로 뺄 것
public partial class PlayerController {
public void Hit()
{
_mAnimator.SetValue(AnimatorParam.attack, false);
Debug.Log("Knight Hit!");
}
public void FootR()
{
}
public void FootL()
{
}
public void EnableCollider()
{
}
public void DisableCollider()
{
}
public void EndAttack()
{
if (_isAttack)
{
_isAttack = false;
_mAnimator.SetValue(AnimatorParam.attack, _isAttack);
Behavior = PlayerBehavior.Idle;
}
}
}