2024.01.23, 24 최종프로젝트 Player & Animation 트러블 슈팅

2024. 1. 24. 21:09카테고리 없음

1. Player 관련해서 에쎗이 갑자기 사라져서 새로 에쎗을 추가했다.

2. Player Input 컴포넌트에 Invoke Unity Events 의 연결을 추가했다.

3. 플레이어 애니메이션을 추가했다. FSM 방식으로 애니메이션을 초기에 설정을 했었는데, 이번에는 Character Controller 사용대신 Rigidbody 와 Collider 를 사용한 플레이어를 만들어서 새로운 애니메이션 컨트롤러를 생성했다.

bool 파라미터를 사용하여 애니메이션 트랜지션을 연결해주었고, PlayerController 스크립트에 애니메이션 컴포넌트와, 실행함수를 추가해주었다.

using System;
using System.Collections;
using System.Collections.Generic;
using System.Dynamic;
using UnityEditor.Build;
using UnityEngine;
using UnityEngine.InputSystem;
public class PlayerController : MonoBehaviour
{
    private Animator animator; //애니메이터 추가

    public float baseSpeed = 5f; //기본 속도
    public float currentSpeed; //현재 속도
    [Header("Movement")]
    public float moveSpeed;
    private Vector2 curMovementInput;
    public float jumpForce;
    public LayerMask groundLayerMask;
    [Header("Look")]
    public Transform cameraContainer;
    public float minXLook;
    public float maxXLook;
    private float camCurXRot;
    public float lookSensitivity;
    private Vector2 mouseDelta;
    [HideInInspector]
    public bool canLook = true;
    private Rigidbody _rigidbody;
    public static PlayerController instance;
    private void Awake()
    {
        instance = this;
        _rigidbody = GetComponent<Rigidbody>();
        animator = GetComponent<Animator>(); //애니메이터 컴포넌트 추가
    }
    void Start()
    {
        Cursor.lockState = CursorLockMode.Locked;
        currentSpeed = baseSpeed; //속도
    }
    public void ApplySpeedPotion(float SpeedUp)   //속도
    {
        currentSpeed += SpeedUp;
    }
    public void ResetSpeed()    //속도
    {
        currentSpeed = baseSpeed;
    }
    private void FixedUpdate()
    {
        Move();
    }
    private void LateUpdate()
    {
        if (canLook)
        {
            CameraLook();
        }
    }
    private void Move()
    {
        Vector3 dir = transform.forward * curMovementInput.y + transform.right * curMovementInput.x;
        dir *= moveSpeed;
        dir.y = _rigidbody.velocity.y;
        _rigidbody.velocity = dir;

        
    }
    void CameraLook()
    {
        camCurXRot += mouseDelta.y * lookSensitivity;
        camCurXRot = Mathf.Clamp(camCurXRot, minXLook, maxXLook);
        cameraContainer.localEulerAngles = new Vector3(-camCurXRot, 0, 0);
        transform.eulerAngles += new Vector3(0, mouseDelta.x * lookSensitivity, 0);
    }
    public void OnLookInput(InputAction.CallbackContext context)
    {
        mouseDelta = context.ReadValue<Vector2>();
    }
    public void OnMoveInput(InputAction.CallbackContext context)
    {
        if (context.phase == InputActionPhase.Performed)
        {
            curMovementInput = context.ReadValue<Vector2>();
            animator.SetBool("Walk", true); //MoveInput이 실행될 때 Walk 애니메이션의 bool을 true로 바꾼다.
        }
        else if (context.phase == InputActionPhase.Canceled)
        {
            curMovementInput = Vector2.zero;
            animator.SetBool("Walk", false);
        }
    }
    public void OnJumpInput(InputAction.CallbackContext context)
    {
        if (context.phase == InputActionPhase.Started)
        {
            if (IsGrounded())
                _rigidbody.AddForce(Vector2.up * jumpForce, ForceMode.Impulse);
        }
    }
    private bool IsGrounded()
    {
        Ray[] rays = new Ray[4]
        {
            new Ray(transform.position + (transform.forward * 0.2f) + (Vector3.up * 0.01f) , Vector3.down),
            new Ray(transform.position + (-transform.forward * 0.2f)+ (Vector3.up * 0.01f), Vector3.down),
            new Ray(transform.position + (transform.right * 0.2f) + (Vector3.up * 0.01f), Vector3.down),
            new Ray(transform.position + (-transform.right * 0.2f) + (Vector3.up * 0.01f), Vector3.down),
        };
        for (int i = 0; i < rays.Length; i++)
        {
            if (Physics.Raycast(rays[i], 0.1f, groundLayerMask))
            {
                return true;
            }
        }
        return false;
    }
    private void OnDrawGizmos()
    {
        Gizmos.color = Color.red;
        Gizmos.DrawRay(transform.position + (transform.forward * 0.2f), Vector3.down);
        Gizmos.DrawRay(transform.position + (-transform.forward * 0.2f), Vector3.down);
        Gizmos.DrawRay(transform.position + (transform.right * 0.2f), Vector3.down);
        Gizmos.DrawRay(transform.position + (-transform.right * 0.2f), Vector3.down);
    }
    public void ToggleCursor(bool toggle)
    {
        Cursor.lockState = toggle ? CursorLockMode.None : CursorLockMode.Locked;
        canLook = !toggle;
    }
}

전투나, 장애물 넘는 과정에서 FSM 방식으로 애니메이션을 기획하면 연계되는 게 더욱 깔끔한 것 같은데, 아직 이해를 완전히 하지 못해서 응용하는 부분에서 애로사항을 겪는 것 같다.

 

FSM 방식에서는 Player 오브젝트의 하위 prefabs 모델에 있는 캐릭터에 애니메이터를 적용해주었는데, 새로 만든 NewPlayer의 경우 Animator 컴포넌트를 NewPlayer 오브젝트 자체에 적용을 해준 뒤 Avatar를 추가해서 애니메이션을 만들었다.

 

다양한 방법들이 있겠지만 아직까지 활용하는 부분은 어렵게만 느껴진다.

 

애자일 방식으로 게임의 한 싸이클을 진행하기 위한 준비는 거의 끝나가는 것 같다.

 

몬스터 or 적을 구현하여 플레이어를 따라오게 하는 Chasing 부분만 잘 해결하면 기획했던 내용들은 어느정도 갖췄다고 생각한다.

 

24일 수요일에 기술면접도 진행을 해보았는데, 머리속에 있는 내용들을 말로써 논리정연하게 설명하는 것이 수월하지 않는 걸 보니 아직 이론에 대한 내용들도 정리가 더 된 것 같다.

 

면접에서 꼬리질문으로 계속해서 질문이 이어졌는데, struct vs class 에 대한 차이를 설명하고 -> 값형식 vs 참조형식 -> 스택방식 vs 힙방식 -> 가비지컬렉터로 이어졌다.

 

세부적인 내용까지 잘 이해하기 위해서 더욱 공부를 해야겠다.