-4차원 복소수를 이용한 회전표현 방법 ( x,y,z,w)로 이루어져 있고 , 각 성분은 축이나 각도가 아니다.
-180도가 넘는 회전을 표현하지 못한다 ( 180도 넘는 표현은 179 + 130 이런식으로 더해서 표현한다)
-각 축을 한번에 계산하여 비용이 적고 짐벌락이 발생하지 않는다.
위의 각 오일러 각 , 쿼터니언의 특징을 알고있으면 게임 개발시 많은 도움을 받을 수있다.
유니티는 Inspector 에서 나오는 Rotation(회전)은 vector3로 표현이 된다. 즉, 오일러 각을 의미한다.
하지만 유니티 내부에서는 회전을 계산시에 오일러각이 아닌 쿼터니언을 사용하게된다.
즉, 코드내부에서 회전을 시킬경우 쿼터니언 메서드들을 사용해서 회전을 시켜줘야한다.
쿼터니언은 많은 메서드를 가지고 있지만 자주 사용하는것을 몇개 기록하였다.
1. Quaternion.Euler(x,y,z) : 오일러각을 쿼터니언으로 변경
두 벡터의 거리(Vector2 direction)를 인자값으로 아크탄젠트를 이용하여 각도(rotZ)를 반환받은뒤
해당 각도를 이용하여 객체(armPivot)을 회전시키고 있다.
2. Quaternion.LookRotation : 머리를 회전하는 것처럼, 앞과 위를 특정한 방향으로 하는 회전 쿼터니언을 만듬 3. Quaternion,Slerp : 쿼터니언과 다른 쿼터니언 사이 내분점을 알수 있음, 구형보간 기법(Spherical Linear Interpolation)을 활용해서 쿼터니언에 쓰면 더 정확해짐 ex)두 쿼터니언 Q1,Q2가 있을때 30% 지점은 어디일까? 같은 문제를 풀기 유용해짐
Unity 작업시 기존부터 사용되어왔던 입력처리 패키지로 비교적 쉽게 사용가능하다는 장점이 있다.
Unity-ProjectSetting에 접근시 기본적으로 설치되어 있는 패키지 중 하나이다.
*Inspect를 통한 간단한 키매핑
public KeyCode Up;
public KeyCode Down;
void Update()
{
movement = 0f;
if(Input.GetKey(Up)) { movement += 1f; }
if(Input.GetKey(Down)) { movement -= 1f; }
rigidbody.velocity = new Vector2(0, movement * speed);
}
InputManager를 이용하여 키 맵핑과 오브젝트 조작까지 동작하게하는 코드이다.
위에 코드 적용시 Inspector에서 이런식으로 키맵핑이 가능해진다.
<InputManager 를 지양하게 된이유>
1.다양한 입력 장비 대응 : 현 게임시장은 다양한 플랫폼이 제공되고 있고 , 키맵핑도 매우 자유롭다. 하지만 InputManager는 해당 문제를 대응하기 부적절하다. 2.입력 처리와 실제 로직 실행주체의 분리의 목적 InputManager의 자체 문제는 아니지만, 기능 별로 class를 나누는 작업을 해야 유지 보수 및 확장성이 많이 상승한다.
-> OPP(객체지향프로그래밍) 에서 이런 설계 원칙을 단일책임원칙(SRP)라고 부름
위에 이렇게 단점이 있지만 실제로도 간단한 프로젝트를 만들때는 아직도 많이 사용된다.
<InputSystem>
위에 말한 InputManager의 단점을 극복하기 위해 새로 나온 패키지이다.
해당 패키지는 Unity 패키지에 포함되어있지 않기에 ProjectManager를 통해서 설치해야한다.
window - packageManager-inputsystem 설치 ( 현재 설치되있는상태라 Remove로 뜸)
InputSystem의 추가로 Unity에서 사용하는 모습
Input Action : 해당 동작에 대한 키를 맵핑 데이터를 모아두는 파일
Player Input 컴포넌트 : 자동으로 입력 행동을 처리하고 해당 게임 오브젝트에 메시지를 보내는 역할
Player Input의 Behaviour은 무엇인가?
해당 Input 입력 발생시 해당 게임 오브젝트에 메시지 보내는 여러 방식중 하나 라고 생각하면 된다.
입력이 들어오면 그 즉시 처리 되기에 중복 입력에 대한 필터링이 없음(액션 상태에 따른 시작,중지)가 이루어지지 않음
연속적인 입력 처리가 필요할때 주로 사용,동일한 입력에서 여러 프레임에 걸쳐 이벤트를 받을 수 있음
언제 사용하면 됨?? 축(axis)기반 입력이나 마우스의 움직임 , 복잡한 키 조합 : 축적된 입력을 매 프레임마다 처리해야 하는 경우 ex)조이스틱 축, 마우스 이동 -> 연속적인 입력으로 매 프레임마다 값을 처리해야함 ex2) 멀티 터치 입력 -> 여러 입력을 동시에 수집하고 처리해야됨, 중복입력 필터링이 없기에 모든 입력을 받음
<InputSystem 예제>
using UnityEngine.InputSystem;
public void OnMove(InputValue value)
{
Debug.Log("OnMove" + value.ToString());
Vector2 moveInput = value.Get<Vector2>().normalized;
CallMoveEvent(moveInput);
//실제 움직이는 처리는 여기서 작업하는게 아님
//PlayerMovement에서 작업을 하는것
}
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)
{
CallLookeEvent(newAim);
}
}
수업 듣는 InputController의 구조를 살짝 떼왔다. Event Action으로 각 기능의 함수를 동작시키는 형태인데,
InputValue 타입의 변수 인자값을 받아 해당 동작에서 사용하는 간단한 예시이다.
하지만 게임 프로젝트 규모가 커질수록 Input Map들도 많아지게되며, map에 직접 접근해서 사용해야되는 경우가 존재한다.
ChatGPT - 참고 코드 : 사용시 꼭 읽어보고 사용할것
using UnityEngine;
using UnityEngine.InputSystem;
public class ActionMapSwitcher : MonoBehaviour
{
// InputActionAsset은 Unity의 Input Actions Asset 파일을 연결할 때 사용됩니다.
public InputActionAsset inputActions;
// Action Maps
private InputActionMap playerActionMap;
private InputActionMap uiActionMap;
private void Awake()
{
// InputActionAsset에서 각 Action Map을 가져옴
playerActionMap = inputActions.FindActionMap("Player");
uiActionMap = inputActions.FindActionMap("UI");
// Player Action Map에서 'Move' 액션을 가져와 이벤트 등록
InputAction moveAction = playerActionMap.FindAction("Move");
moveAction.started += OnMoveStarted;
moveAction.performed += OnMovePerformed;
moveAction.canceled += OnMoveCanceled;
// UI Action Map에서 'Navigate' 액션을 가져와 이벤트 등록
InputAction navigateAction = uiActionMap.FindAction("Navigate");
navigateAction.started += OnNavigateStarted;
navigateAction.performed += OnNavigatePerformed;
navigateAction.canceled += OnNavigateCanceled;
}
private void OnEnable()
{
// 기본적으로 Player Action Map 활성화
playerActionMap.Enable();
}
private void OnDisable()
{
// 비활성화 시 모든 액션맵을 비활성화
playerActionMap.Disable();
uiActionMap.Disable();
}
// 'Move' 액션 관련 콜백 함수들
private void OnMoveStarted(InputAction.CallbackContext context)
{
Debug.Log("Move started");
}
private void OnMovePerformed(InputAction.CallbackContext context)
{
Vector2 moveInput = context.ReadValue<Vector2>();
Debug.Log($"Move performed: {moveInput}");
}
private void OnMoveCanceled(InputAction.CallbackContext context)
{
Debug.Log("Move canceled");
}
// 'Navigate' 액션 관련 콜백 함수들
private void OnNavigateStarted(InputAction.CallbackContext context)
{
Debug.Log("Navigate started");
}
private void OnNavigatePerformed(InputAction.CallbackContext context)
{
Vector2 navigateInput = context.ReadValue<Vector2>();
Debug.Log($"Navigate performed: {navigateInput}");
}
private void OnNavigateCanceled(InputAction.CallbackContext context)
{
Debug.Log("Navigate canceled");
}
// Action Map 전환 예시
public void SwitchToUI()
{
// Player Action Map 비활성화
playerActionMap.Disable();
// UI Action Map 활성화
uiActionMap.Enable();
Debug.Log("Switched to UI Action Map");
}
public void SwitchToPlayer()
{
// UI Action Map 비활성화
uiActionMap.Disable();
// Player Action Map 활성화
playerActionMap.Enable();
Debug.Log("Switched to Player Action Map");
}
private void Update()
{
// 예시: Escape 키를 누르면 UI로 전환, 다시 누르면 Player로 전환
if (Keyboard.current.escapeKey.wasPressedThisFrame)
{
if (playerActionMap.enabled)
{
SwitchToUI(); // UI로 전환
}
else
{
SwitchToPlayer(); // Player로 전환
}
}
}
}
해당 코드는 게임내에서의 Player와 UI창의 키 맵핑을 다르게 하고 사용하는 모습이다.
Esc 키를 누르면 UI로 전환 한번 더 누르면 Player로 전환하는 방식이다.
결론 :
1.InputManager는 간단한 프로젝트 진행시 사용하기 좋다.
2.InputSystem은 규모가 커지고 다양한 플랫폼에 제공 및 키 맵핑 변경을 한다면 좋은 선택지이다.
3.InputSystem의 핵심 개념은 , InputAction , Input Action Asset , Player Input 컴포넌트 이 세가지이다.
InputAction : 프로젝트 창에서 생성 가능한 Input 맵핑 데이터가 있는 파일
Input Action Asset : 여러 개의 입력 행동을 그룹화하는 방법, InputAction을 열면 설정창에서 ActionMaps,Actions,AcitonProperites를 수정할 수 있다.
Player Input 컴포넌트 : 입력 행동을 받아 해당 게임오브젝트에 메시지로 전달해주는 역할