유니티 기초 프로젝트 캐릭터 이동, 반전/ 카메라 이동 / 맵 구현
캐릭터 이동
CharacterController.cs
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CharacterController : MonoBehaviour
{
public event Action<Vector2> OnMoveEvent;
public event Action<Vector3> OnLookEvent;
public void CallMoveEvent(Vector2 direction)
{
OnMoveEvent?.Invoke(direction); //null이 아닐 경우만 실행: 캐릭터 이동
}
public void CallLookEvent(Vector2 direction)
{
OnLookEvent?.Invoke(direction); //null이 아닐 경우만 실행: 캐릭터 보는 방향 변경
}
}
PlayerInputController
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.InputSystem;
public class PlayerInputController : CharacterController
{
private Camera _camera;
private void Awake()
{
_camera = Camera.main;
}
public void OnMove(InputValue value)
{
Vector2 moveInput = value.Get<Vector2>().normalized; //대각선 이동시 속도 증가 방지
CallMoveEvent(moveInput);
}
public void OnLook(InputValue value)
{
// Debug.Log("OnLook" + value.ToString());
Vector2 newAim = value.Get<Vector2>();
Vector2 worldPos = _camera.ScreenToWorldPoint(newAim);
newAim = (worldPos - (Vector2)transform.position).normalized; //월드 포지션과 로컬 포지션에 대한 값 처리
if (newAim.magnitude >= .9f)
{
CallLookEvent(newAim);
}
}
}
MoveMent.cs
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEditor.Experimental.GraphView;
using UnityEngine;
public class Movement : MonoBehaviour
{
private CharacterController _controller;
private Vector2 _movementDirection = Vector2.zero;
private Rigidbody2D _rigidbody;
private void Awake()
{
_controller = GetComponent<CharacterController>();
_rigidbody = GetComponent<Rigidbody2D>();
}
private void Start()
{
_controller.OnMoveEvent += Move;
}
private void FixedUpdate()
{
ApplyMovement(_movementDirection);
}
private void ApplyMovement(Vector2 direction)
{
direction = direction * 5;
_rigidbody.velocity = direction;
}
private void Move(Vector2 direction)
{
_movementDirection = direction;
}
}
Input Action으로 입력처리
캐릭터 반전
AimRotation.cs
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class AimRotation : MonoBehaviour
{
[SerializeField] private SpriteRenderer characterRenderer;
private CharacterController _controller;
private void Awake()
{
_controller = GetComponent<CharacterController>();
}
void Start()
{
_controller.OnLookEvent += OnAim;
}
private void OnAim(Vector3 newAimDirection)
{
RotateArm(newAimDirection);
}
private void RotateArm(Vector2 direction)
{
float rotZ = Mathf.Atan2(direction.y, direction.x) * Mathf.Rad2Deg; // 각도값을 라디안 값으로 변경
characterRenderer.flipX = Mathf.Abs(rotZ) > 90f; //캐릭터와 마우스 위치가 90이상일 때 캐릭터 반전
}
}
캐릭터 이동에 따른 카메라 이동
CameraController
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CameraController : MonoBehaviour
{
public GameObject target; // 카메라가 따라갈 대상 = Player
[SerializeField] private float CameraSpeed = 5f; // 카메라가 따라갈 속도
private Vector3 targetPosition; // 대상의 현재 위치
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
if (target.gameObject != null)
{
// this는 카메라를 의미 (z값은 카메라값을 그대로 유지)
targetPosition.Set(target.transform.position.x, target.transform.position.y, -10);
// vectorA -> B까지 T의 속도로 이동
this.transform.position = Vector3.Lerp(this.transform.position, targetPosition, CameraSpeed);
}
}
}
이해하기 어렸웠던 점
1. Mathf.Atan2 와 Mathf.Atan
2. Vector3 와 Vector2
3. Mathf.Abs
4. Mathf.Rad2Deg
1. Atan는 atan(y/x) 함수는 인자로 float 형식 변수 한개를 갖는다. 이 때 x좌표값이 0이라면 y/0이 되어 계산이 안되고 버그가 발생한다. 이러한 이유로 atan2(y,x) 함수가 생기게 되었다. atan2 함수는 인자를 y,x 두개를 받아 오류가 발생할 일이 없다.
2. Vector2는 x,y 값을 가지고 있고 Vector3는 x,y,z 값을 가지고 있다. 2d프로젝트에서는 vector2로 표현가능하니깐 연산에서 백터2로 하고 마지막 부분에서 유니티가 자동으로 백터3으로 변환해준다.
3. Mathf.Abs는 절대값으로 변환해준다.
4. Mathf.Deg2Rad / Mathf.Rad2Deg
각각 라디안 -> 각도, 각도 -> 라디안으로 바꿀때 필요한 상수의 읽기전용 변수입니다. Deg2Rad는 2 π/360이고 Rad2Deg는 180/ π와 같습니다.
***알아두면 좋은 유용한 Mathf 함수
1. 절댓값
Mathf.Abs(float num)
2. 최대/최솟값
Mathf.Clamp(float num, float min, float max)
Mathf.Clamp01(float num)
Clamp는 num 값을 min, max에 맞추어 재조정해줍니다.
min보다 작으면 min값을, max 값보다 크면 max값을 반환합니다. 주로 특정 변수가 어떤 값 사이에 존재해야 할 때 프로퍼티로 빼고 set 쪽에서 필터링을 걸어줄 때 사용합니다.
3. 올림 / 버림 / 반올림
올림 - Mathf.Cell(float num)
버림 Mathf.Floor(float num)
반올림 - Mathf.Round(float num)
4. 근사
Mathf.Approximately(float a, float b)
두 변수 a, b가 같은지(근사한지) 비교합니다. float은 부동 소수점이기 때문에 데이터들이 이리저리 가공되거나
특히, 물리를 사용하여 물체를 요리조리 가지고 놀다가 위치나 속력 같은 친구들 가지고 == 연산을
하게 되면 일치하지 않을 때가 있습니다. 이럴 때를 대비해서 float 데이터들은 Approximately를 이용하여
비교해야 합니다. 예를 들어 1.8f == 18.0f / 10.0f가 true를 반환하지 않을 수도 있습니다.
4. 선형 보간
Mathf.Lerp(float a, float b, float t)
a와 b 사이의 값을 변환하는 함수입니다. 0<= t <= 1인 t를 통해 a와 b를 잇는 직선 AB를 t: 1-t로 분할하는 지점을 변환합니다.