PlayerInput

Input System은 Input Actions와 PlayerInput으로 구성된다. Input Actions는 입력과 행동의 연결을 정의하는 구조이고, PlayerInput은 그 정의를 바탕으로 실제 입력을 감지하고 동작을 실행하는 컴포넌트다.

 

동작의 주체가 되는 Player 게임 오브젝트에 PlayerInput 컴포넌트를 추가하고, Actions 필드에 사용할 Input Actions 에셋을 지정하면 PlayerInput을 사용할 준비가 완료된다.

 

unity - PlayerInput

 

Default Scheme

어떤 입력 장치(키보드마우스, 게임패드 등)에 대한 입력을 처리할지 지정할 수 있는 설정이다. 

Player Input - Scheme

 

기본값인 Any는 어떤 장치에서든 입력을 받을 수 있다. 특정 장치를 지정하더라도 Auto-Switch가 활성화되어 있다면, 다른 장치의 입력이 감지되었을 때 자동으로 해당 장치로 전환되어 입력을 처리한다. 반대로 Auto-Switch가 비활성화되어 있다면, 처음 감지된 장치만 계속 사용하게 된다. 

 

예를 들어 Default Scheme을 Any로 설정하면 먼저 사용된 키보드마우스로 Control Scheme이 잡힌다.

PlayerInput - Keyboard&Mouse

 

이 상태에서 게임패드를 연결하여 조작을 하면 Auto-Switch 덕분에 자동으로 게임패드로 입력이 감지되어 처리된다.

PlayerInput - GamePad detection

 

Default Map

Default Map은 Input Action Maps 중에서 기본으로 사용할 Map을 지정하는 설정이다.

Input Actions - Default Map

 

Input Action은 상황에 따라 다른 Map으로 전환할 수 있다.

예를 들어 캐릭터 조작 시에는 Player 맵을 사용하고, 메뉴를 열었을 때는 UI 맵으로 전환하여 입력을 UI 조작에만 반응하도록 만들 수 있다. 이러한 방식은 게임패드나 조이스틱처럼 여러 입력이 혼합되는 환경에서 특히 유용하다.

 

UI Input Module

UI와의 상호작용은 EventSystem에 연결된 Input System UI Input Module 컴포넌트를 통해 처리된다.

기본 Unity UI 시스템은 단일 입력만 처리하도록 설계되어 있지만 멀티플레이 게임(로컬)에서는 각 플레이어가 자신의 UI를 조작해야 하는 경우가 생기기 때문에 각 플레이어에게 UI 입력용 시스템도 별도로 연결해주어야 한다.

Event System

 

PlayerInput 컴포넌트가 사용하는 Input Action Asset은 UI Input Module에도 동일하게 적용되어, 동일한 동작과 디바이스 설정으로 UI와 게임 조작을 일관되게 제어할 수 있다.

 

멀티플레이 환경에서는 MultiplayerEventSystem 컴포넌트를 사용하여 화면에 여러 UI 인스턴스를 동시에 표시하고 각 UI를 서로 다른 플레이어가 독립적으로 제어할 수 있게 만들 수 있다.

MultiPlayer Event System

 

Camera

Camera 필드는 멀티 플레이어 상황에서, 플레이어 관리에 사용되는 PlayerInputManager 컴포넌트의 Split-Screen 기능이 활성화된 경우에 의미를 갖는다.

PlayerInputManager

 

이 기능이 켜지면 각 플레이어는 자신만의 카메라를 통해 분할된 화면을 보게 되며, 이때 PlayerInput의 Camera 필드에 각 플레이어의 카메라를 연결해주어야 한다.

 

Mario Kart 2P

 

이렇게 설정하면, UI의 입력 처리도 해당 카메라를 기준으로 이루어지므로 플레이어마다 올바른 UI 포커스 및 이벤트 처리가 가능해진다.

 

Behavior

이벤트가 발생했을 때 어떤 방식으로 처리할지 결정하는 옵션이다.

 

Send Messages

PlayerInpt - Behavior

 

Send Message는 Unity의 고전적인 메시지 전달 방식으로, SendMessage("함수명", 파라미터) 형태로 특정 메서드를 실행한다.

PlayerInput 컴포넌트는 Input Action이 발생했을 때, 해당 액션 이름을 기반으로 구성된 함수명을 자동으로 호출한다. 이 메서드는 GameObject에 연결된 MonoBehaviour 스크립트 내에 정확한 이름으로 존재해야 하며, 그렇지 않으면 호출되지 않고 무시된다.

예를 들어 Jump라는 액션이 정의되어 있다면, PlayerInput은 OnJump()라는 함수명을 찾아 호출한다.

 

이처럼 Input Action에서 정의된 Action 이름 앞에 On을 붙인 함수명이 호출 대상이 되며 위 이미지에서 텍스트로 사용가능한 함수명이 표시된다. 이 함수명 텍스트는 Input Actions 에셋에서 Action의 이름을 추가하거나 편집하고 Asset을 저장하면 자동으로 수정되어 보인다.

 

SendMessage 방식의 장점은 간단하고 빠르게 연결 가능하기 때문에 코드 구조가 가볍지만 메서드명이 정확히 일치해야 작동한다는 점과 동적 호출 방식이기 때문에 컴파일 타임에서 오류 체크가 불가능하며 함수의 파라미터가 InputValue만 전달되기 때문에 복합적인 처리나 Context 정보 전달, 다중 파라미터 기반 로직등의 처리가 어렵다.

 

public void OnMove(InputValue value)
{
	moveInput = value.Get<Vector2>();
}

 

 

Broadcast Message

Broadcast Message 방식도 Unity의 고전적인 메시지 전달 방식으로 Send Message와 동일한 형식을 따르지만, 차이점은 현재 GameObject 뿐만 아니라 모든 자식 오브젝트들에게도 메시지를 전파한다는 점이다.

 

예를 들어 계층 구조 내 여러 컴포넌트가 동일한 함수명을 가지고 있다면, 모두 호출되기 때문에 예상치 못한 중복 동작이 발생할 수 있다. 또한 자식 오브젝트가 많거나 계층이 깊을 경우, 성능 저하의 원인이 될 수 있어 주의가 필요하다.

 

Invoke Unity Events

이벤트 기반 정적 연결방식으로, 함수명을 신경 쓸 필요 없이 에디터에서 간편하게 메서드를 지정할 수 있다.

Behavior - Invoke Unity Events

 

Input Actions에서 정의한 Action들은 PlayerInput 컴포넌트 내에서 자동으로 이벤트로 생성되며, 인스펙터 창에서 해당 이벤트에 호출할 메서드를 직접 할당할 수 있다. 이러한 이벤트 - 리스너 구조는 코드 간의 결합도를 낮추고, 동작을 시각적으로 구성할 수 있어 직관적이고 유지보수도 용이하다.

 

Invoke C Sharp Events

Invoke C# Events는 코드 기반으로 입력을 처리하는 방식으로, PlayerInput이 제공하는 onActionTriggered 이벤트에 리스너를 등록하여 모든 입력 액션을 하나의 이벤트에서 감지할 수 있다.

void OnEnable()
{
    playerInput.onActionTriggered += OnActionTriggered;
}

void OnDisable()
{
    playerInput.onActionTriggered -= OnActionTriggered;
}

void OnActionTriggered(InputAction.CallbackContext context)
{
    if (context.action.name == "Jump")
    {
        Debug.Log("Jump triggered");
    }
}

 

action.name을 기준으로 원하는 액션을 구분해서 처리할 수 있으며, Unity Events 방식은 인스펙터에서 함수명을 문자열로 참조하기 때문에 함수명이 바뀌면 참조가 끊길 수 있는 반면 Invoke C# Events는 코드에서 직접 리스너를 등록하기 때문에 함수명을 변경하더라도 안전하게 리팩토링이 가능하며, 유지보수에 강점을 가진다.

 

정리

각 Behavior 방식은 특징이 다르기 때문에 상황에 따라 적절히 선택해서 사용하는 것이 중요하며 다음과 같이 요약할 수 있다.

- Send Message : 간단한 구현이 필요할 때 유용

- Broadcast Message : 하위 오브젝트까지 포함하여 입력 처리를 해야 하는 특수한 경우에 사용

- Invoke Unity Events : 비프로그래머나 디자이너가 에디터에서 직관적으로 연결할 때 적합

- Invoke C Sharp Events : 복잡한 입력 로직을 처리할 때 사용

728x90
반응형

'Develop > Unity' 카테고리의 다른 글

Input System 으로 플레이어 만들기  (0) 2025.04.12
Input System - Input Actions  (0) 2025.04.10
InputSystem 기본 사용법  (0) 2025.03.25
유니티 기본 물리 샘플  (0) 2025.03.21
구글 계정 연동  (1) 2025.02.28

Input System

2019 버전을 발표할 시점인 19년도에 새로운 Input System을 업데이트하면서 기존까지 입력 처리를 담당했던 Input Manager에 대해서 앞으로 추가 업데이트 사항은 없다고 언급을 했었다. 그 후 아직까지도 호환성은 유지한 채 사용할 수 있도록 제공하고 있지만 공식 문서에서도 legacy로 표현하며 Input System을 권장하고 있다. 

 

Input System을 권장하는 이유는 새로운 입력 처리 방식의 장점과 Input Manager의 오래된 기술로 인한 한계에 있다.

 

Input System 장점

- 다양한 입력 장치를 지원하며 사용자 정의가 가능하다. 이를 통해서 다양한 플랫폼에서 일관된 입력을 처리할 수 있다. 

- 비동기 입력 처리를 지원하기 때문에 입력 이벤트를 더 효율적으로 관리할 수 있어 게임 성능의 향상을 모색할 수 있다.

- Input System의 API는 더 직관적이어서 사용하기 쉬워 코드의 가독성을 높인다.

 

Input Manager 한계

- 다양한 입력 장치를 동시에 처리하는 등의 현대의 게임 개발에서 요구되는 사항을 충족하기  어렵다.

- 기본적인 입력 처리만 가능하기 때문에 복잡한 입력에 대한 요구 사항을 처리하기 부적합하다.

 

Unity 6 버전을 기준으로 진행한다.

 

Project Settings

기본 선택은 both로 되어있는데 Input System만 을 사용하기 위해서 Project Settings > Player > Active Input Handling에서 Input System Package를 선택한다. 

 

어느 버전부터인지 모르겠지만 이전에 사용했던 버전에서는 Input System을 선택 시 패키지 설치가 필요했는데 현재 버전에서는 패키지가 기본적으로 설치되어 있고 InputSystem_Actions 파일이 기본 생성되어 있다.

 

Input Actions

Input System - Input Actions


Input Actions Asset 파일을 열면 입력에 대한 처리를 맵핑과 세부 설정을 할 수 있는 Input Actions Editor 창이 열린다.

 

Action Maps

입력을 그룹으로 묶어 관리할 수 있는 단위이다. 기본적으로 Player, UI 맵이 제공된다.

각 Action Map은 관련된 여러 입력 동작인 Action들의 설정 묶음으로 하나의 Input Actions Asset에서 활성화되는 Map은 하나만 처리되므로 플레이어의 상태에 따라 Map을 전환하여 상황에 맞는 입력만 처리하도록 구성할 수 있어 게임 내 다양한 상태에 따라 입력 처리를 명확하게 구분하고 유지 보수 및 확장도 간편하다.

 

Actions

사용자 입력에 반응하여 수행될 동작을 정의하는 요소이다.

Input Actions - Actions

 

이동, 점프, 공격 등과 같이 플레이어의 입력 행동 단위이다. 각 Action은 하나 이상의 입력 Binding과 연결되고 키보드, 마우스, 게임 패드 등 다양한 장치의 입력을 조합하여 정의할 수 있다.

 

Action은 하나의 입력 동작에 대한 정의이며 Binding은 Action을 어떤 입력 장치에 매핑할지 설정한다.

 

각각 Properties에서 세부적인 옵션 설정을 할 수 있다.

 

Action Properties

각 Action의 동작 방식과 입력값의 처리 형태를 세부적으로 설정할 수 있는 항목이다.

입력의 종류, 처리 방식, 반환 값의 형태 등을 정의하여 다양한 입력 상황에 대응할 수 있도록 옵션이 제공된다.


각 옵션의 기본 설정은 Project Settings > Input System > Settings의 값을 따르며 개별 값을 조정하려면 Default 플래그를 끄고 직접 수정하거나 Settings Asset을 생성하여 값을 커스텀한다.

 

Action Type

입력 시스템의 동작 방식을 정의하는 요소로 각 타입마다 입력 이벤트를 처리하는 방식에 따라 다르게 동작한다.

Value, Button, Pass Through 세 가지 방식이 있다.

Action Properties - Action Type

 

Value

지속적인 입력 값을 반환한다. 입력이 활성화된 동안 현재 상태 값을 계속해서 업데이트한다. 주로 조이스틱의 위치나 슬러이더처럼 지속적으로 변화하는 값을 처리할 때 유용하다.

 

Button

버튼의 누름 상태를 감지한다. 점프, 공격, 상호작용처럼 단일 이벤트 트리거에 적합하다.

 

PassThrough

입력을 필터링 없이 그대로 전달한다. 가공되지 않고 호출 대상에 직접 전달되며 주로 복잡한 입력 로직, 멀티 컨트롤 입력, UI 입력 등에 활용한다.

 

Control Type

Action Type에 따라 달라지는데 Value인 경우 다양한 값 형식으로 가공해서 받을 수 있다.

Value - Control Type

 

Type 설명 반환 타입
Axis 단일 축(1차원)의 연속적인 값 (-1 ~ 1) float 조이스틱 축, 키보드 이동, 마우스 휠 등
Analog 0.0 ~ 1.0 범위의 연속 아날로그 값 float 게임패드의 트리거, 슬라이더 등
Integer 정수 값 int 타임라인, 메뉴 인덱스 등
Digital 이진 값 (0 또는 1, true/false) float or bool 버튼 입력, 온/오프 스위치 등
Double 높은 정밀도 실수 double 정밀 제어, 시뮬레이션 등
Vector2 2D 벡터 Vector2 2D 이동, 마우스/터치 위치, 텍스처 좌표 등
Vector3 3D 벡터 Vector3 3D 위치, 방향 등
Delta 변화량을 나타내는 값(차이값) Vector2 마우스 드래그, 터치 슬라이드 변화량
Quaternion 3D 회전을 나타내는 사원수 Quaternion 컨트롤러 회전, 장치 방향
Stick 아날로그 스틱 입력 StickControl 게임 패드의 조이스틱
Dpad 4방향 디지털 입력 DpadControl 게임 패드의 십자키
Touch 단일 터치 정보 TouchControl 터치 스크린
Pose 위치 + 회전 정보 PoseControl VR, AR 디바이스
Eyes 시선 추적 데이터 EyesControl VR HMD, 아이 트래킹 장비

 

PlayerInput의 Behavior 방식에 따라 다르지만 Stick, Dpad, Touch, Pose, Eyes와 같은 타입들은 내부적으로 해당 클래스 타입(StickControl, DpadControl 등)으로 처리되며, Callback 방식에서 해당 클래스를 직접 참조하여 세부 데이터를 추출할 수 있다.

 

Interactions

 Action의 세 가지 이벤트 상태(started, performed, canceled)에 도달하기 위한 조건을 세부적으로 정의하는 항목이다.

 

Action 상태

- started : 입력의 시작점

- performed : 입력이 성공적으로 완료된 시점

- canceled : 입력이 도중에 중단 또는 실패한 경우

 

Action Properties - Interactions

 

Hold

일정 시간 동안 누르고 있을 때만 유효한 입력으로 인식한다.

Interactions - Hold

 

Press Point : 입력 강도를 판정하는 것으로 어느 정도 눌렸을 때 Press로 보는지 판단하는 기준으로 트리거나 스틱 같이 값 변경이 미세한 경우에서 중요하게 판단된다.

 

Hold Time : Press Point를 넘은 후 이 시간만큼 입력이 유지됐을 때 performed 상태가 되고 그전에 입력이 중단되면 canceled 상태가 된다.

 

Multi Tap

일정 시간 안에 특정 횟수만큼의 입력이 발생했을 때 작동한다.

Interactions - Multi Tap

 

Tap Count : 몇 번을 입력해야 performed 되는지

Max Tap Spacing : 탭과 탭 사이 최대 허용 시간

Max Tap Duration : 각 탭이 유지될 수 있는 최대 시간

Press Point : 유효한 입력으로 판단할 최소 세기

 

입력 사이 간격이 Max Tap Spacing을 넘거나, 각 탭 유지 시간이 Max Tap Duration을 넘기면 canceled

 

Press

버튼을 누르거나 뗄 때 발생하는 단순 입력을 세밀하게 제어할 때 사용한다. 

단순 버튼의 입력에 대한 처리라면 Action Type의 Button으로 설정하면 되고 세부 제어가 필요한 경우 Press Interaction을 사용한다.

Interactions - Press

 

Trigger Behavior : Press Only, Release Only, Press and Release 세 가지 상태가 있으며 각 상태는 버튼을 눌리는 순간, 떼는 순간, 누를 때 started 뗄 때 performed로 처리한다.

 

Slow Tap

버튼을 누른 뒤 일정 시간 후에 뗄 때 performed 상태가 된다.

Min Tap Duration : 탭이 performed 되기 위한 최소 시간

 

Hold와 비슷하지만 hold는 시간 조건이 됐을 때 performed, slow tap은 시간을 채우고 뗄 때 performed 되는 차이가 있다. 하지만 겹치는 동작이 발생할 수 있기 때문에 동일한 Action에서 Hold와 Slow Tap 두 인터랙션을 동시에 사용할 때는 조건을 명확하게 하여 구분할 필요가 있다.

 

Tap

버튼을 빠르게 누르고 떼는 동작을 인식한다.

Max Tap Duration : 입력이 Press Point 이상으로 감지된 이후에 started 상태가 되고 Max Tap Duration 안에 입력을 뗄 때 performed 된다.

 

Processors

입력값을 처리하여 최종적으로 Action에 전달되는 값을 조정하는 기능이다.

컨트롤러의 조이스틱, 마우스, 트리거 등 다양한 입력 장치에서 입력된 원시 값을 자동으로 보정, 변환, 필터링할 수 있다.

Action Properties - Processors

 

Axis Deadzone, Stick Deadzone

Axis Deadzone은 축 단위(float)의 선형적인 입력값에 대해 deadzone을 적용한다.

입력값이 min 보다 작으면 0, max 보다 크면 1, 그 사이의 값은 0 ~ 1 사이로 정규화된 값

Processors - Deadzone

 

주로 게임패드의 트리거와 같이 선형적인 입력에서 의도치 않은 작은 입력을 무시하거나 거의 끝까지 입력된 경우 1로 보정한다.

Example - Trigger Axis Deadzone

 

Stick Deadzone은 2D Vector 입력에 대해서 방사형 범위의 deadzone을 적용한다.

입력된 벡터의 길이(magnitude)가 min 보다 작으면 0, max 보다 크면 1, 그 사이값은 정규화하여 보정한다.

 

Processor - Stick Deadzone

 

게임패드의 아날로그 스틱 입력에서 중앙 근처의 미세한 입력을 무시하고 가장자리에 가까우면 1, 범위 내의 값은 정규화하여 보정한다.

Example - Stick Deadzone

 

 

Clamp

입력값이 특정 범위를 벗어나지 않도록 제한해 주는 기능이다. 즉, 최소와 최댓값을 지정하고 그 범위를 벗어나는 값은 경곗값으로 보정한다.

Processors - Clamp

 

Min : 입력값의 최솟값

Max : 입력값의 최댓값

 

Invert, Invert Vector2, Invert Vector3

입력값의 부호를 반전시킨다. 

Processors - Invert

 

단일 수치(float) 뿐 아니라 Vector2, Vector3 타입의 입력에도 사용 가능하며, 각 축별로 플래그로 개별 설정할 수 있다.

 

Normalize, Normalize Vector2, Normalize Vector3

입력값을 -1 ~ 1 사이로 정규화한다.

Processors - Normalize

 

벡터의 크기는 무시하고 방향성만 필요한 경우에 사용한다.

 

Scale, Scale Vector2, Scale Vector3

입력 값에 곱셈 계수 Factor를 적용한다.

Processors - Scale

 

마우스 민감도 등 감도 조정에 사용할 수 있다.

 

Binding Properties

Binding

단일 입력 바인딩

Binding Properties - Binding

 

Path

이 Binding이 참조하는 입력 장치와 입력 경로를 지정하며 기본 입력 연결 포인트로, 해당 Action이 어떤 입력에서 데이터를 받을지 결정한다.

 

Show Drived Bdings : 입력 장치마다 자동으로 파생되는 바인딩 목록을 확인할 수 있다.

 

Use in control scheme

특정 Control Scheme에 이 Binding을 포함할지 여부를 정한다.

예를 들어서 Keyboard&Mouse, Gamepad, Touch 등으로 나누어진 스킴에서 이 바인딩이 어떤 스킴에서 사용되는지 지정한다.

 

Composite

복합 입력 바인딩

Binding Properties - Composite Binding

 

여러 입력 값을 조합해서 하나의 논리적 입력으로 만들 때 사용한다.

대표적으로 WASD 나 방향키 조합으로 Vector2 이동을 구현하는 것이 있다.

 

Composite Type

어떤 형태의 입력 조합인지 지정한다.

 

1D Axis 

두 개의 입력을 받아서 -1 ~ 1 사이의 float 값으로 반환한다.

1D Axis

Negative 입력 -1, Positive 입력 +1 두 입력이 동시에 있다면 Which Side Wins에 따라 결과가 달라진다.

 

Composite - 1D Axis

Neither : 두 입력이 상쇄되어 0

Positive : Positive 입력 우선, +1 반환

Negative : Negative 입력 우선, -1 반환

 

2D Vector

네 개의 입력을 받아 Vector2(x, y) 값으로 결합하여 반환

Composite - 2D Vector

Up : +y

Down : -y

Left : -x

Right : +x

2D Vector - Mode

 

Analog : 아날로그 입력 값을 그대로 사용

Digital Normalized : 디지털 입력의 정규화 값

Digital : 입력이 있는 방향에 대해 -1/0/1의 벡터 구성

 

3D Vector

여섯 개의 입력을 받아 Vector3(x, y, z) 값으로 결합

Composite - 3D Vector

2D Vector에서 

Forward : +z

Backward : -z

추가

 

모드는 동일하다.

 

Button With One/Two Modifiers

하나 또는 두 개의 Modifier 키와 Button의 조합이다.

Modifier의 입력이 있으며 Button이 눌려야 Action이 발생한다.

Composite - Button With Two Modifiers

 

일반적으로 shift, ctrl, alt 등의 키를 modifier 키지만 일반키를 Modifier로 사용할 수 있다.

 

Button With Two Modifiers

 

Override Modifiers Need To Be Pressed First : Modifier 키가 먼저 눌려야 Action이 발동되는지 결정하는 옵션

활성화 시 Modifier 키들이 먼저 입력된 상태에서 Button이 입력되어야 동작 비활성화 시 순서 상관없이 모두 눌려지면 동작

 

One/Two Modifiers

하나 또는 두 개의 Modifier 키의 조합이다.

Binding이 있지만 이 키의 입력은 상관없이 Modifier의 입력만으로 판단한다.

 

Composite - Two Modifiers

 

Button의 입력이 중요한 Button With ~ Modifier와 달리 Modifier의 입력만으로 동작의 조건이 충족된다.

Binding은 Modifier 입력을 기반으로 추가 입력을 받을 수 있는 여지를 만들어 주는 역할을 한다.

728x90
반응형

'Develop > Unity' 카테고리의 다른 글

Input System 으로 플레이어 만들기  (0) 2025.04.12
Input System - Player Input  (0) 2025.04.11
InputSystem 기본 사용법  (0) 2025.03.25
유니티 기본 물리 샘플  (0) 2025.03.21
구글 계정 연동  (1) 2025.02.28

PlayerInput Component

빌트인 컴포넌트인 PlayerInput을 플레이어 오브젝트에 추가해서 키입력을 바로 받을 수 있다.

 

unity - PlayerInput

 

Actions에 등록된 InputSystem_Actions를 열어볼 수 있는데 일반적으로 사용되는 키로 바인딩되어 있는 걸 확인할 수 있다.

 

unity - input action

 

이 파일을 수정해서 바인딩 키나 값을 변경하여 처리할 수 있다.

 

플레이어 조작 스크립트에서 이 입력을 가져다 쓰는 방법은 다음과 같다.

 

private void Awake()
{
    rb = GetComponent<Rigidbody>();
}

private void FixedUpdate()
{
    if (currentInput != Vector2.zero)
    {
        // 방향 설정
        body.forward = new Vector3(currentInput.x, 0, currentInput.y).normalized;

        // 속도 계산
        float currentSpeed = walkSpeed;
        Vector3 moveVelocity = new Vector3(currentInput.x, 0, currentInput.y) * currentSpeed;

        // 물리 이동
        rb.linearVelocity = moveVelocity;

        // 애니메이션
        animator.SetFloat("Move", currentInput.magnitude);
    }
    else
    {
        // 정지 상태
        animator.SetFloat("Move", 0);
        rb.linearVelocity = Vector3.zero;
    }
}

public void OnMove(InputValue value)
{
	moveInput = value.Get<Vector2>();
}

 

업데이트 안에서 이동키 입력으로 변경되는 moveInput 값을 갱신해서 플레이어를 움직인다.

 

unity - player move

 

Action Properties 설정을 통해서 필요에 맞춰 수정해서 쓸 수 있다.

 

unity - sprint properties

 

쉬프트를 누르면 달리고, 떼면 걷도록 상태를 변경하는 기능을 추가해본다. 

 

기본 Action은 눌렀을 때만 처리하고 있는데 이 부분을 PressAndRelease로 변경한다. 

 

그리고 Initial State Check를 활성화 해준다.

 



private void FixedUpdate()
{
    currentInput = Vector2.SmoothDamp(
        currentInput,
        moveInput * (isSprint ? 1f : 0.5f),
        ref smoothVelocity,
        smoothTime
    );

    if (currentInput != Vector2.zero)
    {
        // 방향 설정
        body.forward = new Vector3(currentInput.x, 0, currentInput.y).normalized;

        // 속도 계산
        float currentSpeed = isSprint ? sprintSpeed : walkSpeed;
        Vector3 moveVelocity = new Vector3(currentInput.x, 0, currentInput.y) * currentSpeed;

        // 물리 이동
        rb.linearVelocity = moveVelocity;

        // 애니메이션
        animator.SetFloat("Move", currentInput.magnitude);
    }
    else
    {
        // 정지 상태
        animator.SetFloat("Move", 0);
        rb.linearVelocity = Vector3.zero;
    }
}

private void PlayerAnimation(float moveAmount)
{
    animator.SetFloat("Move", moveAmount);
}

public void OnMove(InputValue value)
{
    moveInput = value.Get<Vector2>();
}

public void OnSprint(InputValue value)
{
    isSprint = value.isPressed;
}

 

InputManager의 GetAxis처럼 입력이 서서히 -1 0 1 사이에서 움직이는 선택 없이 GetAxisRaw처럼 고정된 숫자로 값이 반환되는데 이 부분이 InputSystem에서 설정으로 제어 가능한 부분이 아닌 것으로 현재 판단되어서 일단 damp를 사용해서 임의로 값을 증가, 증감시켜 범위 내 변하는 값으로 움직임을 처리한다.

 

이 값이 필요한 이유는 애니메이션을 블렌딩으로 처리하기 때문에 자연스러운 애니메이션을 표현하기 위해서 시작-도착 값까지의 변화하는 값이 필요하다.

 

unity - move

728x90
반응형

'Develop > Unity' 카테고리의 다른 글

Input System - Player Input  (0) 2025.04.11
Input System - Input Actions  (0) 2025.04.10
유니티 기본 물리 샘플  (0) 2025.03.21
구글 계정 연동  (1) 2025.02.28
2D 애니메이션, 이펙트  (1) 2024.12.03

유니티의 물리엔진의 기본 기능들의 샘플 구현

 

중력

유니티는 물리적인 오브젝트에는 중력과 힘 등의 물리 작용들이 적용된다.

 

물리적인 오브젝트란 Rigidbody 컴포넌트가 붙어있는 것으로 이 컴포넌트에서 중력의 적용 여부나 질량, 마찰력 등의 설정을 제어할 수 있다.

 

유니티의 중력은 Physics.gravity로 접근하여 값을 가져오고 변경할 수 있다.

 

이 중력은 Vector3 값으로 기본값은 현실과 동일하게 y 축으로 -9.81으로 되어있다.

 

이 값을 변경하면 중력을 다양한 방식으로 적용할 수 있다.

 

unity - gravity

 

Rigidbody 컴포넌트의 drag 값은 항력을 제어한다. 하지만 이는 선형적인 값으로 현실적인 물리와는 차이가 있다.

 

angular drag는 회전 항력으로 회전력에 적용되는 저항력이다.

 

unity - drag
unity - angular drag

 

 

물리적인 상태의 오브젝트에는 힘을 가해서 움직이거나 회전 또는 범위 내 오브젝트에 거리 비례 힘을 가하는 물리 기능들을 사용할 수 있다.

 

AddForce

물체에 특정 방향으로 특정 크기만큼의 힘을 가한다.

unity - add force

 

AddTorque

물체에 회전력을 준다.

unity - add torque

 

AddExplosionForce

unity - add explosion force

 

AddExplosionForce는 이 함수만 호출한다고 주변에 영향을 주는 것이 아니라 특정한 객체를 기준으로 영향을 줄 주변 객체를 직접 탐색하면서 AddExpolsionForce를 적용시킨다.

 

public void ApplyExplosion(float force, float radius)
{
    Collider[] colliders = Physics.OverlapSphere(transform.position, radius);
    foreach (Collider col in colliders)
    {
        Rigidbody rb = col.GetComponent<Rigidbody>();
        if (rb != null)
        {
            rb.AddExplosionForce(force, transform.position, radius);
        }
    }
}

 

 

샘플 프로젝트 Github 저장소

https://github.com/Bakcoding/unity-physics-sample.gi

728x90
반응형

'Develop > Unity' 카테고리의 다른 글

Input System - Input Actions  (0) 2025.04.10
InputSystem 기본 사용법  (0) 2025.03.25
구글 계정 연동  (1) 2025.02.28
2D 애니메이션, 이펙트  (1) 2024.12.03
Input System 사용시 UI 상호작용 안될때  (0) 2024.11.18

버전 : Unity 6

 

구글 계정에 연동과정

 

Google Sign In SDK에서 ID 토큰, 액세스 토큰을 받는다.

 

Firebase Authentication으로 Google ID 토큰을 Firebase로 전달하고 이를 인증한다.

 

Google Sign In SDK는 구글 계정으로 로그인할 수 있지만 이후 로그인한 사용자를 앱의 인증 시스템에서 관리할 방법이 없다.

 

또한 Google ID 토큰을 앱에서 직접 검증하는 것은 보안상 위험하기 때문에 파이어베이스를 통해서 토큰을 검증하고 관리하여 안전하게 관리할 수 있고 파이어베이스의 다양한 기능과 연계하여 사용할 수도 있다.

 

1. 파이어베이스 인증 SDK 설치

Firebase Authentication SDK

 

Google 로그인과 Unity를 사용하여 인증하기  |  Firebase

의견 보내기 Google 로그인과 Unity를 사용하여 인증하기 컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요. Google 로그인을 앱에 통합하여 사용자가 Google 계정으로

firebase.google.com

 

Firebase Authentication

 

다운로드한 압축 파일에서 FirebaseAuth.unitypackage 패키지를 프로젝트에 임포트

 

FirebaseAuth

 

2. Google-Signin-Unity

Google-SignIn-Unity

 

GitHub - googlesamples/google-signin-unity: Google Sign-In API plugin for Unity game engine. Works with Android and iOS.

Google Sign-In API plugin for Unity game engine. Works with Android and iOS. - googlesamples/google-signin-unity

github.com

 

최신버전 1.0.4 사용

 

* 프로젝트에 임포트하면 Unity.Task 관련해서 충돌 에러가 발생하는데 Assets > Parse  폴더를 지우면 해결 가능하다.

 

설치 후 패키지 문제 없는지 테스트 빌드를 진행

 

gradle 에러가 발생해서 빌드에 실패한다. 안드로이드 빌드 시 자주 발생하는 에러로 이런 경우 프로젝트 세팅의 최소 타겟 API를 올리면 해결되는 경우가 많은데 먼저 이 부분을 확인해서 다시 빌드해 본다.

 

Minimum API Level 23 -> 24로 변경 후 다시 빌드하니 해결되었다.

 

3. Key Store 생성

파이어베이스에서 인증 정보를 저장하고 관리할 프로젝트를 생성해야 하는데 이때 유니티 프로젝트의 SHA 키가 필요하다.

 

먼저 유니티에서 키스토어를 생성하고 SHA를 확인해 둔다.

 

1. 키스토어 생성

 

 

2. SHA 확인

키스토어를 열어보기 위해서는 keytool을 사용해야 하는데 유니티 에디터를 설치하면 포함되어 있기 때문에 에디터 설치 경로에서 

keytool.exe 파일이 위치한 경로에서 명령 프롬프터를 켜서 'keytool -list -keystore [키스토어 경로]' 를 실행한다.

 

 


* 구글 계정 인증에는 SHA-1 이 필요한데 Unity 6 버전의 keytool을 사용했더니 256만 뜨고 나머지 지문들은 생략된다.

   다른 에디터 버전의 keytool을 사용해서 SHA-1을 확인하고 메모해 둔다.

 

해당 키는 잠시 메모해 둔다.

 

4. 파이어베이스 프로젝트 세팅

Firebase

 

Firebase | Google's Mobile and Web App Development Platform

개발자가 사용자가 좋아할 만한 앱과 게임을 빌드하도록 지원하는 Google의 모바일 및 웹 앱 개발 플랫폼인 Firebase에 대해 알아보세요.

firebase.google.com

 

로그인 인증을 처리할 프로젝트를 생성한다.

 

 

유니티 플랫폼을 선택해서 앱을 추가한다.

 

 

여기서 디지털 지문 추가에서 키스토어의 SHA 키를 입력한다.

 

Authentication 항목으로 들어가서 로그인 제공업체를 추가한다.

 

 

Google을 선택하고 사용설정을 해준다.

 

5. 클라이언트 ID 확인

Google Cloud

 

Google 클라우드 플랫폼

로그인 Google 클라우드 플랫폼으로 이동

accounts.google.com

 

구글 클라우드에 접속하면 파이어베이스에서 생성했던 프로젝트와 동일한 정보로 프로젝트가 생성되어 있다.

 

이 중에서 사용자 인증 정보 항목에서 OAuth 2.0 클라이언트 ID를 사용해서 유니티에서 접속을 시도한다.

 

 

6. 로그인 스크립트

유니티로 돌아가서 로그인 스크립트를 구현한다.

 

* 에러

SignIn 함수 호출 시 계정 선택 UI 팝업이 뜬 후 계정을 선택하고 나서 반응이 없는 현상이 있었는데 결과를 받아서 처리하는 콜백에서 에러가 발생했었다.

 

이때 메인스레드에서 처리되도록 Dispatcher 함수를  구현해서 처리하니 문제가 해결되긴 했는데 정확한 원인은 확인을 못한 부분이다.

 

using System.Collections.Generic;
using UnityEngine;

public class MainThreadDispatcher : MonoBehaviour
{
    private static MainThreadDispatcher instance;
    private readonly Queue<System.Action> executionQueue = new Queue<System.Action>();

    private void Awake()
    {
        if (instance == null)
        {
            instance = this;
            DontDestroyOnLoad(gameObject);
        }
        else
        {
            Destroy(gameObject);
        }
    }

    private void Update()
    {
        lock (executionQueue)
        {
            while (executionQueue.Count > 0)
            {
                executionQueue.Dequeue()?.Invoke();
            }
        }
    }

    public static void RunOnMainThread(System.Action action)
    {
        if (instance != null)
        {
            lock (instance.executionQueue)
            {
                instance.executionQueue.Enqueue(action);
            }
        }
    }
}

 

 

디스패처를 사용해 SignIn 함수 결과를 처리한다.

 

using Google;
using System.Collections.Generic;
using System.Threading.Tasks;
using UnityEngine;

public class GoogleLogin : MonoBehaviour
{
    private string web_client_id = "구글 클라우드의 클라이언트 ID";

    private void Awake()
    {
        Init();
    }

    private void Init()
    {
        GoogleSignIn.Configuration = new GoogleSignInConfiguration
        {
            WebClientId = web_client_id,
            UseGameSignIn = false,
            RequestEmail = true,
            RequestIdToken = true
        };
    }

    public void SignIn()
    {
        DebugMessage.Instance.ShowMessage("Calling SignIn");
        Debug.Log("Calling SignIn");
        GoogleSignIn.DefaultInstance.SignIn().ContinueWith(
          OnAuthenticationFinished);
    }

    internal void OnAuthenticationFinished(Task<GoogleSignInUser> task)
    {
        Debug.Log("Authentication finished, processing on main thread");
        MainThreadDispatcher.RunOnMainThread(() => ProcessAuthResult(task));
    }

    private void ProcessAuthResult(Task<GoogleSignInUser> task)
    {
        Debug.Log("Auth Result");
        if (task.IsFaulted)
        {
            using (IEnumerator<System.Exception> enumerator = task.Exception.InnerExceptions.GetEnumerator())
            {
                if (enumerator.MoveNext())
                {
                    GoogleSignIn.SignInException error = (GoogleSignIn.SignInException)enumerator.Current;
                    DebugMessage.Instance.ShowMessage("Got Error: " + error.Status + " " + error.Message);
                    Debug.Log("Got Error: " + error.Status + " " + error.Message);
                }
                else
                {
                    DebugMessage.Instance.ShowMessage("Got Unexpected Exception?!?" + task.Exception);
                    Debug.Log("Got Unexpected Exception?!?" + task.Exception);
                }
            }
        }
        else if (task.IsCanceled)
        {
            DebugMessage.Instance.ShowMessage("Canceled");
            Debug.Log("Canceled");
        }
        else
        {
            DebugMessage.Instance.ShowMessage("Welcome: " + task.Result.DisplayName + "!");
            DebugMessage.Instance.ShowMessage(task.Result.Email + "!");
            DebugMessage.Instance.ShowMessage(task.Result.IdToken + "!");

            Debug.Log("Welcome: " + task.Result.DisplayName + "!");
            Debug.Log(task.Result.Email + "!");
            Debug.Log(task.Result.IdToken + "!");
        }
    }
}

 

 

폰트에 한글이 지원되지 않아서 깨진 것 빼고는 로그인 성공 후 들어오는 리턴 정보를 로그로 찍은 값들이 잘 출력되는 게 확인된다.

 

 

728x90
반응형

'Develop > Unity' 카테고리의 다른 글

InputSystem 기본 사용법  (0) 2025.03.25
유니티 기본 물리 샘플  (0) 2025.03.21
2D 애니메이션, 이펙트  (1) 2024.12.03
Input System 사용시 UI 상호작용 안될때  (0) 2024.11.18
유니티 프로젝트 창 검색 활용  (1) 2024.06.30

최근에 UI 애니메이션을 작업하다 정리가 필요한 부분이 있어서 작성한다.

 

2D Sprite

2D 스프라이트의 애니메이션은 리소스와 Animator를 가지고 만들 수 있다.

Sprite Renderer Animation

 

원하는 프레임마다 스프라이트를 변경하는 방식으로 애니메이션을 만들 수 있다.

 

UI Animation

UI 경우에도 애니메이션으로 컨트롤하는 경우에는 동일한 방식으로 처리된다.

UI Animation

 

Effect

Sprite Renderer를 사용하는 상황에서 뭔가 발산하는 이펙트를 사용한다면 어떻게 하는 게 좋을까 생각하면서 파티클 시스템과 오브젝트를 직접 제어하는 방법 두 가지를 사용해 보았다.

 

 

있는 리소소 가지고 대충 테스트만 하려고 만들다 보니 별로 이뻐 보이진 않는다.

 

이러한 상황에서는 오브젝트를 가지고 직접 제어하는 게 나은 방식인 거 같다.

 

 

실제로 사용한다면 풀링을 해서 쓰겠지만 그럼에도 상당히 많은 오브젝트를 뿜어낸다면 파티클을 쓰는 게 적합하다고 보인다.

 

상황에 맞게 잘 조율하는 게 필요하다.

 

위에서 사용한 코드

 

using UnityEngine;

public class Coin : MonoBehaviour
{
    private const float power = 10f;
    private void OnEnable()
    {
        transform.position = Vector3.zero;
        ApplyForce();
    }

    private void ApplyForce()
    {
        var rb = GetComponent<Rigidbody2D>();
        float randomHorizontal = Random.Range(-1f, 1f); // -1 to 1 for left/right
        Vector2 direction = new Vector2(randomHorizontal, 1f).normalized;
        rb.AddForce(direction * power, ForceMode2D.Impulse);
    }
}

using UnityEngine;

public class Coin : MonoBehaviour
{
    private const float power = 10f;
    private void OnEnable()
    {
        transform.position = Vector3.zero;
        ApplyForce();
    }

    private void ApplyForce()
    {
        var rb = GetComponent<Rigidbody2D>();
        float randomHorizontal = Random.Range(-1f, 1f); // -1 to 1 for left/right
        Vector2 direction = new Vector2(randomHorizontal, 1f).normalized;
        rb.AddForce(direction * power, ForceMode2D.Impulse);
    }
}

 

대충 동전이 뿜어지는 듯한 모습을 중점으로 만들었다.

 

Coin 간에는 충돌처리하면 초기 한 위치에 모여있을 때 서로 부딪혀서 Physics2D > Layer Collision Matrix를 꺼두었다.

 

바닥에 충돌 후 튕기는 것과 미끄러지는 정도는 Phsics Material로 조절한다 (Friction 마찰력, Bounciness 탄성력)

 

UI Effect

위 내용들은 겸사겸사로 같이 정리한 내용이고 이 글을 쓰기 시작한 이유는 이 부분 때문이었다.

 

상황은 대충 이렇다.

 

간단한 퍼즐 게임을 만드는 중에 스프라이트 렌더러를 쓰기에는 귀찮은 부분들이 있어서 간단하게 만들려고 UI를 베이스로 해서 게임 로직들을 만들었고 그렇게 진행하다 보니 효과를 추가하는 과정에서 물리적인 부분을 사용할 수 없어 직접 위치를 이동시켜서 유사하게 재현할 수밖에 없었다.

 

UI Animation

 

using UnityEngine;

public class UICoinMaster : MonoBehaviour
{
    [SerializeField] UICoin[] uiCoins;

    bool isOn = false;
    public void OnClick_UICoinMaster()
    {
        if (isOn)
        {
            foreach( var coin in uiCoins)
            {
                coin.gameObject.SetActive(false);
            }
            isOn = false;
        }
        else
        {
            foreach (var coin in uiCoins)
            {
                coin.gameObject.SetActive(true);
            }
            isOn = true;
        }
    }
}


using UnityEngine;

public class UICoin : MonoBehaviour
{
    [SerializeField] private float initialForce = 10f;
    [SerializeField] private float gravity = 9.8f;
    [SerializeField] private float bounceForce = 0.5f;
    [SerializeField] private bool isMoving = false;

    private RectTransform rect;
    private Vector2 velocity;
    private Vector2 originPos;
    private void Awake()
    {
        rect = GetComponent<RectTransform>();
        originPos = rect.position;
    }

    private void OnEnable()
    {
        ApplyPower();
    }

    private void OnDisable()
    {
        rect.position = originPos;
    }

    private void ApplyPower()
    {
        float randomX = Random.Range(-1f, 1f);
        velocity = new Vector2(randomX, 1f).normalized * initialForce;
        isMoving = true;
    }

    private void Update()
    {
        if (!isMoving) return;

        velocity.y -= gravity * Time.deltaTime;

        rect.anchoredPosition += velocity * Time.deltaTime;

        if (rect.anchoredPosition.y < 0)
        {
            rect.anchoredPosition = new Vector2(rect.anchoredPosition.x, 0);
            velocity.y = -velocity.y * bounceForce;
            velocity.x *= 0.8f;
            
            if (Mathf.Abs(velocity.y) < 0.1f)
            {
                isMoving = false;
            }
        }
    }
}

 

UI 크기에 맞춰서 값들을 적절하게 세팅하면 그럴듯해 보인다. 구현하는 데는 크게 무리가 없지만 UI 가지고 이래도 되나 싶은 생각이 들기도 한다.

 

개인적으로는 필요한 기능만 직접 구현해서 쓰는 걸 선호하는 편이라 잘 쓰진 않지만 위처럼 UI를 제어하는 데는 DoTween을 사용하는 게 더 간단하고 다양한 동작들도 처리할 수 있을 것이다.

 

UI Particle System

한 번쯤은 'UI위에 파티클 뿌리기'에 대해서 많은 고민과 탐구를 해보았을 것이다. 이 경우 나는 주로 카메라의 렌더링 모드를 Screen Space - Camera로 세팅해서 파티클을 보이게 하는 방법을 사용했다. 그런데 이 방법은 원하는 파티클을 사용할 때나 좌표계를 다룰 때 은근히 귀찮고 까로운면이 있었다.

 

그래서 이번에 좀 더 찾다 보니 좋은 방법을 알게 되었다.

 

https://github.com/Unity-UI-Extensions/com.unity.uiextensions.git

 

GitHub - Unity-UI-Extensions/com.unity.uiextensions

Contribute to Unity-UI-Extensions/com.unity.uiextensions development by creating an account on GitHub.

github.com

 

 

UI Extensions 라이브러리로 여기에서 UIParticle System을 사용하면 파티클을 UI 위에 렌더링 할 수 있는 상태로 만들 수 있다.

 

해당 라이브러리에 대해서는 알고는 있었는데 파티클 관련 기능이 있었다는 건 이번에 알게 되었다.

 

이와 관련해서 UIParticle System 사용방법과 파티클의 기본 사용방법을 배우기 좋은 영상을 메모해 둔다.

 

https://www.youtube.com/watch?v=hiRdux33UCs

 

파티클을 조금 참고해서 만들어 적용시켜 본다.

 

효과를 주고 싶은 UI의 자식에 파티클을 할당하면 UI와 동일한 렌더링 우선순위로 처리가 된다는 점에서 원하는 기능 그 자체였다.

 

 

Performance

겸사겸사로 추가된 내용들이 많지만 결국 UI로 동작들을 구현해 버리면 성능상에 좋지 않은 건 사실이고 권장되는 방식도 아니다.

가장 큰 이유는 UI는 변경될 때마다 캔버스가 리빌드를 돌리기 때문에 이러한 동작이 과도하게 발생되며 이 연산은 CPU에서 처리하기 때문에 신경이 안 쓰일 수 없지만 어느 정도 타협해서 사용한다면 괜찮지 않을까 생각도 든다.

 

UI로 만들어봤자 엄청나게 복잡한 게임도 아닐 것이고 퍼즐 게임 정도면 성능상에 이슈를 발생시킬 만큼은 아닐 것이라고 감히 예상한다.

 

정말 괜찮은지는 프로파일링을 해봐야겠지만 궁금하기도 하니 나중에 시간 날 때 게임 오브젝트와 UI로 구현한 것을 각각 최대한 비슷하게 만들어 놓고 성능을 한 번 비교해 보는 것이 괜찮을 것 같다.

 

728x90
반응형

유니티에서 개발을 하면서 에셋을 이것저것 가져와서 필요한 걸 골라서 사용하기도 한다.

 

여러 가지 사운드 리소스를 틀어가면서 적당한 걸 고르는 경우나 이미지를 돌려가며 잘 어울리는 걸 선택하는 경우가 있다.

 

하지만 에셋을 여러 경로에서 다운로드하다 보면 폴더의 경로나 파일의 네이밍이 제각각이기 때문에 하나씩 틀어보는 게 쉽지 않다.

 

이럴 때 특정 유형의 리소스만 모아서 보는 게 편한데 프로젝트 창의 검색 기능을 활용하여 특정 유형의 파일만 모아서 볼 수 있다.

 

Unity - Project Window

 

 

- 텍스처 파일 검색 : 't:Texture2 D'

- 오디오 파일 검색 : 't:AudioClip'

- 프리팹 검색 : 't:Prefab'

- 스크립트 파일 검색 : 't:Script'

- 머티리얼 검색 : 't:Material'

- 애니메이션 검색 : 't:AnimationClip'

- 모델 검색 : 't:Model'

 

Unity - Project Window / Sreaching

 

 

't:<타입>'은 특정 타입의 에셋을 검색하는 키워드이다.

<타입>에 원하는 유형으로 검색하여 원하는 에셋을 찾기 쉽다.

 

그 밖에도 유니티 검색창에서 사용할 수 있는 특정 키워드가 존재한다.

 

'l:<레이블>' : 특정 레이블이 있는 에셋을 검색한다.

레이블은 에셋을 그룹화하는 데 사용할 수 있는 태그 같은 것으로 에셋을 선택하고 인스펙터 창의 하단에 있는 UI를 통해서 레이블을 확인하고 변경하거나 추가할 수 있다.

 

새로운 레이블을 추가하는 방법은 원하는 이름을 작성하고 엔터를 입력하면 추가된다.

Assets Labels

 

이 기능들은 검색창의 옆에 있는 토글들을 통해서도 사용할 수 있다.

 

Unity - Search by Type / Search by Label

 

728x90
반응형

바이너리와 텍스트(YAML) 비교

비주얼 스튜디오에서 바이너리를 볼 수 있는 확장 툴을 설치해서 해당 파일을 분석해 본다.

 

프로젝트 설정 중에서 에셋 데이터를 관리하는 방식인 바이너리와 텍스트 두 가지에 대해서 몇 가지 테스트를 해볼 것이다.

두 방식을 비교해 보기 위해서 프로젝트에서 모든 컴포넌트의 데이터가 동일한 오브젝트를 생성해 보고 차이점을 비교한다. 

 

하이어라키에서 큐브를 생성하고 프리팹으로 만들어 파일을 확인해 본다.

.prefab Text

파일의 크기는 3kb이며 파일 내용은 YAML 형식으로 오브젝트의 모든 컴포넌트의 정보가 저장되어 있다.

길이는 100줄 정도 된다.

.prefab Text view

 

데이터 내용을 그대로 보아도 어떤 정보를 담고 있는지 파악하기 쉽다.

 

그대로 프로젝트 세팅에서 Asset Seriailization 모드를 Force Binary로 변경한다.

 

.prefab Binary

 

용량이 더 줄어들었을 거라고 예상했지만 반대로 증가했다.

 

.prefab Binary view

 

파일의 마지막은 다음과 같이 정보를 보여준다.

좌측의 메모리주소와 우측의 아스키코드에 대응하는 문자는 편집기의 기능으로 데이터에 포함되지 않는 정보일 것이다.

Binary

 

맨 앞의 8자리 숫자+알파벳의 조합은 16진수로 보인다.

이 주소가 16 단위로 증가하고 뒤에 오는 정보는 8 + 8 총 16으로 정보의 개수를 의미하는 것 같다.

ASCII

메모리 주소 뒤에 오는 행렬 형태의 정보는 아스키코드로 보이는데 아스키 테이블에서 20은 공백, 3C는 < 로 확인할 수 있다. 따라서 맨 우측에는 테이블에 대응하는 문자를 확인된다.

 

마지막 주소가 2030으로 10진법으로 변환 시 8240이다. 즉 총 8240개의 데이터가 담겨있으며 파일의 크기가 9kb인 것으로 생각해 볼 때 하나에 1byte로 떨어지고 각 데이터가 아스키코드이므로 1byte라고 생각하면 얼추 맞아떨어지는 거 같다.

 

파일크기는 9kb로 나오는데 해당 파일을 속성을 열어서 자세히 보면

.prefab size

더 근접한 크기임을 알 수 있다. 

 

좀 더 정밀하게 계산하면 마지막 줄에는 데이터 4개가 빠져있어서 8236이다. 즉 최종적으로 16byte가 모자라다.

만약 마지막 메모리가 온전히 16을 차지한다고 해도 8240이 최대일 텐데 그래도 12byte가 채워지지 않는다.

 

어디서 계산이 잘못된 건지 이 부분은 다시 확인해 볼 필요가 있다.

 

다시 본래의 목적으로 돌아가서 YAML 형식이 바이너리보다 용량이 적은 것은 의문이 들어서 프리팹의 크기를 키워보기로 한다. 기존의 큐브 프리팹에 자식으로 큐브를 추가해서 수정해 결과를 확인해 본다.

 

+1 cube biary

 

바이너리의 경우 768 byte 가 추가되었다.

 

모드를 변경해서 Text의 크기를 확인해 보니 6kb로 처음 경우에서 2배로 사이즈가 커졌다. 증가량만 따졌을 때는 엄청난 크기 차이가 있다.

 

몇 번 더 큐브를 추가해 보면서 살펴본다.

큐브 개수 / 파일 사이즈(kb)  Binary Text
1 9 3
2 9 6
3 10 9
4 11 12
20 23 56
100 82 276

 

프리팹에 오브젝트가 많이 포함되어 있을수록 파일의 사이즈는 확연히 차이가 난다.

게임을 만들다 보면 프리팹 하나에 여러 오브젝트들이 붙어있게 되는 경우는 많기 때문에 거의 일반적으로 Text 모드가 용량이 크다고 보인다.

 

비교

테스트 결과로 비교해 보면 바이너리를 사용하는 것이 데이터의 크기를 줄여주기 때문에 프로젝트를 열고 데이터를 저장하는 과정에서 시간이 단축될 수 있다.

 

하지만 유니티를 사용한 프로젝트를 협업할 때에는 바이너리보다는 Text 가 권장된다. Github에서는 공식문서에서 해당 부분에 대하여 Force Text로 설정해야 한다고 명시해 두었다.

 

Github unity Asset Serialization

 

Github - Git and Unity

 

Git and Unity

Git and Unity. GitHub Gist: instantly share code, notes, and snippets.

gist.github.com

 

유니티에서도 기본값은 Force Text이며 이렇게 Force Text를 권장하는 이유는 바이너리 형식으로는 파일을 수정하고 병합하는 것이 불가능하다. 따라서 변경된 사항을 파악하는 것이 불가능한데 협업뿐만 아니라 개인 프로젝트 또한 버전 컨트롤을 사용하는 것이 일반적인데 해당 기능을 사용하지 못하는 Mixed 또는 Binary 모드는 더 이상은 사용되지 않는 기능으로 생각된다.

 

 

 

728x90
반응형

에디터 버전 : 2021.3.28f1 (LTS)

 

유니티 에디터의 전체적인 설정을 변경할 수 있는 항목이다.

Unity Remote [Depricated]

Android, iOS 등 앱을 개발할 때 사용하기 위한 기능으로 유니티 플레이 모드에서 화면 출력과 입력이 디바이스와 연결되도록한다. 따라서 빌드 이전 단계에서 타겟 디바이스를 통한 테스트가 가능하다.

 

2020.1 및 이후 버전에서는 depricated 되었으며 Device Simulator Package가 기능을 대신한다.

 

Device Simulator Package

2020 이후 버전이라면 에디터에 기능이 포함된 상태로 Window > General > Device Simulator 를 통해 사용할 수 있다.

Device Simulator

 

이전 버전의 경우 패키지를 설치해 주어야 창을 열 수 있다.

패키지 매니저를 통해서 설치가 가능하며 이 때 패키지가 검색해도 나오지 않는 경우 

패키지 매니저 창에서 어드밴스 설정에 들어가서 

Pre-release Package 옵션을 활성한 이후에 패키지를 검색하면 찾을 수 있다.

Advanced Project Settings

 

Enable Pre-release Package

 

Asset Serialization

프로젝트를 저장할 때 에셋들의 정보를 저장하는 방식에 대해서 설정할 수 있는 옵션이다.

Asset Serialization

 

Serialization 옵션에는 세가지가 있다.

 

Mixed

에셋이 바이너리와 문자열 각각의 저장된 상태로 유지된다. 새로 추가되는 에셋의 경우 바이너리가 적용된다.

 

Force Binary

에셋을 바이너리로 저장한다. 

임의의 프리팹을 생성하고 파일을 열어보면 바이너리로 저장된걸 확인할 수 있다.

Unity .prefab binary view

 

비주얼 스튜디오에서 파일이 열리지 않는 경우 Extensions > Manage Extensions 에서 HexVisualizer 를 설치하면 된다. 이때 실행중인 비주얼 스튜디오는 모두 종료해야 설치가 진행된다.

VS Manage Extensions-HexVisualizer

 

Force Text

에셋을 문자열로 저장한다.

Unity .prefab Text

저장된 정보는 텍스트 기반으로 데이터 직렬화 언어로 많이 사용되는 YAML 형식이다.

프리팹의 정보가 키&밸류 형태로 정리되어있어  바이너리와 달리 사람이 쉽게 읽을 수 있도록 표현되었다.

 

Force Text 모드에서 프리팹을 생성하고 Mixed 모드로 변경시 기존 프리팹은 텍스트, 새로 생성된 프리팹은 바이너리로 저장된다.

 

Left Text, Right Binary

 

Mixed 또는 Force Text 를 선택한 경우 Serialize Inline Mappings On One Line 토글이 활성화된다.

이 옵션은 참조 및 인라인 맵핑을 한 줄에 쓸것인지 여부를 정한다. 비활성화시 한 줄의 총 문자가 80자 이상이 되면 텍스트가 분할된다.

 

Default Behaviour Mode

프로젝트를 처음 생성시 2D 또는 3D를 선택하는데 프로젝트 생성 이후에도 해당 설정에서 변경이 가능하다.

Unity Default Behaviour Mode

 

유니티에서는 프로젝트가 Full 2D 인 경우 이외에는 모두 3D 로 작업환경을 정할 것을 추천한다.

 

2D와 3D 설정에는 프로젝트의 몇가지 기본세팅에서 차이가 있다.

 

2D

- Import 하는 모든 영상은 2D 이미지로 간주되며 Sprtie로 설정된다.

- Scene View 가 2D로 세팅된다.

- 게임 오브젝트가 기본적으로 실시간 Directional light 의 광원을 받지 않는다.

- 카메라의 기본 위치가 0, 0, -10 으로 설정된다.

- 카메라가 Orthographic 으로 설정된다.

- Lighting 창의 옵션의 경우

   * 새로운 씬에 대해서 Skybox가 비활성화

   * Ambient Source 는 Color(54, 58, 66) 로 설정

   * Realtime Global Illumination(Enlighten) 꺼짐 상태

   * Baked Global Illumination 꺼짐 상태

   * Auto-Building 꺼짐 상태

 

3D

- Import 한 모든 이미지가 2D 이미지로 간주되지 않는다.

- Sprite Packer 가 비활성화된다.

- Scene View 는 3D로 설정된다.

- 기본 게임 오브젝트가 리얼 타임 Directional Light 광원을 받는다.

- 카메라의 기본 포지션은 0, 1, -10 으로 설정된다.

- 카메라가 Perspective 로 설정된다.

- Lighting 창의 경우

  * Skybox 는 built-in Default Skybox 로 설정

  * Ambient Source 는 Skybox 로 설정

  * Realtime Global Illumination (Enlighten) 켜짐 상태

  * Baked Global Illumination 켜짐 상태

  * Auto-Building 켜짐 상태

 

차이점을 보면 2D에서 3D 작업을 한다고 해서 치명적인 문제가 발생하지는 않는다.

하지만 몇가지 기본 설정들은 각 상황에서만 사용하는 경우가 많기 때문에 맞춰서 작업하는것이 권장된다.

 

728x90
반응형

에디터 버전 : 2021.3.28f1 (LTS)

 

Audio

오디오 시스템을 구성하는 데 사용되는 설정으로 모든 Audio 컴포넌트에 영향을 미치는 전역적인 설정을 제공한다.

 

Unity Project Settings - Audio

 

Global Volume

오디오 시스템의 볼륨을 전역으로 적용한다.

Audio - Global Volume

볼륨의 초기값에 곱해주는 수로 AudioListner.volume과 동일하다.

 

Volume Rolloff Scale

볼륨이 감쇠되는 정도를 전역으로 조절한다. 

Audio Volume Rolloff Scale

단 Logarithmic Volume Curves 인 경우에만 적용된다.

Logarithmic Volume Curves는 로그 함수 곡선형태로 사운드가 감쇠되는 경우에만 적용되는데 이 사운드는 Audio Source 컴포넌트의 속성값 중에 3D Sound Settings의 Volume Rolloff에서 선택할 수 있는 옵션이다.

( 기본으로 Logarithmic Rolloff 설정 )

 

값은 기본적으로 1로 되어있는데 이 값이 현실에 가장 가까운 수치이다.

 

Doppler Factor

소리에 도플러 효과(Doppler Effect)를 적용시키기 위한 수치이다. 

Audio Doppler Factor

원하는 도플러 효과를 얻기 위해서 해당 수치를 조절할 수 있다.

 

Doppler Effect

도플러 효과란 파동의 진동수가 왜곡되는 현상이다. 음원(소리의 근원지)가 움직이면서 파원이 다가오고 있을 때 정지한 관찰자에게는 파동의 파장이 실제보다 짧게 느껴지고 다시 멀어지게 되면 파장이 실제보다 길게 느껴지는 것이다.

 

예를 들어 멀리서부터 소방차가 사이렌을 켜고 달려오고 있다. 이때 멀리서부터 나에게 가까워지는 동안에는 사이렌의 소리가 점점 높아지는 것처럼 들리다가 내 옆을 지나쳐 멀어질 때는 낮아지는 것처럼 느껴진다. 하지만  이는 상대적인 효과로 관찰자만 느끼는 현상이고 소방차에 탑승한 사람에게는 일정한 소리로 들린다.

 

유니티의 프로젝트 세팅에서 Doppler Factor 수치는 기본적으로 1이다. 이 수치는 소리의 움직임이 실제 도플러 효과와 거의 동일하게 시뮬레이션되며 값이 0에 가까워질수록 도플러 효과가 감소하고 값이 높아질수록 강조된다.

 

Default Speaker Mode

프로젝트의 오디오 출력을 설정할 수 있는 옵션이다. 유니티 엔진에서 오디오가 재생될 때 사용되는 스피커의 타입을 지정할 수 있다.

Audio - Default Speaker Mode

옵션의 종류는 다음과 같다.

Default Speaker Mode - Option

 

Mono

채널 개수가 1개이다.

오디오를 단일 스피커에서 재생한다. 오디오 소스는 좌우 채널이 결합된 단일 스피커로 재생된다. 

주로 모노 오디오 효과나 음성 등 단일 채널 오디오를 재생하는 데 사용된다.

 

Stereo

채널 개수가 2개이다.

좌우 스피커에서 각각의 채널이 재생된다. 대부분의 오디오에서 사용되는 일반적인 스테레오 효과를 재생할 때 사용되며 기본으로 선택된 설정이다.

 

Quad

채널 개수가 4개이다.

전후좌우  4개의 스피커에 각각의 채널이 재생되며 3D 오디오 효과를 표현할 수 있다.

 

Surround

채널 개수는 5개이다.

전면 좌우, 중앙, 후면 좌우 5개의 스피커를 사용한다. 더 입체적인 공간 음향 효과를 재생할 수 있다.

 

Surround 5.1/7.1

채널 개수는 5개 이상이다.

전면 좌우, 중앙, 후면 좌우 + 서브 우퍼 채널을 통해 사운드가 재생된다.

 

Prologic DTS(Digital Theater System)

채널 개수는 2개이다.

스피커는 스테레오로 출력되지만 데이터는 Prologic/Prologic2 디코더에서 인식하고 5.1 채널 스피커로 분리되도록 인코딩 된다.

 

System Sample Rate

출력되는 샘플 레이트를 설정한다. 해당 수치를 조절하면 오디오 주파수의 표현 범위를 조정할 수 있다. 0으로 설정하면 시스템의 샘플 레이트를 사용하고 0 이외의 값을 설정하면 입력한 값을 샘플 레이트로 사용하게 된다. iOS나 Android와 같은 특정 플랫폼에서 샘플 레이트를 변경할 수 있는 경우에만 해당한다.

 

Sample Rate

샘플의 빈도수 즉, 1초당 추출되는 샘플의 개수를 뜻한다. 샘플 레이트의 수치가 높을수록 정확한 음원을 저장할 수 있지만 그만큼 용량이 기하급수적으로 증가한다. 이에 따라 적당한 타협선인 44.1kHz의 샘플 레이트가 일반적으로 사용된다. 

 

DSP Buffer Size

Digital Signal Processing 버퍼 크기

실시간으로 들어오는 오디오 데이터를 처리하고 재생하기 위해서 일시적으로 저장하는 공간의 크기를 설정한다.

Audio - DSP Buffer Size

해당 저장공간이 작으면 오디오 데이터가 빠르게 처리되지만 CPU 부하가 증가하고 지연 시간이 감소한다. 반면에 공간이 큰 경우에는 한 번에 더 많은 오디오 데이터가 처리되므로 CPU부하가 감소하고 지연 시간이 증가한다.

 

DSP Buffer Size

Default

유니티의 기본 DSP 버퍼 크기를 사용한다. 대부분의 경우 적절한 응답성과 지연 시간을 제공하는 안정적인 설정이다.

 

Best latency

지연 시간을 고려하여 성능을 절충한다. 더 낮은 지연 시간이 요구되는 실시간 애플리케이션에 적합하다. CPU 부하가 증가할 수 있고 낮은 CPU 성능에서는 문제가 발생할 수 있다.

 

Good latency

지연 시간과 CPU 성능의 균형을 유지한다. 일반적인 오디오 처리 요구 사항을 충족하는데 적합하다.

 

Best performance

CPU 성능을 유리하도록 지연시간을 맞춘다. 높은 오디오 처리 요구 사항이 있거나 더 많은 CPU 성능을 활용해야 하는 경우에 적합하며 지연 시간이 증가할 수 있다.

 

Max Virtual Voices

Audio - Max Virtual Voices

오디오 시스템이 관리할 수 있는 최대 사운드의 개수를 설정한다. Real Voices의 수보다 크게 설정되어야 하며 그렇지 않은 경우 콘솔에서 경고 메시지가 표시된다. 가장 큰 소리들 중에서 Max Real Voices 수만큼만 실제로 재생되고 나머지 소리들은 재생 위치만 업데이트된다.

 

Max Real Voices

Audio - Max Real Voices

게임에서 동시에 재생 가능한 실제 음성의 수를 설정한다. 매 프레임마다 가장 큰 음성이 선택된다.

 

Spatializer Plugin

Audio - Spactializer Plugin

공간화된 오디오 처리를 수행하기 위한 플러그인이다. 오디오를 공간적으로 위치시키고 음향 효과를 적용하여 3D 소리의 현실감을 높이는 데 사용된다.

 

일반적으로 게임 엔진이나 오디오 미들웨어에서 제공되며 다양한 기능과 설정을 제공한다. 오디오 원본의 위치, 방향, 거리 등을 고려하여 소리를 공간 내에서 정확하게 재생할 수 있으며 일반 스피커 시스템이나 헤드폰을 사용하는 경우, 소리가 사용자 주변에서 움직이거나 공간의 특정 위치에서 들리는 것처럼 느껴지게 된다.

 

해당 기능을 사용하기 위해서는 해당 플러그인의 최신 SDK 설치가 필요하다.

현재 버전을 기준으로 공식문서에서 안내되는 플러그인 다운링크

 

Ambisonic Decoder Plugin

Audio - Ambisonic Decoder Plugin

Ambisonic을 Binaural 필터링하기 위한 플러그인을 설정할 수 있다.

유니티에서 제공되는 빌트인 디코더는 없으며 일부 VR 하드웨어 제조사의 경우 오디오 SDK에 유니티용 빌트인 디코더가 있다. 타깃 플랫폼 제조사의 문서를 통해 프로젝트에 적합한지 확인할 수 있다.

 

Ambisonic 오디오 클립을 임포트 하려면 임포트 한 파일의 Ambisonic 옵션을 체크해야 한다.

Import Ambisonic Audio Clip

Ambisonic 클립을 사용하기 위해서는 Audio Source 컴포넌트의 Spatialize 옵션을 비활성화해야 하고 해당 클립이 재생될 때 자동으로 프로젝트에서 선택된 플러그인을 통해서 디코딩된다.

 

Ambisonic

다중 마이크로폰 배열을 사용하여 소리의 공간 정보를 캡처하는 방법이다. 소리의 방향, 거리, 공간 위치 등을 캡처하여 공간적으로 정확한 사운드 재생을 가능하게 한다. 일반적으로 360도 환경 음향을 재현하거나 VR 및 3D 오디오 환경에서 사용된다. 다중 채널 포맷으로 저장되고 Ambisonic을 사용하면 각 채널을 특정 스피커에 매핑하지 않고 사운드필드가 더 전체적인 방법으로 표현된다. 

Binaural

인간의 이중귀를 모방하여 소리를 전달하는 기술이다. 두 개의 이어폰 또는 헤드폰을 사용해서 소리를 개별적으로 각 귀에 전달함으로 공간적인 사운드 경험을 제공한다. 3D 오디오를 더욱 현실적이고 공간적으로 인지할 수 있도록 한다.

 

Disable Unity Audio

Disable Unity Audio

런타임에 출력 장치를 할당하지 않도록 설정한다. 내장된 오디오 시스템 이외의 다른 사운드 시스템을 사용하는 경우에 활성화하는 옵션이다. 

 

Enable Output Suspension (editor only)

Enable Output Suspension

출력이 오랜 시간 동안 정지된 것이 감지되면 자동으로 오디오 출력을 일시 중단시킨다. 오디오 시스템을 중단하면 컴퓨터가 절전 모드로 전환되는 것을 방지하는 운영 체제의 기능이 비활성화되고 이를 통해 오랜 시간 동안 정지된 오디오 출력으로 인해 컴퓨터가 절전 모드로 전환되는 것을 방지할 수 있다. 주로 배터리 수명을 연장하거나 오디오가 정지된 상태에서 시스템의 에너지 소비를 최소화하기 위해 사용된다.

 

해당 설정은 기본적으로 활성화되어 있다.

 

Visualize Effects

컬링 되는 오브젝트의 Audio Source에서 Spatializer를 동적으로 비활성화하여 CPU를 절약한다. 

즉 카메라에 의해 렌더링 되지 않는 오브젝트에 대한 오디오 처리를 제한시킨다.

728x90
반응형

+ Recent posts