using UnityEngine; using UnityEngine.InputSystem; using Unity.Netcode; using Colosseum.Network; using Colosseum.Skills; namespace Colosseum.Player { /// /// 3인칭 플레이어 이동 (네트워크 동기화) /// [RequireComponent(typeof(CharacterController))] public class PlayerMovement : NetworkBehaviour { [Header("Movement Settings")] [SerializeField] private float moveSpeed = 5f; [SerializeField] private float rotationSpeed = 10f; [SerializeField] private float gravity = -9.81f; [Header("Jump Settings")] [SerializeField] private float jumpForce = 5f; [Header("References")] [SerializeField] private SkillController skillController; private CharacterController characterController; private Vector3 velocity; private Vector2 moveInput; private InputSystem_Actions inputActions; private bool isJumping; private bool wasGrounded; /// /// 현재 이동 속도 (애니메이션용) /// public float CurrentMoveSpeed => moveInput.magnitude * moveSpeed; /// /// 현재 지면 접촉 상태 /// public bool IsGrounded => characterController != null ? characterController.isGrounded : false; /// /// 점프 중 상태 /// public bool IsJumping => isJumping; public override void OnNetworkSpawn() { // 로컬 플레이어가 아니면 입력 비활성화 if (!IsOwner) { enabled = false; return; } characterController = GetComponent(); // SkillController 참조 if (skillController == null) { skillController = GetComponent(); } // 스폰 포인트에서 위치 설정 SetSpawnPosition(); // Input Actions 초기화 inputActions = new InputSystem_Actions(); inputActions.Player.Enable(); // Move 액션 콜백 등록 inputActions.Player.Move.performed += OnMovePerformed; inputActions.Player.Move.canceled += OnMoveCanceled; // Jump 액션 콜백 등록 inputActions.Player.Jump.performed += OnJumpPerformed; // 카메라 설정 SetupCamera(); } /// /// 스폰 위치 설정 /// private void SetSpawnPosition() { Transform spawnPoint = PlayerSpawnPoint.GetRandomSpawnPoint(); if (spawnPoint != null) { // CharacterController 비활성화 후 위치 설정 (충돌 문제 방지) characterController.enabled = false; transform.position = spawnPoint.position; transform.rotation = spawnPoint.rotation; characterController.enabled = true; } } /// /// 네트워크 정리리 /// public override void OnNetworkDespawn() { if (inputActions != null) { inputActions.Player.Move.performed -= OnMovePerformed; inputActions.Player.Move.canceled -= OnMoveCanceled; inputActions.Player.Jump.performed -= OnJumpPerformed; inputActions.Disable(); } } private void OnMovePerformed(InputAction.CallbackContext context) { moveInput = context.ReadValue(); } private void OnMoveCanceled(InputAction.CallbackContext context) { moveInput = Vector2.zero; } private void OnJumpPerformed(InputAction.CallbackContext context) { if (!isJumping && characterController.isGrounded) { Jump(); } } private void SetupCamera() { var cameraController = GetComponent(); if (cameraController == null) { cameraController = gameObject.AddComponent(); } cameraController.Initialize(transform, inputActions); } private void Update() { if (!IsOwner) return; ApplyGravity(); Move(); } private void ApplyGravity() { if (wasGrounded && velocity.y < 0) { velocity.y = -2f; } else { velocity.y += gravity * Time.deltaTime; } } private void Move() { if (characterController == null) return; // 스킬 애니메이션 재생 중에는 이동 불가 if (skillController != null && skillController.IsPlayingAnimation) { // 중력만 적용 characterController.Move(velocity * Time.deltaTime); return; } // 이동 방향 계산 (카메라 기준) Vector3 moveDirection = new Vector3(moveInput.x, 0f, moveInput.y); moveDirection = TransformDirectionByCamera(moveDirection); moveDirection.Normalize(); // 이동 적용 Vector3 moveVector = moveDirection * moveSpeed * Time.deltaTime; characterController.Move(moveVector + velocity * Time.deltaTime); // 회전 (이동 중일 때만) if (moveDirection != Vector3.zero) { Quaternion targetRotation = Quaternion.LookRotation(moveDirection); transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, rotationSpeed * Time.deltaTime); } // 착지 체크 (Move 후에 isGrounded가 업데이트됨) if (!wasGrounded && characterController.isGrounded && isJumping) { OnJumpEnd(); } // 다음 프레임을 위해 현재 상태 저장 wasGrounded = characterController.isGrounded; } private void Jump() { isJumping = true; velocity.y = jumpForce; // 애니메이션 컨트롤러에 점프 알림 var animController = GetComponent(); if (animController != null) { animController.PlayJump(); } } /// /// 점프 중 상태가 끝나면 IsJumping = false; /// public void OnJumpEnd() { isJumping = false; } private Vector3 TransformDirectionByCamera(Vector3 direction) { if (Camera.main == null) return direction; Transform cameraTransform = Camera.main.transform; Vector3 cameraForward = cameraTransform.forward; Vector3 cameraRight = cameraTransform.right; // Y축 제거 cameraForward.y = 0f; cameraRight.y = 0f; cameraForward.Normalize(); cameraRight.Normalize(); return cameraRight * direction.x + cameraForward * direction.z; } } }