안동민 개발노트

본문 시작

환경과 상호작용하는 오브젝트 설정

입력·트리거·참조·상태 변화를 연결해 문 열기 예제를 구현하고 재사용 가능한 환경 상호작용 구조를 익힙니다.

이전 챕터들에서 조명, 날씨, 시간 같은 시각 요소와 물리 엔진, 충돌 같은 물리 요소를 다듬어 레벨의 기반을 만들었습니다.

이제는 그 기반 위에 플레이어의 행동이 실제로 세계를 바꾸는 환경 상호작용(Environmental Interaction)을 올릴 차례입니다.

문을 열고, 스위치를 누르고, 아이템을 줍는 순간처럼 월드가 즉시 반응할 때 게임은 훨씬 더 살아 있게 느껴집니다.

이번 절에서는 언리얼 엔진에서 이런 상호작용을 안정적으로 구성하는 방법을 단계적으로 다룹니다.

이 흐름을 익히고 나면 플레이어가 내가 세계에 영향을 주고 있다는 감각을 자연스럽게 전달할 수 있습니다.


환경 상호작용의 중요성

환경 상호작용은 게임 플레이의 핵심이자 레벨 디자인의 중요한 부분입니다.

  • 몰입감 증대: 플레이어가 주변 환경에 영향을 미치고, 환경이 플레이어의 행동에 반응할 때 게임 세계는 더욱 현실적이고 몰입감 있게 느껴집니다.
  • 게임 플레이 다양성: 스위치 조작, 문 열기, 퍼즐 풀이, 아이템 획득 등 다양한 상호작용은 게임 플레이에 깊이와 다양성을 더합니다.
  • 내러티브 강화: 환경과의 상호작용은 스토리를 진행하거나, 세계관에 대한 정보를 제공하는 중요한 수단이 될 수 있습니다.
  • 문제 해결 및 탐험 유도: 잠긴 문을 열거나 숨겨진 스위치를 찾는 등의 상호작용은 플레이어에게 문제 해결과 탐험의 동기를 부여합니다.

기본적인 환경 상호작용 구현 요소

언리얼 엔진에서 환경 상호작용을 구현하기 위해 주로 사용되는 액터, 컴포넌트, 그리고 개념들은 다음과 같습니다.

트리거 (Triggers)

트리거는 플레이어(또는 다른 액터)가 특정 영역에 진입하거나 이탈했을 때 이벤트를 발생시키는 투명한 볼륨입니다.

상호작용의 시작을 감지하는 가장 기본적인 방법입니다.

  • 종류
    • Box Collision (박스 충돌): 가장 흔히 사용되는 사각형 형태의 트리거.
    • Sphere Collision (구 충돌): 원형 또는 구 형태의 트리거.
    • Capsule Collision (캡슐 충돌): 캐릭터 충돌에 주로 사용되는 캡슐 형태의 트리거.
  • 생성 및 설정

    레벨 에디터의 액터 배치(Place Actors) 검색에서 Trigger Box나 Trigger Sphere를 찾아 배치합니다.

    또는 기존 액터에 Box Collision 등의 컴포넌트를 추가할 수도 있습니다.

    Details 패널에서 Collision 섹션을 찾습니다.

    Collision Presets
    • OverlapOnlyPawn: 기본 프리셋은 Pawn·Camera·Vehicle에 Overlap 응답을 둡니다. 플레이어 전용 필터는 별도로 필요합니다.
    • OverlapAll: 기본 채널에 Overlap 응답을 둡니다. 상대 채널 응답과 이벤트 생성 옵션도 맞아야 합니다.
    • Custom...: 특정 오브젝트 타입과만 오버랩하도록 세부 설정할 수 있습니다.

    Generate Overlap Events: 트리거와 상대 컴포넌트 양쪽에서 활성화하고 query 충돌도 켜야 합니다.

  • 블루프린트 활용
    • Actor Blueprint에 추가한 충돌 컴포넌트를 선택하고 OnComponentBeginOverlap과 OnComponentEndOverlap 이벤트를 추가합니다. 레벨의 Trigger Actor는 Level Blueprint의 Actor overlap 이벤트로도 연결할 수 있습니다.
    • 이벤트 그래프에서 Other Actor 핀을 Cast To PlayerCharacter (또는 여러분의 플레이어 클래스)로 연결하여, 오직 플레이어에 의해서만 이벤트가 발생하도록 필터링합니다.

상호작용 가능한 오브젝트

문, 스위치, 아이템 등 플레이어가 직접 행동하여 조작하는 오브젝트입니다.

  • 기본 구조

    Static Mesh Component: 오브젝트의 시각적인 형태를 제공합니다. (예: 문의 뼈대, 스위치의 버튼 모델)

    Collision Component: 플레이어가 상호작용 영역에 들어왔는지 감지하거나, 오브젝트와 물리적으로 충돌하는 역할을 합니다. (자세한 내용은 7장 2절 충돌 참고)

    블루프린트 로직: 상호작용 시 실행될 행동을 정의합니다. (예: 문 열기 애니메이션 재생, 스위치 상태 변경)

  • 상호작용 방식
    • 트리거 기반: 플레이어가 오브젝트 근처의 특정 트리거 영역에 진입했을 때 상호작용 메시(예: E 키를 눌러 상호작용)를 표시하고, 플레이어가 키를 누르면 상호작용이 발생합니다.
    • 시선 기반 (Line Trace): 플레이어의 카메라 시선이 오브젝트에 닿았을 때 상호작용 가능 여부를 판단하고, 키를 누르면 상호작용합니다. (자세한 내용은 8장 2절에서 다룸)
    • 충돌 기반 (Hit Events): 오브젝트에 직접 부딪혔을 때 상호작용이 발생하는 경우. (예: 발로 차서 문 열기)

블루프린트 (Blueprints)

환경 상호작용 로직의 대부분은 블루프린트를 통해 구현됩니다.

  • 액터 블루프린트: 문, 스위치, 아이템 등 각 상호작용 가능한 오브젝트를 개별적인 액터 블루프린트(BP_Door, BP_Switch, BP_Item)로 만듭니다.
  • 이벤트 그래프: OnComponentBeginOverlap, OnComponentEndOverlap, 그리고 플레이어 입력 이벤트(예: Input Action Interact)를 사용하여 상호작용 로직을 구현합니다.
  • 컴포넌트 조작: Static Mesh 컴포넌트의 가시성/위치/회전 변경, Timeline을 이용한 애니메이션, Play Sound at Location 등의 노드를 사용하여 상호작용 결과를 시각적/청각적으로 표현합니다.

상호작용 가능한 오브젝트 구현 예시 (문 열기)

상호작용 오브젝트는 배치만으로 동작하지 않고 트리거, 상태, 피드백이 함께 준비되어야 합니다.

가장 기본적인 환경 상호작용인 문 오브젝트를 만들어 봅시다.

새로운 액터 블루프린트 생성
  • 콘텐츠 브라우저에서 마우스 오른쪽 버튼 클릭 블루프린트 클래스(Blueprint Class) 선택.
  • 부모 클래스는 Actor로, 이름은 BP_Door로 지정합니다.

컴포넌트 추가: BP_Door 블루프린트를 열고 컴포넌트(Components) 패널에서 다음을 추가합니다.

  • Static Mesh (DoorFrame): 문틀이 될 메시를 할당합니다. (예: SM_DoorFrame)
  • Scene Component (Hinge)와 자식 Static Mesh (Door): Hinge를 경첩 위치에 놓고 Door 메시를 자식으로 붙여 오프셋을 맞춥니다. 회전할 Hinge와 Door는 Movable로 두며 Simulate Physics는 끕니다.
  • Box Collision (InteractionVolume): 문 앞에 놓일 트리거 볼륨입니다. 문이 열리는 영역이 됩니다.
    • Details > Collision Presets의 Custom에서 Pawn만 Overlap, 나머지는 Ignore로 두고 Generate Overlap Events를 켭니다. 플레이어 캡슐 쪽 설정도 맞춥니다.
이벤트 그래프 로직 (문 열기/닫기)
  • 변수 추가
    • bIsOpen (Boolean, 초기 False): 완전히 열린 상태인지 저장합니다.
    • bIsAnimating (Boolean, 초기 False): 이동 중 재입력을 막습니다.
    • ClosedRotation / OpenRotation (Rotator): BeginPlay에서 Hinge의 상대 회전을 ClosedRotation으로 저장하고, 로컬 Z축 Yaw에 90도를 더해 OpenRotation을 한 번 정합니다.
  • 오버랩 이벤트
    • InteractionVolume 컴포넌트를 선택하고 OnComponentBeginOverlap (InteractionVolume) 이벤트를 추가합니다.
    • OnComponentEndOverlap (InteractionVolume) 이벤트를 추가합니다.
    • 두 이벤트의 Other Actor를 플레이어로 필터링하고 Other Comp가 그 플레이어의 캡슐인지도 확인합니다. 플레이어는 현재 후보 문 참조를 저장하고, 이탈 시 같은 참조만 비웁니다.
  • 상호작용 UI 표시/숨김 (선택 사항)
    • OnComponentBeginOverlap 시 플레이어 HUD에 E 키를 눌러 문 열기 같은 텍스트 위젯을 표시하는 로직을 추가합니다. (이때 위젯 블루프린트와 연결해야 합니다.)
    • OnComponentEndOverlap 시 해당 위젯을 제거합니다.
  • 문 열림/닫힘 로직 (Input Event)
    • 입력은 플레이어 Character/Controller가 받습니다. 키를 누를 때 한 번 발생하도록 매핑한 Interact가 들어오면 유효한 후보 문 하나의 ToggleDoor 커스텀 이벤트를 호출합니다. 일반 Actor에 입력 노드를 추가하는 것만으로 입력이 활성화되지는 않습니다.
    • 문의 ToggleDoor에서 요청 플레이어의 범위를 다시 확인하고, bIsAnimating이 True라면 요청을 무시합니다.
    • 요청이 유효하면 먼저 bIsAnimating=True로 둡니다. bIsOpen=False이면 Play, True이면 Reverse로 분기합니다. 상태와 별도의 FlipFlop을 중복 관리하지 않습니다.
    • 문 회전 (Timeline 사용)

      Timeline 노드를 추가하고 이름을 DoorAnimation으로 지정합니다.

      DoorAnimation 더블클릭하여 타임라인 에디터를 엽니다.

      Track에 Add Float Track을 추가하고 이름을 Alpha로 지정합니다.

      Alpha 트랙에 키를 추가합니다. (예: 시간 0.0, 값 0.0)

      두 번째 키를 추가합니다. (예: 시간 1.0, 값 1.0)

      키의 보간을 조절해 부드러운 커브를 만듭니다. Alpha의 범위는 0~1, Timeline 길이는 1초로 맞춥니다.

      Timeline의 Update에서 Set Relative Rotation을 실행하고, 순수 노드 Lerp (Rotator)의 출력을 연결합니다.

      • A 핀: 시작 시 저장한 ClosedRotation
      • B 핀: 시작 시 정한 OpenRotation
      • Alpha 핀: 타임라인의 Alpha 출력 핀 연결

      Lerp (Rotator)의 결과를 Set Relative Rotation (Hinge) 노드의 New Rotation 핀에 연결합니다.

      DoorAnimation 타임라인의 Play 핀을 문 여는 로직에, Reverse 핀을 문 닫는 로직에 연결합니다.

      Finished에서 Direction이 Forward이면 bIsOpen=True, Backward이면 False로 확정하고 bIsAnimating=False로 풉니다. Update 중의 현재 회전을 보간 시작값으로 다시 읽지 않습니다.

  • 사운드 추가: Play Sound at Location 노드를 사용하여 문이 열리거나 닫힐 때 적절한 사운드를 재생합니다.

초기 상태가 닫힘이고 진행 중 입력을 무시하는 이 예제의 전환은 다음과 같습니다.

재입력을 막는 문 열림·닫힘 상태

닫힘에서 시작하며 유효한 플레이어 입력만 받는다. 열리는 중과 닫히는 중에는 재입력을 무시한다.

문 상태의 네 가지 전환닫힘에서 유효한 입력은 Play로 여는 중으로 전환한다. 정방향 Finished에서 열림, 다음 유효 입력은 Reverse로 닫는 중, 역방향 Finished에서 닫힘으로 돌아간다. 진행 중에는 bIsAnimating으로 추가 입력을 무시한다. 이 구조는 예제에서 직접 구현할 상태 규칙이다.닫힘bIsOpen = false여는 중bIsAnimating = true열림bIsOpen = true닫는 중bIsAnimating = true입력 / Play열림 완료입력 / Reverse닫힘 완료
문 상태의 네 가지 전환닫힘에서 유효한 입력은 Play로 여는 중으로 전환한다. 정방향 Finished에서 열림, 다음 유효 입력은 Reverse로 닫는 중, 역방향 Finished에서 닫힘으로 돌아간다. 진행 중에는 bIsAnimating으로 추가 입력을 무시한다. 이 구조는 예제에서 직접 구현할 상태 규칙이다.닫힘bIsOpen = false여는 중입력 잠금열림bIsOpen = true닫는 중입력 잠금입력 / Play열림 완료입력 / Reverse닫힘완료

상호작용 구현의 최적화 및 고려 사항

  • 블루프린트 vs C++: 복잡하고 성능에 민감한 상호작용은 C++로 구현하는 것이 유리할 수 있지만, 대부분의 기본적인 상호작용은 블루프린트로 충분합니다.
  • 충돌 설정의 중요성: Trigger Volume과 상호작용 오브젝트의 충돌 설정이 정확해야 합니다. 불필요한 Block 설정은 피하고, 필요한 곳에만 Overlap을 사용합니다.
  • 컴포넌트 구조화: 상호작용 로직이 복잡해질수록 블루프린트 내의 컴포넌트들을 논리적으로 그룹화하고 이름을 명확하게 지정합니다.
  • 입력 매핑: Legacy Input은 Project Settings의 Action Mappings를 사용합니다. Enhanced Input은 Input Action·Input Mapping Context를 만들고 로컬 플레이어에 Context를 등록한 뒤 입력 이벤트를 연결합니다.
  • 피드백: 상호작용이 발생했을 때 플레이어에게 시각적(UI, 이펙트), 청각적(사운드), 또는 햅틱(진동) 피드백을 제공하여 몰입도를 높입니다.
  • 상호작용 우선순위: 여러 상호작용 가능한 오브젝트가 겹쳐 있을 때 어떤 오브젝트와 상호작용할지 결정하는 로직을 고려합니다. (예: 가장 가까운 오브젝트, 시선에 있는 오브젝트)

후보가 여러 개면 유효 조건을 먼저 확인한 뒤 시선·거리 같은 프로젝트 규칙으로 하나만 선택합니다. 선택이 바뀌면 이전 프롬프트와 하이라이트를 정리합니다.


환경 상호작용은 트리거, 상호작용 가능한 오브젝트, 블루프린트 로직을 연결해 플레이어 입력에 반응하는 레벨 요소를 만드는 작업입니다.

상호작용 범위, 피드백, 상태 변화를 분리해 관리해야 합니다.