상세 컨텐츠

본문 제목

메모장1

카테고리 없음

by MJ_119 2025. 1. 14. 01:31

본문

PlayerMove 스크립트

- 경사면을 내려갈때 땅 체크가 간헐적으로 됐다 안됐다 하는 문제 발생.

- isGround 값이 체크가 잘 안되는 문제.

- isGround 상태가 true일때 ySpeed 값을 건드린게 문제.

해결 : 땅에 닿았을때 ySpeed값 설정하는 코드를 없애버리면 자연스럽게 땅 체크가 잘 됨.

isGrounded = characterController.isGrounded;

 

 

 

using Cinemachine;
using System;
using UnityEngine;
using UnityEngine.UI;

public class PlayerMove : MonoBehaviour
{
    CharacterController characterController;
    Player player;
    PlayerController controller;
    Animator animator;
    public CinemachineVirtualCamera virtualCamera; // 캐릭터 줌 카메라

    public Vector2 moveInput { get; private set; }
    public float walkSpeed = 4f;
    public float runSpeed = 7f;
    public float rotationSpeed = 5f;
    public float jumpSpeed = 5f;


    [Header("Mouse Zoom")]
    float zoomValue;
    public float zoomSpeed = 3f;
    public float minFOV = 16;
    public float maxFOV = 60;

    [Header("Ground Check")]
    public LayerMask groundMask;
    public bool isGrounded;
    float ySpeed;

    Vector3 movementDirection;
    float verticalVelocity;
    float speed;
    float xVelocity;
    float yVelocity;
    bool isRunning = false;
    bool isJumping;
    bool isCombat;

    // 입력 시간을 저장하는 변수
    private float lastTapTimeW = 0f;
    private float lastTapTimeA = 0f;
    private float lastTapTimeS = 0f;
    private float lastTapTimeD = 0f;

    // 더블탭을 감지할 시간 간격
    public float doubleTapTime = 0.3f;

    private void Awake()
    {

    }

    void Start()
    {
        characterController = GetComponent<CharacterController>();
        player = GetComponent<Player>();
        controller = player.playerController;
        animator = GetComponentInChildren<Animator>();

        speed = walkSpeed;
        isCombat = false;

        controller.Character.Move.performed += context =>
        {
            moveInput = context.ReadValue<Vector2>();
            Run(); // 입력이 발생할 때마다 더블탭 감지
        };

        controller.Character.Move.canceled += context =>
        {
            moveInput = Vector2.zero;
            isRunning = false;
            speed = walkSpeed; // 걷기 속도로 복귀
            animator.SetBool("isRunning", isRunning);
        };

        controller.Character.Jump.performed += context =>
        {
            Jump();
        };

        controller.Character.Combat.performed += context =>
        {
            isCombat = !isCombat;
            animator.SetBool("IsCombat", isCombat);
        };

        controller.Character.Zoom.performed += context =>
        {
            //zoomValue = Mathf.Sign(context.ReadValue<float>());
            zoomValue = context.ReadValue<float>();
        };
    }

    void Update()
    {
        Move();
        CameraZoom();
    }

    private void CameraZoom()
    {
        if(zoomValue != 0 && virtualCamera != null)
        {
            float currentFOV = virtualCamera.m_Lens.FieldOfView;
            currentFOV -= zoomValue * 0.01f * zoomSpeed ;
            currentFOV = Mathf.Clamp(currentFOV, minFOV, maxFOV);
            virtualCamera.m_Lens.FieldOfView = currentFOV;
            
            zoomValue = 0; // 마우스 휠 한번 움직인 뒤, 휠 움직임값 0으로 초기화
        }
    }

    private void Jump()
    {
        //ySpeed = jumpSpeed;
        if (isGrounded) // 착지 상태일 때만 점프 가능
        {
            isJumping = true; // 다음 프레임에서 점프 요청
        }
    }

    private void Move()
    {
        ApplyMovement();
    }

    private void Run()
    {
        if (moveInput.y > 0 && Mathf.Abs(moveInput.x) == 0) // W 키 입력 감지
        {
            if (!isRunning && Time.time - lastTapTimeW < doubleTapTime)
            {
                // 더블탭 감지됨 => 달리기 전환
                isRunning = true;
                speed = runSpeed;
                animator.SetBool("isRunning", true);
                print("double click");
            }
            lastTapTimeW = Time.time; // 마지막 입력 시간 갱신
        }
        else if (moveInput.y < 0 && Mathf.Abs(moveInput.x) == 0) // S 키 더블탭 감지
        {
            if (!isRunning && Time.time - lastTapTimeS < doubleTapTime)
            {
                isRunning = true;
                speed = runSpeed;
                animator.SetBool("isRunning", true);
            }
            lastTapTimeS = Time.time;
        }
        else if (moveInput.x > 0 && Mathf.Abs(moveInput.y) == 0) // D 키 더블탭 감지
        {
            if (!isRunning && Time.time - lastTapTimeD < doubleTapTime)
            {
                isRunning = true;
                speed = runSpeed;
                animator.SetBool("isRunning", true);
            }
            lastTapTimeD = Time.time;
        }
        else if (moveInput.x < 0 && Mathf.Abs(moveInput.y) == 0) // A 키 더블탭 감지
        {
            if (!isRunning && Time.time - lastTapTimeA < doubleTapTime)
            {
                isRunning = true;
                speed = runSpeed;
                animator.SetBool("isRunning", true);
            }
            lastTapTimeA = Time.time;
        }
    }


    private void ApplyMovement()
    {
        if (TimeManager.instance.gameOver)
            return;

        // 시네머신 가상카메라의 Transform에서 forward 방향 가져오기
        Transform cameraTransform = virtualCamera.VirtualCameraGameObject.transform;
        Vector3 cameraForward = cameraTransform.forward;
        Vector3 cameraRight = cameraTransform.right;

        // 수직 방향은 제외하고 카메라가 바라보는 평면 방향만 가져옴
        cameraForward.y = 0;
        cameraRight.y = 0;

        cameraForward.Normalize();
        cameraRight.Normalize();

        // 중력 적용
        ApplyGravity();

        // 입력을 카메라 기준으로 변환
        Vector3 moveDirection = cameraForward * moveInput.y + cameraRight * moveInput.x;

        //if (moveDirection.magnitude > 0)
        //{
        //    // 캐릭터 회전
        //    Quaternion targetRotation = Quaternion.LookRotation(moveDirection);
        //    transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, Time.deltaTime * rotationSpeed);
        //}

        // 여기서부터 수정된 부분
        if (moveDirection.magnitude > 0)
        {
            RaycastHit hit;
            // 현재 위치에서 아래로 레이캐스트를 쏴서 경사면 감지
            if (Physics.Raycast(transform.position + Vector3.up * 0.1f, Vector3.down, out hit, 1f, groundMask))
            {
                // 이동 방향을 경사면의 normal 벡터를 기준으로 투영
                moveDirection = Vector3.ProjectOnPlane(moveDirection, hit.normal).normalized;
            }

            // 캐릭터 회전
            Quaternion targetRotation = Quaternion.LookRotation(moveDirection);
            transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, Time.deltaTime * rotationSpeed);
        }

        // 캐릭터 이동
        Vector3 velocity = moveDirection * speed;

        velocity.y = ySpeed;

        characterController.Move(velocity * Time.deltaTime);

        animator.SetFloat("move", moveDirection.magnitude);
        animator.SetFloat("X", moveInput.x, 0.1f, Time.deltaTime);
        animator.SetFloat("Y", moveInput.y, 0.1f, Time.deltaTime);
    }

    private void ApplyGravity()
    {
        // 캐릭터가 땅에 닿았는지 확인
        isGrounded = characterController.isGrounded;
        //isGrounded = Physics.CheckSphere(transform.position, 0.3f, groundMask);
        //isGrounded = Physics.Raycast(transform.position + new Vector3(0, 0.02f, 0), Vector3.down, 0.04f, groundMask);
        //Debug.DrawRay(transform.position + new Vector3(0 ,0.02f, 0), Vector3.down * 0.04f, isGrounded ? Color.green : Color.red);

        if (isGrounded)
        {
            if(ySpeed < 0)
            {
                // 착지 시 수직 속도를 리셋
                ySpeed = -0.1f; // 아주 작은 음수 값으로 유지
                animator.SetBool("isGrounded", true);
                animator.SetBool("isJumping", false);
                animator.SetBool("isFalling", false);
            }

            // 점프 기능
            if(isJumping)
            {
                ySpeed = jumpSpeed; // 점프 속도 적용
                isJumping = false;  // 점프 요청 초기화

                animator.SetBool("isGrounded", false);
                animator.SetBool("isJumping", true);
                animator.SetBool("isFalling", true);
            }
        }
        else
        {
            // 착지하지 않았을 때 중력 적용
            ySpeed -= 9.81f * Time.deltaTime;
        }
        
    }
    //void OnDrawGizmos()
    //{
    //    // 체크하는 구체를 시각화
    //    Gizmos.color = isGrounded ? Color.green : Color.red;
    //    Gizmos.DrawWireSphere(transform.position, 0.32f);
    //}