레고® 무서운 우주(LEGO® Scary Space) 프로젝트 템플릿에 어서 오세요! 점프 스케어로 가득한 으스스한 우주선을 체험하고, 장치와 Verse 코드를 사용해 이 독특한 프로젝트 템플릿을 기반으로 코즈믹 호러 테마 게임을 직접 만들어 보세요.
무서운 우주 플레이하기
무서운 우주 템플릿을 플레이할 때, 여러분은 우주선의 선원으로 플레이하게 됩니다. 이 섹션은 게임의 기본적인 길잡이 역할을 해, 각 시퀀스에서 시연하는 디자인 의도와 메카닉을 설명합니다.
템플릿에서 프로젝트를 만들려면 프로젝트 브라우저에서 브랜드 템플릿(Brand Templates) 을 찾아 레고®(LEGO®) 아래에서 ScarySpace 를 선택하세요.

UEFN에서 프로젝트 템플릿을 열면 세션 시작(Launch Session) 을 클릭해 포트나이트 클라이언트를 여세요.

에디터 개인설정에 따라, 프로젝트는 클라이언트를 플레이 모드로 시작하거나 섬을 제작 모드로 시작합니다. 제작 모드라면 게임 메뉴(Game Menu) 를 열고 노란색 게임 시작(Start Game) 버튼을 클릭해 게임을 시작하세요.

제어실
친근한 로봇이 우주선의 제어실에 말을 걸어와, 우주선을 타고 우주를 왜 떠돌고 있는지에 대한 배경을 설명합니다. 로봇은 우주선에 운석이 충돌했고, 충돌 현장으로 이동해 피해도를 판단할 것을 권합니다.

이 인트로 시퀀스에는 시네마틱과 NPC가 포함되며, 플레이어에게 게임 속 세계를 소개합니다.씬은 시퀀서를 사용해 제작되었습니다.IntroSequence 에셋은 프로젝트의 Sequences 폴더에 있습니다.Verse 장치(intro_manager_device.verse)도 하나 있어컷씬 중 플레이어 이동을 제어할 수도 있습니다.
using { /Fortnite.com/Devices }
using { /Fortnite.com/Characters }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/Diagnostics }
# 이 클래스의 목적은 인트로 컷씬 중에는 플레이어 이동을 잠그고, 컷씬이 끝나면 잠금 해제하는 것입니다.
intro_manager_device := class(creative_device):
# 시퀀스에서 게임플레이 이벤트를 전달하는 장치입니다.
@editable
TriggerDevice : trigger_device = trigger_device{}
OnBegin<override>()<suspends>:void=
Sleep(0.0)
# 여기서 플레이어는 정지 상태가 되며(이동 잠금), 게임플레이 이벤트가 트리거 장치를 활성화하면 정지 상태에서 풀려납니다.
if(Character := GetPlayspace().GetPlayers()[0].GetFortCharacter[]):
Character.PutInStasis(stasis_args{AllowFalling := true})
TriggerDevice.TriggeredEvent.Await()
Character.ReleaseFromStasis()
복도 지나기
이후 복도 몇 곳을 지나 격납고로 이동해 충돌 현장을 찾게 됩니다. 복도에는 깜짝 놀랄 일이 기다립니다!

첫 두 개의 복도에서 카메라 설정을 조작해 점프 스케어를 구성하는 법을 알아볼 수 있습니다.
-
시퀀스 A(Sequence A): 첫 부분에서 카메라는 플레이어에게 가깝게 설정되어 더욱 밀접하고 강렬한 플레이 경험을 조성합니다. 이 시퀀스는 돌연변이 유발 구역과 선회 카메라 장치를 사용해 플레이어의 시점을 바꿉니다.
-
시퀀스 B(Sequence B): 첫 번째 복도 끝에서는 창문을 들여다보고 있는 외계인 때문에 깜짝 놀라게 될 것입니다! 이 점프 스케어는 잠금, 트리거, 오디오 플레이어 장치를 사용하고, hallway_jump_scare_device Verse 장치로 제어됩니다.
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/Diagnostics }
using { /UnrealEngine.com/Temporary/SpatialMath }
using { Utility }
hallway_jump_scare_device := class(creative_device):
# 편집 가능 어트리뷰트는 에디터에서 할당 가능한 레퍼런스를 생성합니다.
@editable
PlayerTrigger : trigger_device = trigger_device{}
@editable
LockDevice : lock_device = lock_device{}
@editable
ScaryProps : []creative_prop = array{}
@editable
StingerAudioPlayer : audio_player_device = audio_player_device{}
@editable
HallwayLight : customizable_light_device = customizable_light_device{}
OnBegin<override>()<suspends>:void=
ScaryProps.SetVisibility(false)
# 첫 단계는 플레이어가 트리거와 충돌하기를 기다리고, 에이전트를 저장해 잠금 장치에 사용하도록 하는 것입니다.
MaybeAgent := PlayerTrigger.TriggeredEvent.Await()
if (Agent := MaybeAgent?):
# First part: Initialize the jump scare by opening the door and start the playback of the audio stinger.
LockDevice.Open(Agent)
StingerAudioPlayer.Play()
# 여기서 대기하는 것은 타이밍 때문입니다.
Sleep(0.5)
# 두 번째 부분 사물을 보여주고 문을 닫기 시작합니다.
ScaryProps.SetVisibility(true)
LockDevice.Close(Agent)
# 다시 한번 타이밍을 맞추기 위해 기다립니다.
Sleep(1.8)
# 세 번째 부분 여기서는 사물을 숨깁니다. 플레이어가 문에 도달했을 때 복도가 '평범'해 보이고 무서운 괴물이 있을거라 생각지 못 하기 때문입니다.
ScaryProps.SetVisibility(false)
Sleep(0.5)
HallwayLight.TurnOn()
격납고 안으로
마지막으로, 두 번째 복도의 끝에서 격납고에 도달하게 됩니다. 미닫이문을 지나 들어가세요. 격납고에 들어가면 라이트가 하나씩 켜집니다. 조심하세요. 외계인들이 지켜보고 있으니까요! 외계인의 시선은 플레이어를 따라와 긴장을 높입니다.

격납고 미로의 끝에 가까워지면 손이 튀어나와 잡으려 듭니다!

-
시퀀스 C(Sequence C): 천천히 켜지는 라이트는 느린 속도로 인해 긴장을 높이지만, 어둠이 빛으로 밝혀지며 안정감이 생기기도 합니다. 이 시퀀스는 트리거 장치를 사용해 일련의 지연을 두고 라이트를 사용하는 이벤트를 만듭니다.
-
격납고의 레이아웃은 미로처럼 되어 있어, 플레이어는 이 템플릿에 사용된 여러 우주 에셋을 둘러보고 탐색해야 합니다. 이 에셋은 콘텐츠 브라우저에서 이용할 수 있으며, 포크리 인벤토리에서 프리팹과 갤러리로도 이용할 수 있습니다.
-
시퀀스 D(Sequence D): 이 시퀀스는 플레이어를 따라오는 외계인의 시선을 제어합니다.트리거 장치를 사용해 시퀀스를 시작하지만, 다른 모든 행동은
prop_look_at_device
Verse 장치에 의해 제어됩니다.
using { /Fortnite.com/Devices }
using { /Fortnite.com/Characters }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/Diagnostics }
using { /UnrealEngine.com/Temporary/SpatialMath }
using { Utility }
prop_look_at_device := class(creative_device):
# 편집 가능 어트리뷰트는 에디터에서 할당 가능한 레퍼런스를 생성합니다
# 회전시키는 눈 꽃 사물입니다
@editable
Prop : creative_prop = creative_prop{}
@editable
PlayerTrigger : trigger_device = trigger_device{}
@editable
CreakAudioPlayer : audio_player_device = audio_player_device{}
DetectionThreshold : float = 800.0
RotationInterval : float = 0.5
OnBegin<override>()<suspends> : void =
# 플레이어가 방에 들어올 때까지 대기하고 PlayerTrigger를 트리거합니다
PlayerTrigger.TriggeredEvent.Await()
# 플레이어 트리거는 지연을 두고 켜지는 라이트도 작동시킵니다. 에디터의 '저장고 라이트 시퀀스 게시판'에서 자세한 정보를 확인하세요.
# 그러므로 라이트가 켜지고 3초 동안 기다리면 식물이 회전합니다. 이는 극적인 효과를 주기 위해서입니다.
Sleep(3.0)
# 여기서 업데이트 동시 실행 루틴을 시작해 플레이어 위치를 확인하고 사물을 플레이어 방향으로 회전시킵니다.
UpdateProp()
UpdateProp()<suspends>:void=
# 가장 먼저 눈 꽃 사물이 극적으로 180도 회전하고 오디오 신호를 재생하며,
PropTransform := Prop.GetTransform()
PIRotation := PropTransform.Rotation.ApplyLocalRotationZ(PiFloat)
CreakAudioPlayer.Play()
Prop.MoveTo(PropTransform.Translation, PIRotation, 4.0)
# 아래 루프의 코드가 플레이어를 찾고 사물을 플레이어 방향으로 회전시킵니다.
loop:
# 플레이어에 대해 트랜스폼을 구하고 플레이어와 사물 간의 거리가 'DetectionThreshold' 미만인지 확인합니다.
if(PlayerTransform := GetPlayspace().GetPlayers()[0].GetFortCharacter[].GetTransform(),
Distance(PlayerTransform.Translation, PropTransform.Translation) <= DetectionThreshold):
# 사물에서 플레이어를 가리키는 벡터를 만듭니다.
ToVector := PlayerTransform.Translation - PropTransform.Translation
# 커스텀 LookInDirection 함수를 사용해 ToVector와 정렬되는 위 또는 Z축 주위로 회전을 생성합니다.
ToRotation := LookInDirection(ToVector)
# 플레이어 위치가 변경될 때만 사물을 움직이고 오디오를 재생합니다.
if (Distance(Prop.GetTransform().Rotation,ToRotation) <= 0.01):
CreakAudioPlayer.Stop()
Sleep(RotationInterval)
else:
# 삐걱거리는 오디오 재생
CreakAudioPlayer.Play()
# MoveTo 함수로 보간 애니메이션을 만듭니다.
Prop.MoveTo(PropTransform.Translation, ToRotation, RotationInterval)
# 플레이어가 너무 멀리 있거나 게임을 종료하는 경우 코드는 RotationInterval이 끝나기를 기다립니다.
else:
Sleep(RotationInterval)
- 시퀀스 E(Sequence E): 구역 끝에는 점프 스케어가 있습니다. 이 씬은 시퀀서를 사용해 제작되었습니다. SkeletonArmTrapSequence 에셋은 프로젝트의 Sequences 폴더에 있습니다.
교차 구역과 상자 외계인의 추격
격납고에서 나와 십자 형태의 교차점에 들어서면 짧은 시네마틱 끝에 상자 외계인이 등장합니다. 빨리 뛰세요! 외계인은 운석 충돌 현장으로 길을 찾아 나설 때 쫓아옵니다.

-
시퀀스 F(Sequence F): 이 씬은 시네마틱, Verse 장치, 씬에 액션을 만들기 위한 시퀀스를 사용합니다.
-
상자 외계인은 짧은 시네마틱 끝에 등장합니다. 분위기를 조성한 뒤에 등장하는 방식은 긴장을 높이는 또 하나의 방법입니다. 시네마틱과 상자 외계인 이동은 시퀀서에 내장된 BoxChaseSequence로 만들어집니다. BoxChaseSequence 에셋은 프로젝트의 Sequences 폴더에 있습니다.
-
컷씬이 끝나면 플레이어는 상자 외계인의 추적을 피해 즉시 움직여야 합니다. 플레이어가 상자 외계인에게 붙잡히면 쓰러지게 되며, 추격 씬을 처음부터 다시 시작해야 합니다.
-
컷씬이 끝나면 이 씬은 box_chase_device Verse 장치에 의해 제어됩니다.
-
using { /Fortnite.com/Devices }
using { /Fortnite.com/Characters }
using { /Fortnite.com/Game }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/Diagnostics }
box_chase_device := class(creative_device):
# 편집 가능 어트리뷰트는 에디터에서 할당 가능한 레퍼런스를 생성합니다.
@editable
SequenceDevice : cinematic_sequence_device = cinematic_sequence_device{}
@editable
PlayerTrigger : trigger_device = trigger_device{}
@editable
EndCinematicTrigger : trigger_device = trigger_device{}
@editable
MonsterProp : creative_prop = creative_prop{}
@editable
MonsterBreathingAudioPlayer : audio_player_device = audio_player_device{}
OnBegin<override>()<suspends>:void=
# 몬스터를 숨겨두어 의도한 시간보다 일찍 플레이어가 발견하지 못하도록 합니다.
MonsterProp.Hide()
# 컷씬 중에 플레이어의 포트나이트 캐릭터의 이동이 잠깁니다.
Players := GetPlayspace().GetPlayers()
if (Player := Players[0], Character := Player.GetFortCharacter[]):
loop:
# 플레이어가 이 레벨에 배치된 트리거를 작동할 때까지 기다립니다.
PlayerTrigger.TriggeredEvent.Await()
PlayerTrigger.Disable()
MonsterProp.Show()
# 컷씬과 함께 시작되는 시퀀스 재생을 시작합니다.
SequenceDevice.Play()
# 컷씬 중 플레이어 움직임을 잠급니다.
Character.PutInStasis(stasis_args{})
EndCinematicTrigger.TriggeredEvent.Await()
# 플레이어 움직임을 잠금 해제합니다.
Character.ReleaseFromStasis()
# 몬스터의 숨소리 오디오를 재생합니다.
MonsterBreathingAudioPlayer.Play()
# 플레이어가 몬스터에게 처치되었는지 탐지합니다.
Character.EliminatedEvent().Await()
Sleep(3.0)
# 플레이어가 체크포인트에서 부활한 뒤 추격 구성을 초기화해 다시 실행되도록 합니다.
SequenceDevice.GoToEndAndStop()
MonsterProp.Hide()
PlayerTrigger.Enable()
운석 충돌 현장
운석 충돌 현장에 도달하면 바위 꼭대기로 올라가 포털에 입장해야 합니다. 그러면 보스 외계인이 있는 마지막 방으로 가게 됩니다. 여기는 탐사 구역으로, 마지막 구역으로 갈 수 있는 포털을 제외하면 상호작용 메카닉이 없습니다. 여기에 메카닉을 추가하거나 환경을 활용해 플레이어를 포털로 이끌 수 있습니다.
우주 외부(보스 구역)

운석 충돌 현장의 포털에 들어가면 우주 외부 구역으로 이동하게 됩니다. 마지막 구역에는 다음과 같이 다양한 디자인 요소가 있습니다.
-
소름 끼치는 보스 외계인 모노리스가 주인공인 엔딩 시네마틱이 이 템플릿을 위해 특별히 제작되었습니다.
-
시네마틱이 으스스한 배경과 회전하는 계단으로 줌 아웃됩니다. 이 소름 돋는 회전 계단과 다른 핵심 요소는 익숙한 사물이 낯설거나 기묘한 방식으로 보이거나 행동하는 것을 보여줌으로써 코즈믹 호러 분위기를 조성하고 긴장감을 자아내는 방법을 시연합니다.
마지막 구역 시퀀스는 end_game_manager_device Verse 장치에 의해 제어됩니다.
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/Diagnostics }
# 이 클래스의 목적은 EndingSequence에 의해 트리거된 이벤트를 처리하고 게임 종료 장치를 활성화하는 것입니다.
end_game_manager_device := class(creative_device):
# 편집 가능 어트리뷰트는 에디터에서 할당 가능한 레퍼런스를 생성합니다.
@editable
TriggerDevice : trigger_device = trigger_device{}
@editable
EndGameDevice: end_game_device = end_game_device{}
# 트리거 장치는 EndingSequence의 게임플레이 이벤트로 트리거됩니다.
OnBegin<override>()<suspends>:void=
TriggerDevice.TriggeredEvent.Await()
if (Player := GetPlayspace().GetPlayers()[0]):
# 게임 종료 장치가 게임을 종료하려면 에이전트나 플레이어를 수신해야 합니다.
EndGameDevice.Activate(Player)
UEFN 아웃라이너 체계
이 프로젝트의 아웃라이너는 아주 편리한 방식으로 정리되어 있습니다. 게임의 모든 구역은 순서대로 번호가 매겨져 있어, 아웃라이너가 게임의 흐름을 따릅니다. 각 구역 폴더 내에는 일련의 다른 폴더가 항상 동일한 알파벳 순서로 정렬되어 있습니다.
-
Floor
-
Lights
-
Props
-
Roof
-
Setups
-
Walls
일부 구역에는 해당 구역 전용 추가 폴더가 있습니다. 해당 폴더에는 구역 제작에 사용된 모든 에셋이 포함됩니다.
Setups: 폴더에는 구역의 시네마틱과 액션 시퀀스를 만드는 Verse 장치를 포함한 장치가 들어 있습니다.시퀀스 폴더에 이름을 붙이거나 A 부터 F 까지 접두사를 붙여 각 시퀀스가 제작된 방법을 설명하는 지침 게시판과 일치하도록 할 수 있습니다.
게임의 구역과 일치하는 폴더 외에도, 다음 폴더도 있습니다.
-
Environment: 이 폴더에는 전체 레벨의 바운드를 제공하는 장치와 우주선 외부 구역의 앰비언스를 만드는 장치가 들어 있습니다.
-
Settings: 이 폴더에는 섬 설정 장치 등 전체 게임의 설정을 제어하는 장치가 들어 있습니다.3개의 초기 지침 게시판 장치(라벨: '행동 개시' 게시판) 또한 포함됩니다.
-
TUTORIAL Jump Scare: 이 폴더에는 점프 스케어 튜토리얼용 머티리얼이 들어 있습니다(다음 섹션 참조).
Jump Scare Tutorial
이는 프로젝트를 위해 완성하고 커스터마이징할 수 있는 미완성 점프 스케어 시퀀스입니다. 게시판에 기본적인 설명이 있지만, 시퀀스의 Verse 코드 코멘트에서 자세한 정보를 확인할 수 있습니다. 템플릿의 다른 지점에 이를 추가하거나 다른 점프 스케어를 새로 추가해 보세요!
점프 스케어 튜토리얼을 설명하는 게시판은 Verse 장치에 unfinished_jump_scare_device
라벨을 붙입니다. 그러나 Verse 익스플로러에서 Verse 장치와 코드의 실제 이름은 tutorial_jump_scare_device
인 것을 알 수 있습니다.
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/Diagnostics }
using { /UnrealEngine.com/Temporary/SpatialMath }
using { Utility }
# 플레이어가 창문 밖을 내다보면 점프 스케어가 작동합니다. 무서운 사물이 휙 나타나고 사운드도 재생됩니다.
# 이는 인식 트리거를 사용해 구현되어 의도한 방향을 플레이어가 보도록 합니다.
# 아래 지침을 따라 코드를 완성하세요.
tutorial_jump_scare_device := class(creative_device):
# 아웃라이너에서 필요한 장치와 사물을 지정하세요. 레벨의 포크리 장치와 근접하게 배치됩니다.
@editable
PerceptionTrigger : perception_trigger_device = perception_trigger_device{}
@editable
ScaryProp : creative_prop = creative_prop{}
@editable
AudioPlayer : audio_player_device = audio_player_device{}
# 사물이 움직이는 속도를 결정합니다.
Duration : float = 1.0
# 사물이 움직이는 거리를 결정합니다.
MovementDistance : float = 700.0
# 아래에는 상자 몬스터가 플레이어가 보고 있을 때 상자 몬스터가 창문을 가로질러 빠르게 지나가는 점프 스케어를 만드는 단계가 설명되어 있습니다.
# 지침을 따라 코드를 채우세요.
OnBegin<override>()<suspends>:void=
# 0.
# 다른 곳에서 발견할 일이 없도록 무서운 사물부터 먼저 숨깁니다.
ScaryProp.Hide()
# 1.
# 플레이어가 인식 트리거를 바라볼 때까지 기다리는 것으로 시작합니다.
# Fortnite.digest.verse에서 perception_trigger_device를 찾거나 이벤트 이름을 찾기 위해 검색하세요.
# 2.
# 오디오를 재생합니다.
# 3.
# 사물이 보여야 합니다.
# 4.
# MoveTo 함수를 사용해 사물의 움직임을 만듭니다. 함수 파라미터에는 유틸리티 스크립트와 MovementDistance 변수의 Duration과 VectorUp을 사용하세요.
# 5.
# 점프 스케어가 끝나면 사물을 다시 숨겨서 흔적을 없앱니다.
# 6.
# 모든 것이 의도한 대로 작동하는지 테스트합니다. 변수 값을 조정해 보고, 레벨의 다른 위치에서도 점프 스케어를 사용할 수 있나 알아보세요!
디자인 결정 및 팁
나만의 게임을 만들기 위해 프로젝트 템플릿을 사용할 때 지침이 되고 영감을 얻을 수 있도록, 본 프로젝트 템플릿의 디자인 의도에 대한 인사이트를 소개합니다.
-
본 프로젝트 템플릿의 목표는 장치나 Verse를 사용하여 UEFN의 이벤트 기반 시스템을 소개하는 것입니다.
-
이 프로젝트는 전반적으로 코즈믹 호러 라는 장르의 분위기를 띱니다. 이 장르는 우주의 광대함 앞에서 느껴지는 존재의 미시성을 강조합니다. 기묘하고 낯설며 그로테스크한 요소를 자주 활용해 이러한 미시성과 공포의 느낌을 전달합니다.
-
점프 스케어는 미디어를 막론하고 다양한 공포 장르에서 흔히 사용되는 기법으로, 이 프로젝트에서도 사용했습니다. 튜토리얼 점프 스케어를 따라 직접 점프 스케어를 만드는 방법을 배울 수 있습니다. 프로젝트에 기본적으로 제공되는 점프 스케어를 수정, 이동, 삭제하는 것도 가능합니다.
-
Verse 장치와 Verse 코드를 검토해 작동 방식을 알아보고, 다른 분야에서 무엇을 복사하고 재사용할 수 있는지 알아보세요. Verse 코드는 메뉴(Menu) 바로 이동해 Verse > Verse 익스플로러(Verse > Verse Explorer) 를 클릭해 확인하고 편집할 수 있습니다. 아웃라이너 옆에 고정된 탭이 열립니다. VSCode에서도 프로젝트의 Verse 코드를 열 수 있습니다.
직접 해보기
이제 레고 섬에 무섭고 으스스한 우주 게임을 만드는 방법을 알았으니, 어서 가서 직접 무서운 콘텐츠를 만들어 보세요!
레고 섬 창작에 대해 자세히 알아보고 싶다면 레고 섬 제작하기 포크리 문서를 확인하세요. 시작하기 UEFN 문서를 둘러보고 UEFN에 대해 더 자세히 알아볼 수도 있습니다.