본문 바로가기

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

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

앞 장들에서 조명과 날씨, 시간 같은 시각 요소와 물리, 충돌을 다듬어 레벨의 기반을 만들었습니다. 이제 그 위에 플레이어의 행동이 실제로 세계를 바꾸는 환경 상호작용(environmental interaction)을 올릴 차례입니다. 문을 열고, 스위치를 누르고, 아이템을 줍는 순간 세계가 바로 반응하면, 플레이어는 자신이 세계에 영향을 주고 있다고 느낍니다.

이 글에서는 상호작용을 만드는 재료인 트리거와 상호작용 오브젝트, 블루프린트를 먼저 정리하고, 가장 기본적인 예인 문을 처음부터 만들어 봅니다. 문 하나에도 범위 감지, 입력 전달, 상태 관리, 회전 애니메이션이 함께 필요하므로, 각 부분이 어떻게 이어지는지와 어디서 자주 끊기는지를 차례로 따라갑니다.


환경 상호작용이 하는 일

환경 상호작용은 게임 플레이의 핵심이자 레벨 디자인의 중요한 부분입니다. 플레이어가 주변에 영향을 주고 환경이 그 행동에 반응하면, 게임 세계가 더 현실적이고 몰입감 있게 느껴집니다. 스위치 조작, 문 열기, 퍼즐 풀기, 아이템 줍기 같은 상호작용은 게임 플레이에 깊이와 다양성을 더합니다.

상호작용은 이야기를 진행하거나 세계관을 알려 주는 수단이 되기도 합니다. 잠긴 문을 열거나 숨겨진 스위치를 찾는 것처럼, 플레이어에게 문제를 풀고 탐험할 동기를 주기도 합니다.


상호작용을 만드는 재료

트리거

트리거(trigger)는 플레이어나 다른 액터가 어떤 영역에 들어오거나 나갈 때 이벤트를 일으키는 투명한 볼륨으로, 상호작용의 시작을 감지하는 가장 기본적인 방법입니다. 모양에 따라 가장 흔히 쓰는 상자 모양의 Box Collision, 구 모양의 Sphere Collision, 캐릭터 충돌에 주로 쓰는 캡슐 모양의 Capsule Collision이 있습니다.

트리거는 레벨 에디터의 액터 배치(Place Actors) 패널에서 Trigger Box나 Trigger Sphere를 검색해 배치하거나, 기존 액터에 Box Collision 같은 컴포넌트를 더해 만듭니다. 그다음 디테일 패널의 Collision 항목에서 Collision Presets를 정합니다. OverlapOnlyPawn은 Pawn과 Camera, Vehicle에 Overlap으로 응답하므로, 플레이어만 골라내려면 따로 거르는 로직이 필요합니다. OverlapAll은 기본 채널에 Overlap으로 응답하지만, 상대의 채널 응답과 이벤트 생성 옵션도 맞아야 합니다. 특정 오브젝트 타입하고만 겹치게 하려면 Custom...에서 직접 정합니다. 그리고 Generate Overlap Events는 트리거와 상대 컴포넌트 양쪽에서 켜고, 충돌 검사(query)도 켜야 합니다.

블루프린트에서는 액터 블루프린트에 더한 충돌 컴포넌트를 선택하고 OnComponentBeginOverlap과 OnComponentEndOverlap 이벤트를 추가합니다. 레벨에 직접 놓은 트리거 액터라면 레벨 블루프린트의 액터 오버랩 이벤트로 연결할 수도 있습니다. 이벤트 그래프에서는 Other Actor 핀을 Cast To PlayerCharacter(또는 실제 플레이어 클래스)에 연결해, 플레이어가 들어왔을 때만 반응하게 거릅니다.

상호작용 오브젝트

문이나 스위치, 아이템처럼 플레이어가 직접 조작하는 오브젝트는 보통 세 부분으로 이루어집니다. 스태틱 메시 컴포넌트가 문의 몸체나 스위치의 버튼 같은 겉모습을 만들고, 충돌 컴포넌트가 플레이어가 상호작용 범위에 들어왔는지 감지하거나 물리적으로 부딪히는 일을 맡으며, 블루프린트 로직이 상호작용할 때 무엇을 할지 정합니다. 충돌은 물리 기반 조정 (중력, 충돌)에서 자세히 다뤘습니다.

상호작용을 시작하는 방식은 세 가지가 흔합니다. 트리거 방식은 플레이어가 오브젝트 근처의 트리거에 들어오면 "E 키를 눌러 상호작용" 같은 안내를 띄우고, 키를 누르면 상호작용합니다. 시선 방식은 플레이어 카메라에서 쏜 선(line trace)이 오브젝트에 닿으면 상호작용할 수 있는 대상으로 판단하고, 키를 누르면 상호작용하며, 사용자 인터페이스와 환경 연동에서 다룹니다. 충돌 방식은 발로 차서 문을 여는 것처럼 오브젝트에 직접 부딪힐 때 상호작용합니다.

블루프린트

환경 상호작용의 로직은 대부분 블루프린트로 만듭니다. 문, 스위치, 아이템마다 BP_Door, BP_Switch, BP_Item 같은 액터 블루프린트를 따로 만들고, 이벤트 그래프에서 OnComponentBeginOverlap, OnComponentEndOverlap, 그리고 상호작용 입력 이벤트로 로직을 엮습니다. 결과를 보여 줄 때는 스태틱 메시 컴포넌트의 보이기, 위치, 회전을 바꾸거나, 타임라인(Timeline)으로 움직임을 만들거나, Play Sound at Location으로 소리를 냅니다.


문 만들기: 준비

상호작용 오브젝트는 배치만 한다고 동작하지 않습니다. 범위를 감지하는 트리거와 상태를 기억하는 변수, 플레이어에게 보여 줄 반응이 함께 준비되어야 합니다. 가장 기본적인 상호작용인 문을 만들며 이것을 확인해 봅니다.

먼저 물리 기반 캐릭터 제어의 캐릭터 준비 안내를 확인합니다. 이미 조종할 수 있는 캐릭터가 있다면 그대로 쓰고, Blank로 시작해 아직 없다면 이동과 카메라, 입력을 준비한 뒤 돌아옵니다. 여기서도 PlayerCharacter는 실제 플레이어 캐릭터 블루프린트를 가리키는 예시 이름입니다.

상호작용 입력인 Interact는 이름만 적으면 생기는 이벤트가 아닙니다. 프로젝트 설정과 기본 옵션에서 본 입력 방식에 맞춰 키를 연결하고, 캐릭터나 컨트롤러 가운데 한 곳에서만 이벤트를 받게 합니다. 한 번 누를 때 한 번만 요청하도록 준비하고, 같은 키를 두 곳에서 받아 문을 두 번 부르지 않게 합니다.

컴포넌트 구성

콘텐츠 브라우저를 오른쪽 클릭해 Blueprint Class를 고르고, 부모 클래스를 Actor로 정해 BP_Door를 만듭니다. BP_Door를 열고 Components 패널에서 다음을 추가합니다.

컴포넌트역할
Static Mesh (DoorFrame)문틀입니다. 예를 들어 SM_DoorFrame을 지정합니다.
Scene Component (Hinge)문이 도는 축입니다. 경첩 위치에 놓습니다.
Static Mesh (Door)문짝입니다. Hinge의 자식으로 붙이고, 경첩에서 떨어진 만큼 위치를 맞춥니다.
Box Collision (InteractionVolume)문 앞에 놓는 트리거로, 플레이어가 문을 열 수 있는 범위입니다.

문은 경첩을 축으로 돌아야 하므로, 문짝을 직접 돌리지 않고 문짝을 자식으로 가진 Hinge를 돌립니다. 회전할 Hinge와 Door는 Movable로 두고, Simulate Physics는 끕니다. InteractionVolume은 디테일 패널의 Collision Presets에서 Custom을 골라 Pawn에만 Overlap, 나머지에는 Ignore로 응답하게 하고 Generate Overlap Events를 켭니다. 플레이어 캡슐 쪽의 설정도 맞춥니다.

변수 준비

문이 지금 어떤 상태인지 기억할 변수를 BP_Door에 만듭니다. bIsOpen(Boolean, 처음 False)은 문이 완전히 열린 상태인지를, bIsAnimating(Boolean, 처음 False)은 문이 움직이는 중인지를 저장해, 움직이는 동안 다시 들어온 입력을 막는 데 씁니다. ClosedRotation과 OpenRotation(Rotator)은 닫힘과 열림의 회전입니다. BeginPlay에서 Hinge의 지금 상대 회전을 ClosedRotation으로 저장하고, 그 로컬 Z축 Yaw에 90도를 더해 OpenRotation을 한 번 정해 둡니다.

플레이어 쪽에도 변수 하나가 필요합니다. 플레이어 캐릭터 블루프린트에 CandidateDoor 변수를 만들고, 타입을 BP_Door의 Object Reference로 정하며 처음 값은 None으로 둡니다. 이 변수는 지금 열 수 있는 범위에 있는, 레벨에 놓인 문 하나를 가리킵니다. 문의 종류가 아니라 레벨의 특정 문을 가리켜야 하므로 Class Reference로 정하지 않습니다.


문 만들기: 범위와 입력 연결

범위에 들어오고 나갈 때

InteractionVolume 컴포넌트를 선택하고 OnComponentBeginOverlap과 OnComponentEndOverlap 이벤트를 추가합니다. 두 이벤트 모두에서 Other Actor를 실제 PlayerCharacter 클래스로 캐스트하고, Other Comp가 그 캐릭터의 Capsule Component인지 확인합니다. 캐릭터의 다른 컴포넌트가 겹쳐 이벤트가 여러 번 생기는 것을 막기 위해서입니다.

BeginOverlap에서는 캐스트로 얻은 As PlayerCharacter의 Set CandidateDoor에 문 자신인 Self를 연결합니다. 이제 플레이어는 이 문을 열 수 있는 후보로 기억합니다.

EndOverlap에서는 같은 필터를 통과한 뒤, 그 캐릭터의 CandidateDoor와 문의 Self가 같은 객체인지 ==로 비교합니다. 이 문이 지금의 후보일 때만 CandidateDoor를 None으로 비웁니다. 플레이어가 이미 다른 문으로 후보를 바꿨는데, 앞의 문에서 나갈 때 새 후보까지 지워 버리는 것을 막기 위해서입니다.

원한다면 BeginOverlap에서 플레이어 HUD에 "E 키를 눌러 문 열기" 같은 안내 위젯을 띄우고, EndOverlap에서 지울 수 있습니다. 이때는 위젯 블루프린트와 연결해야 하며, 안내를 다루는 방법은 다음 글에서 자세히 봅니다.

입력을 문까지 전달하기

BP_Door에 ToggleDoor 커스텀 이벤트를 만들고, 입력으로 RequestingPlayer를 Character의 Object Reference로 추가합니다. 이 값은 문을 열어 달라고 요청한 캐릭터입니다.

캐릭터에서 Interact를 받는다면, CandidateDoor가 유효한지 Is Valid로 확인한 뒤 그 문을 Target으로 ToggleDoor를 호출하고, RequestingPlayer에는 캐릭터 자신인 Self를 넘깁니다. 컨트롤러에서 입력을 받는다면, 호출할 때마다 Get Controlled Pawn을 실제 PlayerCharacter 클래스로 캐스트하고, 성공하면 그 캐릭터의 CandidateDoor도 Is Valid로 확인한 뒤 같은 방식으로 호출하며, RequestingPlayer에도 그 캐릭터를 넘깁니다. 이렇게 입력을 받는 곳에서 문을 부르는 이유는, 일반 문 액터에 입력 노드를 더하는 것만으로는 그 액터가 입력을 받지 못하기 때문입니다.

요청을 받은 문이 확인할 것

ToggleDoor의 시작에서는 먼저 RequestingPlayer가 유효한지 Is Valid로 확인합니다. 그다음 그 캐릭터의 Capsule Component를 InteractionVolume의 Is Overlapping Component에 넣어, 지금 범위 안에 있는지 다시 확인합니다. 이 검사는 요청이 올 때마다 새로 합니다. 범위 밖이거나 bIsAnimating이 True라면 요청을 무시합니다.

요청이 유효하면 먼저 bIsAnimating을 True로 바꿔 입력을 잠급니다. 그리고 bIsOpen이 False이면 타임라인을 Play로, True이면 Reverse로 재생하도록 나눕니다. 여기서 상태를 bIsOpen 하나로 관리하므로, FlipFlop 노드를 함께 써서 상태를 두 곳에서 따로 관리하지 않습니다. 두 곳이 어긋나면 문이 반대로 움직이기 때문입니다.


문 만들기: 회전 애니메이션

타임라인 만들기

Timeline 노드를 추가하고 이름을 DoorAnimation으로 정한 뒤, 더블클릭해 타임라인 에디터를 엽니다. Add Float Track으로 트랙을 하나 추가해 이름을 Alpha로 정하고, 시간 0.0에 값 0.0인 키와 시간 1.0에 값 1.0인 키를 넣습니다. 키의 보간을 조절해 부드러운 곡선을 만들고, Alpha의 범위는 0부터 1, 타임라인의 길이는 1초로 맞춥니다.

회전 적용하기

타임라인의 Update에서 Set Relative Rotation (Hinge)를 실행하고, 그 New Rotation에 순수 노드인 Lerp (Rotator)의 출력을 연결합니다. Lerp의 A에는 시작 때 저장한 ClosedRotation을, B에는 OpenRotation을, Alpha에는 타임라인의 Alpha 출력을 연결합니다. 그리고 DoorAnimation의 Play 핀을 문을 여는 분기에, Reverse 핀을 문을 닫는 분기에 연결합니다.

타임라인의 Finished에서는 Direction 출력을 보고 상태를 확정합니다. Forward로 끝났다면 bIsOpen을 True로, Backward로 끝났다면 False로 정하고, bIsAnimating을 False로 바꿔 입력 잠금을 풉니다. 문이 열리고 닫힐 때는 Play Sound at Location으로 알맞은 소리를 냅니다.

Alpha는 각도가 아니라 비율

닫힘의 상대 Yaw를 0도, 열림을 90도로 정했다면, Alpha가 0.5일 때 보간한 회전은 45도입니다. 즉 Alpha는 열린 각도가 아니라 두 끝 회전 사이의 비율입니다. 그래서 Update마다 Hinge의 지금 회전을 다시 읽어 A에 넣으면 안 됩니다. 그러면 시작점이 매번 바뀌어, 같은 곡선을 재생해도 처음 정한 0도에서 90도로의 움직임과 다른 결과가 나옵니다.

상태가 바뀌는 흐름

이 예는 문이 닫힌 상태에서 시작하고, 움직이는 동안 들어온 입력은 무시한다는 규칙으로 동작합니다. 그 흐름을 그림으로 보면 다음과 같습니다.

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

닫힘→여는 중→열림→닫는 중→닫힘과 bIsAnimating 입력 잠금/Finished 확정의 실제 상태 기계이다.

DOOR · STATE TRANSITIONS

문이 움직이는 동안은 재입력을 무시합니다

닫힘에서 시작하고 유효한 입력에 Play·Reverse로 반응합니다. Timeline이 끝나면 bIsOpen을 확정하고 입력 잠금을 풉니다.

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

입력 잠금과 완료 상태

여는 중·닫는 중은 bIsAnimating = true입니다. Finished에서 Direction에 따라 bIsOpen을 정하고 bIsAnimating = false로 바꿉니다.

이 예의 조건

  • 본문과 원 도표에 제시된 사례의 입력·조건을 사용합니다. 설명용 수치나 독립 비교 경로는 각 단계에 표시합니다.
  • 현재 상태·값과 전환 근거의 위치는 모든 단계에서 같습니다. 조건이 맞지 않거나 실행되지 않은 경로를 성공한 동작으로 해석하지 않습니다.
예의 값과 변화
관찰·상황값·보충 정보변화·이유
닫힘·요청

닫힌 문에 열기 입력이 들어온다.

  • 상태: 닫힘
  • bIsAnimating: false→true
  • 애니메이션 중에는 같은 전환이 겹치지 않게 재입력을 막는다.
여는 중·완료

Timeline 완료에서 열린 상태를 확정한다.

  • 상태: 여는 중→열림
  • bIsAnimating: Finished 뒤 false
  • 입력 시점이 아니라 완료 사건에서 최종 상태를 확정한다.
닫기 전환

다음 유효 입력이 역방향 전환을 시작한다.

  • 상태: 닫는 중→닫힘
  • 입력 잠금: 진행 중 true
  • 닫기 완료도 Finished에서 확정하고 잠금을 해제한다.

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

닫힘→여는 중→열림→닫는 중→닫힘과 bIsAnimating 입력 잠금/Finished 확정의 실제 상태 기계이다.

DOOR · STATE TRANSITIONS

문이 움직이는 동안은 재입력을 무시합니다

닫힘에서 시작하고 유효한 입력에 Play·Reverse로 반응합니다. Timeline이 끝나면 bIsOpen을 확정하고 입력 잠금을 풉니다.

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

입력 잠금과 완료 상태

여는 중·닫는 중은 bIsAnimating = true입니다. Finished에서 Direction에 따라 bIsOpen을 정하고 bIsAnimating = false로 바꿉니다.

이 예의 조건

  • 본문과 원 도표에 제시된 사례의 입력·조건을 사용합니다. 설명용 수치나 독립 비교 경로는 각 단계에 표시합니다.
  • 현재 상태·값과 전환 근거의 위치는 모든 단계에서 같습니다. 조건이 맞지 않거나 실행되지 않은 경로를 성공한 동작으로 해석하지 않습니다.
예의 값과 변화
관찰·상황값·보충 정보변화·이유
닫힘·요청

닫힌 문에 열기 입력이 들어온다.

  • 상태: 닫힘
  • bIsAnimating: false→true
  • 애니메이션 중에는 같은 전환이 겹치지 않게 재입력을 막는다.
여는 중·완료

Timeline 완료에서 열린 상태를 확정한다.

  • 상태: 여는 중→열림
  • bIsAnimating: Finished 뒤 false
  • 입력 시점이 아니라 완료 사건에서 최종 상태를 확정한다.
닫기 전환

다음 유효 입력이 역방향 전환을 시작한다.

  • 상태: 닫는 중→닫힘
  • 입력 잠금: 진행 중 true
  • 닫기 완료도 Finished에서 확정하고 잠금을 해제한다.

위 그림은 문의 네 가지 상태와 그 사이의 전환을 보여 줍니다. 처음은 bIsOpen이 false인 닫힘 상태입니다. 여기서 유효한 입력이 들어오면 Play로 여는 중 상태가 되고, 이때 bIsAnimating은 true입니다. 정방향으로 Finished가 오면 bIsOpen이 true인 열림 상태가 확정되고 입력 잠금이 풀립니다. 다음 유효한 입력이 들어오면 Reverse로 닫는 중 상태가 되고, 역방향으로 Finished가 오면 다시 닫힘이 확정되고 잠금이 풀립니다.

단계 그림은 이 흐름을 세 장면으로 나눠, 닫힌 문에 열기 입력이 들어오는 순간, 타임라인이 끝나 열린 상태가 확정되는 순간, 다음 입력이 닫기를 시작하는 순간을 차례로 보여 줍니다. 그림 아래의 카드가 정리하듯이, 여는 중과 닫는 중에는 bIsAnimating이 true라 다시 들어온 입력을 무시하고, Finished에서 Direction에 따라 bIsOpen을 정한 뒤 bIsAnimating을 false로 바꿉니다. 이것은 엔진이 제공하는 기능이 아니라, 이 예에서 직접 만드는 상태 규칙입니다.


문이 반응하지 않을 때

배치한 문 하나로 닫힘, 열기, 완료, 닫기, 완료의 흐름을 먼저 확인합니다. 여는 중에 다시 누른 입력과 범위 밖에서의 요청은 각각 무시되어야 합니다.

문에 가까이 갔는데 CandidateDoor가 계속 None이라면, 양쪽의 Overlap 설정, 플레이어 클래스로의 캐스트, Other Comp가 캡슐인지 거르는 조건을 먼저 확인합니다. 참조는 있는데 문이 반응하지 않는다면, 입력이 한 곳에서만 전달되는지, ToggleDoor의 Target이 문이고 RequestingPlayer가 캐릭터인지, 요청 시점의 범위 검사와 bIsAnimating의 상태를 차례로 확인합니다.

안내 UI를 함께 만들었다면, EndOverlap에서 지금의 후보가 이 문인지 확인한 분기 안에서만 후보와 그 안내를 함께 지웁니다. 다른 문으로 선택이 바뀐 뒤 앞의 문에서 나가는 이벤트가 새 안내까지 지우지 않게 하기 위해서입니다.


상호작용을 만들 때 고려할 것

대부분의 기본 상호작용은 블루프린트로 충분하며, 복잡하고 성능에 민감한 상호작용은 C++로 만드는 편이 유리할 수 있습니다. 트리거와 상호작용 오브젝트의 충돌 설정은 정확해야 하며, 필요 없는 Block은 피하고 필요한 곳에만 Overlap을 씁니다. 로직이 복잡해질수록 블루프린트 안의 컴포넌트를 논리적으로 묶고 이름을 분명하게 짓습니다.

입력은 프로젝트의 방식에 맞춰 연결합니다. 기존 입력 방식은 Project Settings의 Action Mappings를 쓰고, 향상된 입력은 입력 액션과 입력 매핑 컨텍스트를 만들어 로컬 플레이어에 컨텍스트를 등록한 뒤 입력 이벤트를 연결합니다. 상호작용이 일어나면 UI나 이펙트 같은 시각 피드백, 소리, 진동 같은 반응을 주어 플레이어가 결과를 바로 알게 합니다.

상호작용할 수 있는 오브젝트가 여러 개 겹쳐 있다면 어느 것과 상호작용할지 정하는 규칙이 필요합니다. 먼저 유효한 조건을 확인한 뒤 가장 가까운 것이나 시선에 있는 것처럼 프로젝트의 규칙으로 하나만 고르고, 선택이 바뀌면 앞의 안내와 강조 표시를 정리합니다.

마지막으로 이 문은 로컬 플레이어 한 명을 위한 예입니다. 멀티플레이어 게임에서 필요한 서버의 권한 확인과 요청 전달, 문 상태의 복제는 만들지 않았습니다.


정리

  • 트리거는 영역에 들어오고 나가는 것을 감지하는 투명한 볼륨이며, 양쪽의 Generate Overlap Events와 충돌 검사, 채널 응답을 함께 맞춰야 이벤트가 생깁니다.
  • 겹친 상대는 Other Actor를 플레이어 클래스로 캐스트하고 Other Comp가 캡슐인지까지 확인해 거릅니다.
  • 문은 Hinge를 축으로 돌리고, 플레이어의 CandidateDoor(Object Reference)에 범위 안의 문을 기억하며, 나갈 때는 지금의 후보가 이 문일 때만 비웁니다.
  • 입력은 캐릭터나 컨트롤러 한 곳에서 받아 ToggleDoor를 호출하고, 문은 요청마다 범위와 bIsAnimating을 다시 확인합니다.
  • 상태는 bIsOpen 하나로 관리하고, 타임라인의 Play와 Reverse, Finished의 Direction으로 열림과 닫힘을 확정하며, FlipFlop으로 상태를 따로 두지 않습니다.
  • Lerp (Rotator)의 Alpha는 각도가 아니라 두 끝 회전 사이의 비율이며, A와 B는 시작 때 저장한 회전을 씁니다.

연습 문제

1. 여는 중에 다시 누르면

문이 열리는 도중에 플레이어가 상호작용 키를 한 번 더 눌렀습니다. 이 예에서 문은 방향을 바꿔 닫힐까요? 문이 닫히려면 언제 다시 눌러야 할까요?

해설 보기

방향을 바꾸지 않고 계속 열립니다. 여는 중에는 bIsAnimating이 True라서 ToggleDoor가 요청을 무시하기 때문입니다.

정방향 Finished에서 bIsOpen이 True로, bIsAnimating이 False로 확정된 뒤에 유효한 입력이 들어와야 Reverse로 닫힙니다. 움직이는 도중에 바로 방향을 바꾸게 하려면 다시 누른 입력을 어떻게 처리할지 규칙과 상태 처리를 따로 바꿔야 하며, 지금 규칙에 FlipFlop을 더하는 것만으로는 해결되지 않습니다.

2. Alpha가 0.25일 때

닫힘의 상대 Yaw가 0도, 열림이 90도입니다. 타임라인의 Alpha가 0.25일 때 Hinge의 Yaw는 몇 도일까요? Update마다 지금의 Hinge 회전을 A에 넣으면 어떤 문제가 생길까요?

해설 보기

Lerp는 0 + (90 - 0) × 0.25로 계산하므로 22.5도입니다.

Update마다 지금의 회전을 A에 넣으면, 다음 프레임의 시작점이 이미 조금 열린 각도가 되어 매번 바뀝니다. 그러면 같은 곡선을 재생해도 처음 정한 0도에서 90도로의 움직임과 달라지고, 속도도 의도와 다르게 됩니다. 그래서 A와 B에는 시작 때 저장한 ClosedRotation과 OpenRotation을 씁니다.

3. 다른 문의 안내가 사라진다

두 문 A와 B가 가까이 있습니다. 플레이어가 A의 범위에 들어갔다가 B의 범위로 옮겨 가자 CandidateDoor가 B로 바뀌었는데, 그다음 A의 범위를 완전히 벗어나는 순간 B의 안내까지 사라지고 CandidateDoor도 None이 되었습니다. 무엇을 고쳐야 할까요?

해설 보기

A의 EndOverlap이 지금의 후보가 무엇인지 확인하지 않고 CandidateDoor와 안내를 무조건 비웠기 때문입니다.

EndOverlap에서는 그 캐릭터의 CandidateDoor가 이 문 자신(Self)과 같은지 ==로 비교하고, 같을 때만 후보와 안내를 함께 비웁니다. 그러면 A에서 나가도 지금의 후보인 B는 그대로 남습니다.

타임라인 노드의 사용법은 Epic의 타임라인 안내에서 확인할 수 있습니다.

다음 글 사용자 인터페이스와 환경 연동에서는 상호작용할 수 있는 대상을 화면의 안내 UI로 알려 주고, 후보가 바뀔 때 안내를 정확히 정리하는 방법을 다룹니다.