Unity

수업 내용 복습 1

psb08 2025. 3. 9. 14:48
728x90
반응형

학교 수업 시간에 배운 내용을 복습하기 위해 수업시간에 만든 것을 다시 만들었습니다.

 

Input System으로 간단하게 탑 뷰 캐릭터 이동을 만들었습니다.

Input System은 1학년 때 배웠으며, 3D로 만들었다는 점과 유니티 6로 했다는 것을 빼면 거의 비슷했습니다.

 

먼저 Cinemachine과 DoTween을 다운 받았습니다.

카메라를 탑 뷰처럼 설정한 뒤, 플레이어를 만들었습니다.

플레이어에 3D에서 Rigidbody 대신 쓸 수 있는 Character Controller를 사용했습니다.

 

Character Controller에서

Slop Limit --> 일정 각도 이상 이동하지 못하게 합니다. 예를 들어 지금처럼 45라면 오르막길의 각도가 45도 이상이라면 이동할 수 없습니다.

Step Offset --> 이 값보다 계단이 땅에 더 가깝다면 계단을 오를 수 있게 해줍니다.

 

그 다음으로 Follow Cam을 만든 뒤, 설정했습니다.

그 다음 Input Actions을 만든 뒤,

설정했습니다.

Actions를 Generate C# Class 한 뒤,

 

PlayerInputSO, Player, CharacterMovement를 만들었습니다.

 

수업에서는 점프와 Sprint를 만들지 않았지만, 저는 추가 해보았습니다.

 

PlayerInputSO.cs

using System;
using UnityEngine;
using UnityEngine.InputSystem;

namespace TopDownView.Player
{
    [CreateAssetMenu(fileName = "PlayerInput", menuName = "SO/PlayerInput", order = 0)]
    public class PlayerInputSO : ScriptableObject, Controls.IPlayerActions
    {
        public event Action<Vector2> OnMovementChange;
        public event Action OnAttackPressed;
        public event Action OnJumpPressed;
        public event Action OnRunPressed;

        private Controls _controls;

        private void OnEnable()
        {
            if (_controls == null)
            {
                _controls = new Controls();
                _controls.Player.SetCallbacks(this);
            }
            _controls.Player.Enable();
        }

        private void OnDisable()
        {
            _controls.Player.Disable();
        }

        public void OnMove(InputAction.CallbackContext context)
        {
            Vector2 input = context.ReadValue<Vector2>();
            OnMovementChange?.Invoke(input);
        }

        public void OnAttack(InputAction.CallbackContext context)
        {
            if (context.performed)
                OnAttackPressed?.Invoke();
        }

        public void OnJump(InputAction.CallbackContext context)
        {
            if (context.performed)
                OnJumpPressed?.Invoke();
        }

        public void OnSprint(InputAction.CallbackContext context)
        {
            if (context.performed)
                OnRunPressed?.Invoke();
        }

    }
}

CharacterMovement.cs

using UnityEngine;

namespace TopDownView.Player
{
    public class CharacterMovement1 : MonoBehaviour
    {
        [SerializeField] private float moveSpeed = 8f;
        [SerializeField] private float sprintSpeed = 1.5f;
        [SerializeField] private float gravity = -9.8f;
        [SerializeField] private float jumpHeight = 1f;
        [SerializeField] private CharacterController controller;
        [SerializeField] private Transform parent;

        public bool IsGrounded => controller.isGrounded;

        private Vector3 _velocity;
        public Vector3 Velocity => _velocity;
        private float _verticalVelocity;
        private Vector3 _movementDirection;
        private bool _isSprint;

        public void SetMovementDirection(Vector2 movementInput)
        {
            _movementDirection = new Vector3(movementInput.x, 0, movementInput.y).normalized;
        }

        public void SetSprint(bool isSprinting)
        {
            _isSprint = isSprinting;
        }

        public void Jump()
        {
            if (IsGrounded)
                _verticalVelocity = Mathf.Sqrt(jumpHeight * -1f * gravity);
        }

        private void FixedUpdate()
        {
            CalculateMovement();
            ApplyGravity();
            Move();
        }

        private void CalculateMovement()
        {
            float currentSpeed = _isSprint ? moveSpeed * sprintSpeed : moveSpeed;
            _velocity = Quaternion.Euler(0, -45f, 0) * _movementDirection;
            _velocity *= currentSpeed * Time.fixedDeltaTime;

            if (_velocity.magnitude > 0)
            {
                Quaternion targetRot = Quaternion.LookRotation(_velocity);
                float rotationSpeed = 8f;
                parent.rotation = Quaternion.Lerp(parent.rotation, targetRot, Time.fixedDeltaTime * rotationSpeed);
            }
        }

        private void ApplyGravity()
        {
            if (IsGrounded && _verticalVelocity < 0)
            {
                _verticalVelocity = -0.03f;
            }
            else
                _verticalVelocity += gravity * Time.fixedDeltaTime;

            _velocity.y = _verticalVelocity;
        }

        private void Move()
        {
            controller.Move(_velocity);
        }


    }
}

Player.cs

using TMPro;
using UnityEngine;


namespace TopDownView.Player
{
    public class Player1 : MonoBehaviour
    {
        [SerializeField] private CharacterMovement1 movement;
        [SerializeField] private PlayerInputSO playerInput;
        [SerializeField] private TextMeshProUGUI sprintTxt;
        private bool isSprinted = false;

        private void Start()
        {
            sprintTxt.text = "Walk";
        }

        private void Awake()
        {
            playerInput.OnMovementChange += HandleMovementChange;
            playerInput.OnJumpPressed += HandleJumpPressed;
            playerInput.OnRunPressed += HandleRunPressed;
            playerInput.OnAttackPressed += HandleAttackPressed;
        }

        private void OnDestroy()
        {
            playerInput.OnMovementChange -= HandleMovementChange;
            playerInput.OnJumpPressed -= HandleJumpPressed;
            playerInput.OnRunPressed -= HandleRunPressed;
            playerInput.OnAttackPressed -= HandleAttackPressed;
        }

        private void HandleMovementChange(Vector2 movementnput)
        {
            movement.SetMovementDirection(movementnput);
        }

        private void HandleJumpPressed()
        {
            movement.Jump();
        }

        public void HandleRunPressed()
        {
            isSprinted = !isSprinted;
            if (isSprinted)
            {
                movement.SetSprint(true);
                sprintTxt.text = "Running";
            }
            else
            {
                movement.SetSprint(false);
                sprintTxt.text = "Walk";
            }
        }

        private void HandleAttackPressed()
        {
            Debug.Log("Attack!");
        }


    }
}

Run 메서드를 Public으로 만든 뒤, 버튼을 누르면 사용할 수 있도록 했습니다.

 

버튼을 누르거나 Shift를 누르면 걷기, 달리기 상태가 변경 됩니다.

걷기 상태이면 위에 Walk 라고 뜨며, 달리기 상태이면 위에 Running이라고 뜹니다.

 

Space를 누르면 점프 합니다.

 

'Unity' 카테고리의 다른 글

수업 내용 복습 3  (0) 2025.03.16
수업 내용 복습 2  (0) 2025.03.10
3D 테스트 프로젝트 15  (0) 2025.03.08
3D 테스트 프로젝트 14  (0) 2025.03.07
3D 테스트 프로젝트 13  (0) 2025.03.06