[Unreal Engine] Input Framework of Unreal Engine(relating to UMG/Slate)

Imeamangryang·2025년 6월 30일

Unreal UMG & Slate UI

목록 보기
10/13
post-thumbnail

Input Framework of Unreal Engine(relating to UMG/Slate)

Input Flow of Unreal Engine

입력(Input)이 가장 하위 레벨에서 상위 레벨로 어떻게 흐르는지에 대한 전체적인 개요입니다. 아래는 각 사용자의 입력이 Unreal Engine에서 라우팅되는 순서대로 정리한 단계별 흐름입니다(각 단계는 다음 단계로 입력을 전달합니다):

  1. 엔진 하트비트 틱 FEngineLoop: Unreal Engine의 하트비트 틱으로, 플랫폼 SDK에 매 프레임마다 틱/업데이트를 알립니다.
  2. 플랫폼 API GenericApplication & FGenericApplicationMessageHandler: Windows/Mac/Xbox/Playstation 등 각 플랫폼의 SDK로, 엔진 초기화 시 Slate Application을 생성하고, 매 프레임마다 사용자별 입력을 전달합니다.
  3. Slate Application FSlateApplication: 입력을 Input Processor, Slate UI, 게임 엔진(게임 코드)으로 라우팅합니다.
  4. Input Processor 선택적 IInputProcessor: Slate Application 내에 동적으로 추가/제거할 수 있는 C++ 객체로, 모든 입력을 가장 먼저 받아 처리하며, 입력을 소비할지 계속 라우팅할지 결정합니다.
    프로젝트별로 직접 구현하는 것이 권장되며, 엔진 내 Epic 예제(AnalogCursor)도 참고할 수 있습니다.
    Input Mode UI Only 상태나 에디터에서도 입력을 받을 수 있습니다.
  5. Slate UI 요소 SWidget: 화면에 포커스된 UI 요소로, 입력을 받아 소비할 수 있습니다.
  • UMG 위젯 UWidget도 여기서 입력을 받습니다(UMG 위젯은 Slate 위젯을 감싸는 UObject 기반 래퍼입니다).
  1. Game Viewport Client UGameViewportClient: Slate Application에서 Slate 요소로 전달된 입력이 소비되지 않으면, 뷰포트 위젯(게임의 최종 렌더 이미지를 나타내는 Slate 위젯)으로 전달되고, 여기서 Game Viewport Client로 라우팅됩니다.
    Game Viewport Client는 입력을 게임 엔진의 나머지 부분으로 전달하며, 게임 코드와 연결합니다.
    이 단계에서 Input Mode(Game, Game and UI 등)에 따라 Pawn이 입력을 받을 수 있습니다.
  2. Player Controller APlayerController: Game Viewport가 입력을 받으면, 게임 코드에서 사용할 수 있는지 확인한 뒤, Player Controller의 Input Stack에 추가합니다(ProcessPlayerInput에서 처리, Player Controller의 Tick에서 호출됨).
  3. Player Input UPlayerInput: Player Controller가 보유한 객체로, 입력을 Pawn 및 Input Stack에 있는 다른 객체로 라우팅합니다.
  4. Input Component UInputComponent: 게임 코드에서 입력을 받는 가장 일반적인 방법으로, 모든 액터에 존재하며 Player Controller의 Input Stack과 연결되어 엔진을 통해 입력을 전달받아 게임 코드에서 사용할 수 있습니다.

입력 흐름 다이어그램


Input Components

Input Component는 모든 액터(AActor)에 존재하는 UActorComponent입니다.
이 컴포넌트는 프로젝트의 Axis Mapping과 Action Mapping에 바인딩되어 기능을 실행할 수 있습니다.
각 바인딩은 입력 이벤트를 소비(Consume)할 수 있으며, 한 Input Component가 입력 이벤트를 소비하면 입력 스택의 다른 컴포넌트에서는 해당 이벤트를 처리할 수 없습니다.
Input Component를 사용하면 액터가 입력 이벤트를 델리게이트 함수에 바인딩하여 자동으로 처리할 수 있습니다.
이러한 입력 처리는 두 개의 클래스에 의해 관리됩니다:

  • APlayerController:: 입력 스택을 구성하고, 입력 처리 순서와 우선순위를 제어합니다.
  • UPlayerInput:: 델리게이트 함수 브로드캐스트 및 바인딩 사용 여부 판단을 담당합니다.

아래는 실제로 매 프레임마다 입력 컴포넌트가 처리되는 순서입니다. 아래 다이어그램 참고

  1. [APlayerController::TickPlayerInput]
    1. [UPlayerInput::Tick]
    2. 마우스 오버 이벤트 수집
    3. 터치 오버 이벤트 수집
    4. [APlayerController::ProcessPlayerInput]
      1. [APlayerController::BuildInputStack]: 입력 컴포넌트 스택을 빌드하고 처리 순서를 결정합니다. 오버라이드하여 순서 제어 가능.
      2. [UPlayerInput::ProcessInputStack]: 실제 입력 처리 시작.
        1. [APlayerController::PreProcessInput]
        2. 논-축(key) 상태 복사
          1. 입력 컴포넌트 스택을 위에서 아래로 하나씩 순회(각 루프마다 하나의 입력 컴포넌트 처리)
            1. 이 입력 컴포넌트의 키맵을 빌드하여 어떤 액션/축이 어떤 키 바인딩과 연결되는지 파악
            2. 터치 바인딩을 찾아 입력 액션 바인딩이 발생했는지 판단, 발생했다면 추적
            3. 제스처 바인딩을 찾아 입력 액션 바인딩이 발생했는지 판단, 발생했다면 추적
            4. 축 바인딩을 찾아 입력 축 바인딩이 발생했는지 판단, 발생했다면 추적
            5. 키를 소비할지 여부 결정(키맵 빌드와 이 단계 사이의 기록을 바탕으로)
        3. 각 입력 컴포넌트의 축 바인딩 값을 0으로 리셋
        4. 입력 액션을 해당 입력 컴포넌트에 브로드캐스트
        5. 입력 축을 해당 입력 컴포넌트에 브로드캐스트
        6. [APlayerController::PostProcessInput]
        7. [UPlayerInput::FinishProcessingPlayerInput]: 이번 프레임의 입력 처리를 마무리하며, 입력이 유지되는지 저장하고 다음 프레임을 위해 값 정리
        8. 브로드캐스트된 모든 바인딩 초기화
      3. 다음 프레임을 위해 입력 스택 리셋
    5. [APlayerController::ProcessForceFeedbackAndHaptics]

레벨에서 입력이 틱(Tick)되고 처리되는 순서(즉, APlayerControllerTickPlayerInput에서 시작하는 입력 처리 순서)

입력 컴포넌트는 우선순위 스택을 가지며, 우선순위가 높은 액터가 먼저 입력을 소비할 수 있습니다. \
입력 컴포넌트의 우선순위 스택은 다음과 같습니다(높은 우선순위가 먼저 처리됨):
입력 컴포넌트의 우선순위 스택은 다음과 같습니다(높은 우선순위가 먼저 처리됨):

  1. "입력 허용(Accepts Input)"이 활성화된 액터들(가장 최근에 활성화된 순서대로 우선순위가 높음)
    1. 액터의 "입력 허용"을 다시 활성화하면 이 스택의 최상위로 이동합니다.
  2. 플레이어 컨트롤러(Player Controllers)
  3. 레벨 스크립트(Level Script)
  4. 폰(Pawns)

입력 컴포넌트 스택, Epic 공식 문서 참고


Input Event Types

입력이 발생할 때마다 각 입력 유형에 대해 FInputEvent를 상속하는 구조체가 사용됩니다:

  • FInputEvent: 모든 마우스, 키보드, 터치/모션 이벤트의 기본 구조체입니다.
    • Modifier Keys FModiferKeysState: 이 이벤트가 발생한 프레임의 수정 키(Shift, Ctrl 등) 상태.
    • Is Repeat bool: 입력이 자동 반복(길게 눌러 반복 발생)된 것인지 여부.
    • User Index uint32: 이 이벤트를 발생시킨 Slate User의 인덱스.
    • Event Path const FWidgetPath*: 이 이벤트와 함께 전달되는 이벤트 경로.

모든 입력 이벤트 타입은 FInputEvent에서 파생됩니다:

  • FKeyEvent FInputEvent: 키보드/게임패드의 키가 눌림/해제될 때의 이벤트. 해당 키 입력을 처리하는 이벤트 핸들러에 전달됩니다.
    • Key FKey: 눌린 키의 이름.
    • CharacterCode uint32: Unreal에서 사용하는 문자 코드(해당 키가 문자일 경우). 해당되지 않으면 0 반환.
    • KeyCode uint32: 하드웨어/SDK에서 받은 원본 문자 코드.
  • FAnalogInputEvent FKeyEvent: 아날로그 입력(예: 스틱 축 값)을 나타냅니다.
    • AnalogValue float: 0~1 값으로, 0은 미입력, 1은 최대 입력.
  • FCharacterEvent FInputEvent: 키보드에서 UTF-16 코드(16비트 유니코드)가 입력될 때의 이벤트. OnKeyChar 기능에 사용.
    • Character TCHAR: 입력된 문자.
  • FPointerEvent FInputEvent: 마우스/터치 입력(터치도 마우스 입력으로 간주, 항상 좌클릭으로 처리). Press/Release/Move 등 다양한 정보를 포함합니다.
    • ScreenSpacePosition FVector2D: 현재 포인터의 화면 좌표.
    • LastScreenSpacePosition FVector2D: 이전 프레임의 포인터 화면 좌표.
    • CursorDelta FVector2D: 현재와 이전 위치의 차이.
    • PressedButtons const TSet<FKey>*: 현재 눌려 있는 마우스 버튼 집합.
    • EffectingButton FKey: 이 이벤트가 나타내는 마우스 버튼(터치는 항상 좌클릭).
    • PointerIndex uint32: 이 Slate User의 포인터(손가락) 인덱스.
    • TouchpadIndex uint32: 터치패드 사용 시 포인터 인덱스.
    • Force float: 터치/포인터 입력에 가해진 힘.
    • IsTouchEvent bool: 터치(트랙패드 포함) 기반 이벤트인지 여부.
    • GestureType EGestureType: 스와이프, 스크롤, 확대, 회전, 롱프레스 등 제스처 타입.
    • WheelOrGestureDelta FVector2D: 이전 제스처 이벤트 이후의 변화량.
    • IsDirectionInvertedFromDevice bool: 제스처 방향이 디바이스 기준으로 반전되었는지 여부.
    • IsTouchForceChanged bool: 터치 힘 변화 이벤트인지 여부.
    • IsTouchFirstMove bool: 첫 이동 터치 이벤트인지 여부.
  • FMotionEvent FInputEvent: 내부 자이로스코프를 사용하는 터치패드 이벤트(기울임, 회전 등).
    • Tilt FVector: 디바이스/컨트롤러의 현재 기울기.
    • RotationRate FVector: 디바이스/컨트롤러의 회전 속도.
    • Gravity FVector: 실제 중력 방향(지면 방향).
    • Acceleration FVector: 디바이스/컨트롤러의 3D 가속도.
  • FNavigationEvent FInputEvent: 포커스 내비게이션(좌/우/상/하) 이벤트로, User Focus에 사용됩니다.
    • NavigationType EUINavigation: 내비게이션 방향(상/하/좌/우 등).
    • NavigationGenesis ENavigationGenesis: 이 내비게이션 이벤트의 발생 원인(키보드/컨트롤러/사용자 등).

Input Modes

WidgetBlueprintLibrary에는 Player Controller의 Input Mode를 설정하는 3가지 함수가 있습니다.
이 세 가지 상태는 입력 흐름의 6단계(Game Viewport Client)에서 실제로 어떤 일이 일어나는지 설명합니다.
실제로는 별도의 Input Mode가 존재하는 것이 아니라, Player Controller를 통해 Game Viewport Client의 값을 간편하게 변경하는 단축 기능입니다.

Input Mode 값에 대한 변경은 레벨/맵 이동 시에도 유지됩니다.
이는 Unreal Engine의 기본 기능을 사용하든, Game Viewport Client에서 직접 수동으로 값을 변경하든 동일하게 적용됩니다.

  • Input Mode UI Only: Game Viewport Client에 입력을 무시하도록 지시합니다.
    즉, Game Viewport Client가 입력을 받아도 이후 단계로 전달하지 않고,
    마우스 포인터를 해제하여 뷰포트(또는 Mouse Lock Mode 설정에 따라 뷰포트 밖)에서 자유롭게 클릭할 수 있습니다.
  • Input Mode Game Only: Game Viewport Client가 입력을 받을 수 있도록 허용합니다.
    즉, 입력이 이후 단계로 정상적으로 전달되고,
    마우스 포인터가 뷰포트에 고정되어 뷰포트 내에서만 클릭이 가능합니다.
  • Input Mode Game & UI: Game Viewport Client가 입력을 받을 수 있도록 허용하면서,
    마우스 포인터도 해제하여 뷰포트(또는 Mouse Lock Mode 설정에 따라 뷰포트 밖)에서 자유롭게 클릭할 수 있습니다.

Input Modes Video Example

마우스 락 모드(EMouseLockMode)는 마우스 커서가 뷰포트(화면) 경계를 벗어나지 못하도록 잠그는 방식을 지정합니다. 각 모드는 다음과 같이 동작합니다:

  • Do Not Lock(잠그지 않음): 마우스 커서를 뷰포트에 잠그지 않습니다.
  • Lock On Capture(캡처 시 잠금): 뷰포트가 마우스 입력을 캡처할 때(클릭 또는 상호작용 시)만 커서를 뷰포트에 잠급니다.
  • Lock Always(항상 잠금): 항상 마우스 커서를 뷰포트에 잠가, 커서가 뷰포트 밖으로 나갈 수 없습니다.
  • Lock in Fullscreen(전체화면에서만 잠금): 전체화면 모드일 때만 마우스 커서를 뷰포트에 잠급니다.

참고: 마우스 락 모드는 각 뷰포트(플레이어별 분할 화면 포함) 단위로 적용됩니다. "Window" 모드는 모든 뷰포트를 포함한 전체 창(Window) 기준으로 동작합니다.

profile
언리얼 엔진 주니어 개발자 입니다.

0개의 댓글