-
24년 5월 30일 TIL공부 기록 2024. 5. 30. 07:12
Unity Input System에서 Action Type은 입력을 트리거하고 이벤트를 발생시키는 방법을 정의하는 데 사용 된다. 다양한 Action Type이 있으며, 각각의 유형은 특정한 상황 또는 입력 유형에 맞게 사용 된다. 일반적으로 사용되는 Action Type 몇 가지를 살펴 본다:
- Button:
- 단일 이벤트를 발생시키는 키 또는 버튼에 대한 입력을 나타냄. 예를 들어, 게임에서 "점프" 버튼이나 "공격" 버튼에 사용 됨.
- Value:
- 지속적인 값을 가지는 입력을 나타냄. 예를 들어, 조이스틱의 위치나 마우스의 이동량을 나타내는데 사용될 수 있음.
- Vector2/Vector3:
- 2차원 또는 3차원 벡터 값으로 입력을 나타낸다. 보통 화면의 좌표나 객체의 방향을 나타내는 데 사용 된다.
- Composite:
- 여러 입력을 결합하여 하나의 입력으로 정의하는데 사용 된다. 예를 들어, WASD 키를 하나의 입력으로 정의하여 이동을 제어하는데 사용될 수 있다.
- Pass-Through:
- 입력을 트리거하지 않고 단순히 전달하는데 사용 됨. 대개 이벤트를 트리거하는 것이 아니라 입력의 상태를 읽어오는 데 사용 된다.
이러한 Action Type을 사용하여 게임에서 플레이어 입력을 처리하고 행동을 실행하는 방법을 정의할 수 있다. 각각의 Action Type은 특정한 목적에 맞게 유연하게 사용될 수 있다고 한다.
==
3D에서의 Vector2를 이용한 전방이동 방법 : forward 함수를 사용 해서 전방 이동을 한다.
InputAction에서 w,s를 누를 경우에 1이나 -1인 y값을 받는다. 이거를 forward에 곱해줘서 -1이면 z값에 -1을 곱해서 후방이동, 1이면 양수로 전방으로 1만큼 이동 하게 해준다.
Vector3.y를 곱해준다고 (0,1,0) 이런 식으로 곱하는 게 아닌 y값만 곱하는 것으로 1만 곱해지는 것임. 그래서 Vector2의 y값을 이용 하여 전방이동 구현. forward-> 0,0,1
싱글턴 패턴에 대해서
코드를 보면
public static CharacterManager Instance
{get{
if (_instance == null){
_instance = new GameObject("CharacterManager").AddComponent<CharacterManager>();
}
}
라는 코드와
private void Awake()
{
if (_instance == null)
{
_instance = this; DontDestroyOnLoad(gameObject);
}
}
이렇게 Awake 코드가 있다. 여기서 의문점이 들었는데, 프로퍼티를 사용해서 객체를 생성 해주면 Awake가 필요 없다고 생각이 드는데 왜 굳이 또 Awake를 사용 해서 만드냐는 것이였다.
이거에 대한 답은 이렇다.
코드를 통해 프로퍼티를 사용해서 객체를 만들 때도 있지만, 오브젝트를 만들어서 처음부터 Scene에 있게 만드는 경우도 있기에 이렇게 해주는 것이다. 그렇기에 코드로만 싱글턴을 이용 할 수 있기도 하고, 미리 오브젝트를 만들어서 사용 하는 경우도 할 수 있게 되는 것이다. 아무튼 이런 거 만든 사람들 대단하다.
참고/
- 처음부터 씬에 있는 경우:
- Awake 메서드가 호출될 때 _instance가 null이므로 현재 인스턴스를 _instance에 할당하고, 파괴되지 않도록 설정한다.
- 이후 Instance 프로퍼티에 접근해도 _instance가 이미 설정되어 있으므로 새로운 객체를 생성하지 않는다.
- Instance 프로퍼티에 처음 접근하는 경우:
- 만약 CharacterManager가 처음부터 씬에 없고 Instance 프로퍼티에 처음 접근하는 경우, 새로운 게임 오브젝트와 컴포넌트를 생성하고 _instance에 할당해.
- 이 새로 생성된 객체의 Awake 메서드가 호출될 때 _instance는 이미 설정되어 있으므로, 중복 객체가 아니기 때문에 그대로 유지돼.
- Awake 메서드는 주로 씬에 직접 추가된 CharacterManager 객체를 초기화할 때 사용 된다.
- Instance 프로퍼티는 코드에서 처음으로 인스턴스에 접근할 때 객체를 생성한다.
- 이 두 가지 방식이 함께 동작하여, 중복된 인스턴스가 생성되지 않도록 보장해준다. 첫 번째 인스턴스가 생성되고 나면, 이후 Awake 메서드와 Instance 프로퍼티 접근 모두 기존 인스턴스를 사용하게 되기 때문에 두 번 생성되지 않는다.
값형과 참조형 매개변수로 넘기는 건 값을 넘겨서 필드의 값은 변하지 않는다.
ref out 등을 사용 해서 주소를 넘겨야 한다.
Struct여서 매개변수 필드의 값이 안 바뀌는 게 아니라 그냥 매개변수로 값 넣는 건 거의 대부분 다 값을 복사 해서 넘기는 형식이다. 그래서 필드값은 변하지 않는다.
InputActionPhase의 phase는 입력 액션의 현재 상태를 나타내는 값, Unity의 Input System에서 입력 액션이 어떤 단계에 있는지 알려준다.
InputActionPhase의 각 단계
- Disabled: 입력 액션이 비활성화된 상태. 입력을 받지 않음.
- Waiting: 입력 액션이 활성화되었지만 아직 입력을 기다리고 있는 상태.
- Started: 입력이 감지되어 입력 액션이 시작된 상태. 예를 들어, 버튼을 누르기 시작한 시점.
- Performed: 입력이 완료된 상태. 예를 들어, 버튼을 누르고 있는 동안 지속적으로 발생하거나, 버튼을 눌렀다가 뗀 경우.
- Canceled: 입력 액션이 취소된 상태. 예를 들어, 버튼을 누르는 도중에 입력이 취소된 경우.
ForceMode.Impulse는 짧은 시간 동안 큰 힘을 가할 때 사용, 즉, 순간적인 힘을 줘서 캐릭터가 점프
마우스 이동에 따른 화면 회전 주는 법.
먼저 카메라의 회전값을 줄 변수 하나, 그리고 회전의 최대치와 최소치를 담을 변수 두개, 그리고 마우스 이동에 감도를 정해줄 변수 하나를 만들어 준다.
그리고 함수를 만든다.
void CameraLook()
{
camCurXRot += mouseDelta.y * lookSensitivity;
camCurXRot = Mathf.Clamp(camCurXRot, minXLook, maxXLook);
cameraContainer.localEulerAngles = new Vector3(-camCurXRot, 0, 0);
transform.eulerAngles += new Vector3(0, mouseDelta.x * lookSensitivity, 0);
}인풋시스템으로 마우스의 델타값(이동한거리)를 가져와준다.
Vector2에서 y의 값을 가져와서 float 형식에 담을 수 있음.
이 때 코드를 보게 되면 Delta값에 y를 가져오는 것을 볼 수 있다. 우리는 화면을 위아래로 움직이고 싶을 때 마우스를 y축으로 위아래 움직이게 되는데 이는 엔진에서 좌우 회전값을 주게 된다.
그래서 우리가 움직인 마우스 이동거리 y의 값을 x값에다가 적용 시켜서 우리가 원하는 회전방향대로 하게 해줄 수 있다.
/여기서 +=으로 코드에 값을 넣어주는 이유는 +를 안 하고 =만 하게 되면 순간이동 느낌으로 화면이 회전 되니까. 일 것 같다. ㅋㅋ
그래서 감도를 곱해주고 화면이 계속 돌아가면 안 되니까 회전에 제한을 줄 변수 두 개를 Clamp와 사용해서 값이 나오게 해준다. Clamp는 매개변수 3개를 받는데 첫 번 째 매개변수를 2번째와 3번째를 비교해서 사이에 해당하면 첫 번째 값이 나오고 두번째, 세번째 매개변수보다 크거나 작다면 두번째 세번째 매개변수를 반환하는 함수이다.
그렇게 계산 끝난 카메라의 회전 각도를 localEulerAngles을 사용해서 x에다 값을 적용 시켜준다.
그러면 위아래 회전을 할 수 있게 된다.
x같은 경우는 그대로 x에다가 값을 넣어줘서 사용 하면 된다. 우리가 x축 회전을 할 경우에는 x축으로 마우스를 이동 시키니까 상관이 없다.
y축 이동은 x축이 변경 되지 않고 y축만 오르기에 오른 y축을 x축으로 바꿔주는 작업이 필요한것임.
그리고 똑같이 감도를 곱해줘서 적용 시킨다.
이러면 우리는 마우스 이동에 따라 화면을 회전 시킬 수 있게 된다.
마우스 이동과 카메라 회전의 관계
- 마우스의 Y축 이동: 사용자가 마우스를 위아래로 움직이는 것.
- 카메라의 X축 회전: 카메라가 위아래로 회전하는 것 (Pitch).
회전 축의 의미
- X축 회전 (Pitch): 카메라가 위아래로 회전하는 것을 의미합니다.
- 예를 들어, 머리를 위아래로 끄덕이는 것과 유사합니다.
- Y축 회전 (Yaw): 카메라가 좌우로 회전하는 것을 의미합니다.
- 예를 들어, 머리를 좌우로 돌리는 것과 유사합니다.
왜 마우스 Y축 이동을 카메라 X축 회전에 사용하나?
- 마우스 Y축 이동 (mouseDelta.y):
- 마우스를 위로 이동하면 mouseDelta.y가 양수가 됩니다.
- 마우스를 아래로 이동하면 mouseDelta.y가 음수가 됩니다.
- 카메라 X축 회전 (Pitch):
- 카메라의 X축 회전은 위아래 시야를 조절합니다.
- camCurXRot은 카메라의 현재 X축 회전 각도를 나타냅니다.
- 마우스를 위로 이동하면 카메라가 아래로 회전해야 합니다.
- 마우스를 아래로 이동하면 카메라가 위로 회전해야 합니다.
velocity에 대해서
움직임을 구현 하던 중 문제가 생겼다.
점프나 떨어질 때 엄청 빨리 떨어지는 문제였다.
문제의 원인은
public void ApplyMove(Vector3 direction)
{
direction.y = _rigidbody.velocity.y;
_rigidbody.velocity = direction * speed;
}이 코드였다. 지금 코드를 보게 되면 direction.y = _rigidbody.velocity.y;를 해주게 되는데 이것은 우린 움직이기만 할 때 y의 값은 0이 된다. 움직일 땐 상관이 없으나 3D에서는 점프를 하게 되는데 다음 코드에서 _rigidbody.velocity = direction을 해주게 된다.
이 때 y의 값이 0이면 velocity y값이 0이 되어서 y방향으로의 velocity 가 약해져 엄청 천천히 내려오게 된다.
그래서 direction.y = _rigidbody.velocity.y;라는 코드를 작성 해서 움직여도 y의 velocity의 값은 변경하지 않게 해주는거다.
엄청 빨리 떨어지는 문제에 대해서는 다음 코드가 원인이다.
velocity에 speed값을 곱해주게 되는데 이 방법으로 움직임을 구현한다. 하지만 이 때 y의 값은 다시 초기화가 되지 않는다. 계속 유지가 되게 돼 있다.
rigidbody 컴포넌트에 velocity y의 값이 1이라고 치고 speed가 5라고 하면 이 1의 값에 계속 5를 곱해주게 된다.
(Update 함수에서 이 ApplyMobe를 실행 중이였음)
그래서 y의 값을 velocity의 값을 넣어주기 전에 speed를 곱해주는 코드로 수정을 해줘야 한다.
public void ApplyMove(Vector3 direction)
{direction *= speed;
direction.y = _rigidbody.velocity.y;
_rigidbody.velocity = direction;
}이렇게 수정을 해주면 wasd를 입력 했을 경우에 vector의 값을 받아오고 y는 0이 될 것이니까 direction.y = _rigidbody.velocity.y; 이코드로 y의 값을 넣어줘서 _rigidbody.velocity = direction; 해주면 된다.
speed를 velocity의 y값을 가져오고 난 후에 곱해줘서 생기는 문제였다.
'공부 기록' 카테고리의 다른 글
24년 6월 3일 TIL (0) 2024.06.03 24년 5월 31일 TIL (0) 2024.05.31 24년 5월 29일 TIL (1) 2024.05.29 24년 5월 28일 TIL (0) 2024.05.28 24년 5월 27일 TIL (0) 2024.05.27 - Button: