24/06/04
사용한 오브젝트 : 3D Object -> Capsule
플레이어의 입력을 받아 동작을 수행할 오브젝트를 만들어줍니다.
사용한 오브젝트 : 3D Object -> Plane
플레이어의 움직임을 테스트할 지면을 임시로 만들어줍니다.
(그냥 만들면 가시성이 떨어지고 이동을 테스트하기에 면적이 좁기 때문에 색과 크기를 바꿨습니다.)
키를 입력받아 오브젝트를 이동 시키기 위해 유니티에서 지원하는 Input System패키지를 설치합니다.
나머지 키입력은 Path를 선택하고 각 방향에 맞는 Key를 지정 그리고 상단의 Save Asset을 눌러 저장해줍니다.Input System설치가 다 끝났다면 위 처럼 Project창에 InputActions 파일을 하나 생성하고 Action Maps, Actions 세팅을 해줍니다.
여기서 Move와 Jump의 Action Type이 다른데 Move(이동)의 경우 키를 입력받고 있으면 지속적으로 움직이는 Value방식이고 Jump(뛰어오르기)의 경우 누르고 있는게 아니라 한번의 입력으로도 즉시 점프를 하기 위해 Button 방식으로 처리했다.
플레이어에 사용 할 스크립트를 생성 하고 컴포넌트를 추가 합니다.
using UnityEngine;
public class CharacterManager : MonoBehaviour
{
private static CharacterManager _instance; //싱글톤
public static CharacterManager Instance
{
// 반환
get
{
// 방어코드: _instance가 Null인 경우
if (_instance == null)
{
// CharacterManager를 생성
_instance = new GameObject("CharacterManager").AddComponent<CharacterManager>();
}
// _instance에 넣어주고 반환
return _instance;
}
}
public Player _player;
public Player Player
{
get { return _player; }
set { _player = value; }
}
private void Awake() // Awake 함수가 실행이 됐다면 이미 GameObject로 Script에 붙어있는 상태에서 실행이 되었다는 것.
{
if(_instance == null)
{
_instance = this; // 따라서 GameObject를 만들지 않고 나 자신을 넣는다.
DontDestroyOnLoad(gameObject); // 씬을 이동해도 정보를 파괴하지않는다.
}
else
{
if(_instance != this) // 기존에 것과 넣으려 하는 것이 다른 경우 현재 것을 파괴
{
Destroy(gameObject);
}
}
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Player : MonoBehaviour
{
public PlayerController controller;
private void Awake()
{
CharacterManager.Instance.Player = this;
controller = GetComponent<PlayerController>();
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.InputSystem;
public class PlayerController : MonoBehaviour
{
[Header("Moverment")] // 변수명 분류
public float moveSpeed; // 이동속도
public float jumpPower; // 점프력
private Vector2 curMovementInput; // 현재 입력된 키값
private Rigidbody _rigidbody;
private void Awake()
{
_rigidbody = GetComponent<Rigidbody>();
}
void Start()
{
Cursor.lockState = CursorLockMode.Locked; // 화면상의 마우스 커서 숨기기
}
// rigidbody같은 물리 연산에는 Update보다 FixedUpdate를 사용
void FixedUpdate()
{
Move();
}
private void Move()
{
// 방향 forward = 앞뒤, right = 좌우
Vector3 dir = transform.forward * curMovementInput.y + transform.right * curMovementInput.x;
dir *= moveSpeed;
dir.y = _rigidbody.velocity.y; // 점프시 위 아래로 움직이게
_rigidbody.velocity = dir;
}
public void OnMove(InputAction.CallbackContext context)
{
// 상태(분기점) == 키가 지속적으로 입력되었을 때
if(context.phase == InputActionPhase.Performed)
{
curMovementInput = context.ReadValue<Vector2>();
}
// 키가 떨어졌을때
else if(context.phase == InputActionPhase.Canceled)
{
// 멈춤
curMovementInput = Vector2.zero;
}
}
public void OnJump(InputAction.CallbackContext context)
{
// 키를 눌렀을 때 한번만 점프
if(context.phase == InputActionPhase.Started)
{
_rigidbody.AddForce(Vector2.up * jumpPower, ForceMode.Impulse);
}
}
}
Rigidbody의 Mass는 20 (낮은 점프력에도 오브젝트가 날아가는걸 방지)
Constraints의 Freeze Rotation은 X,Y,Z 체크(오브젝트가 회전하는걸 방지)
Player Input에 스크립트에서 만든 함수들을 찾아서 넣어줍니다.
Player Controller 이동속도 = 10, 점프력 = 80 으로 맞추겠습니다.
모든 적용이 끝나면 이렇게 플레이어 오브젝트가 W,A,S,D 키 입력을 받아 이동하고 Space를 눌러 점프를 하게 된다면 성공입니다.
이번 플레이어 이동을 만들어 보면서 다음에 구현 할 기능들이 막막하면서도 플레이어 이동이 무사히 잘 실행되어서 그나마 다행이라고 느꼈고 계속 반복해서 만들다보면 언젠가 능숙해 지지 않을까 싶다. 다음은 이어서 플레이어 캐릭터 에셋을 적용해보고 여러 기능을 더 추가해 보려고 한다.