학교 수업 시간에 배운 내용을 복습하기 위해 수업시간에 만든 것을 다시 만들었습니다.
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 |