조명 태그 퍼즐 튜토리얼의 이번 단계에서는 게임플레이 태그 를 사용해 게임이 실행 중인 동안 특정 태그가 달린 액터를 찾는 방법을 알아볼 것입니다. 게임플레이 태그를 사용하면 에디터에서 레퍼런스를 설정하지 않고도 여러 장치를 사용할 수 있습니다. 이를 통해 플레이어의 게임 진행 상황에 따라 코드가 어떤 장치를 활성화할지 동적으로 변경하는 등 흥미로운 게임플레이 기능을 구현할 수 있습니다.
다음 단계를 따라 새 게임플레이 태그를 생성하고 퍼즐 레벨의 모든 조명에 할당해 보세요.
- Verse 익스플로러를 열고 tagged_lights_puzzle.verse 를 더블클릭하여 Visual Studio Code에서 스크립트를 엽니다.
- 코드 파일의 최상단에 다음 코드를 작성합니다.
using { /Verse.org/Simulation/Tags }를 추가하여tag클래스를 참조하고GetCreativeObjectsWithTag()함수를 사용합니다.using { /Verse.org/Simulation }을 추가하여 편집 가능 프로퍼티를 만들 수 있도록 합니다.
using { /Fortnite.com/Devices } using { /Verse.org/Native } using { /UnrealEngine.com/Temporary/Diagnostics } using { /Verse.org/Simulation/Tags } using { /Verse.org/Simulation } log_tagged_lights_puzzle := class(log_channel){} -
log_tagged_lights_puzzle클래스 위에tag클래스로부터 상속받는 새 서브클래스puzzle_light를 추가합니다.tag클래스를 상속받는 클래스의 이름은 모든 포크리 장치에 사용할 수 있는 커스텀 게임플레이 태그가 됩니다.# Verse.org/Simulation/Tags 모듈의 `tag` 클래스를 상속받아 새 게임플레이 태그를 생성합니다. puzzle_light := class(tag){} log_tagged_lights_puzzle := class(log_channel){} - UEFN 툴바에서 Verse 스크립트 빌드(Build Verse Scripts) 를 클릭하여 코드와 새
puzzle_light게임플레이 태그를 프로젝트에 컴파일합니다. - UEFN 아웃라이너(Outliner) 에서 설정 가능한 조명 장치 하나를 선택하고 디테일(Details) 패널을 엽니다.
- '디테일' 패널에서 다음을 수행합니다.
- 새 컴포넌트 추가(Add New Component) 를 클릭하고 Verse 태그 마크업(Verse Tag Markup) 을 선택합니다.
- VerseTagMarkup 컴포넌트를 선택하여 디테일 패널에서 세팅을 봅니다.
- 게임플레이 태그(Gameplay Tags) 에서 태그(Tags) 프로퍼티를 편집하고
puzzle_light태그를 추가합니다.

한 장치에 여러 태그를 추가할 수 있으므로 한 장치가 동시에 여러 그룹에 속할 수 있습니다. 예를 들어,
tag1과tag2가 할당된 장치는GetCreativeObjectsWithTag(tag1{})또는GetCreativeObjectsWithTag(tag2{})를 호출해 찾을 수 있습니다. tagged_lights_puzzle클래스 정의에 다음 두 개의 변수 배열 필드를 추가합니다.LightsState라는 편집 가능한logic변수 배열을 추가해 각 조명이 켜져 있는지 꺼져 있는지 현재 상태를 나타냅니다. 조명의 초기 상태를 설정하는 데에도 사용하므로 배열의 엘리먼트 숫자는puzzle_light태그가 달린 조명의 숫자와 일치해야 합니다. 이 예시에서는 모든 조명이 기본적으로 꺼져 있으므로 모든 조명의 시작 값은false입니다.@editable var LightsState : []logic = array{false, false, false, false}Lights라는 편집 가능한customizable_light_device변수 배열을 추가해puzzle_light게임플레이 태그가 할당된 모든 설정 가능한 조명 장치를 저장합니다.@editable var Lights : []customizable_light_device = array{}
- 게임이 시작되면 장치가
LightsState배열에 명시된 초기 환경설정에 맞춰 조명을 설정하고 게임 스테이트가 변경될 때마다 조명을 업데이트할 수 있도록Lights배열에 레퍼런스를 저장합니다. 이 작업은SetupPuzzleLights() : void메서드에서 수행되며,OnBegin()메서드에서 호출되어 게임 시작 시 조명을 설정합니다.SetupPuzzleLights() : void = Logger.Print(“Setting up in-game lights”) OnBegin<override>()<suspends> : void = SetupPuzzleLights() SetupPuzzleLights()에서GetCreativeObjectsWithTag(puzzle_light{})를 호출해puzzle_light태그가 달린 모든 장치를 찾고TaggedActors배열에 저장합니다.TaggedActors는 스코프가SetupPuzzleLights()메서드에 대해 로컬인 상수 배열이라 이 컨텍스트에서 추론할 수 있으므로 배열의 타입을 명시적으로 지정할 필요는 없습니다.SetupPuzzleLights() : void = Logger.Print("Setting up in-game lights") TaggedActors := GetCreativeObjectsWithTag(puzzle_light{})게임플레이 태그를 사용해 장치를 가져올 때는 일정한 순서가 보장되지 않으므로
GetCreativeObjectsWithTag()함수를 여러 번 호출하면 배열 결과에서 액터 순서가 달라질 수 있습니다.puzzle_light태그가 달린 모든 장치를 가져왔으니, 모든 조명이LightsState배열에 명시된 초기 상태와 일치하는지 확인해야 합니다.for루프를 사용해 태그가 달린 모든 장치를 반복작업할 수 있습니다.for: ActorIndex -> TaggedActor : TaggedActors do: TaggedActorGetCreativeObjectsWithTag()함수는creative_object_interface타입의 배열을 반환합니다. 이 예시에서는 조명을 켜거나 끌 수 있도록 각TaggedActor와customizable_light_device로 상호작용해야 합니다.- 타입 형변환 을 사용해 클래스를 서브클래스로 변환할 수 있습니다. 이때 사용하는 구문은
NewDeviceReference := device_type_to_cast_to[DeviceReference]이며,device_type_to_cast_to는 사용하고자 하는 장치 타입이고, 이 예시의 경우 사용할 장치 타입은customizable_light_device입니다. 이는 실패 가능 표현식입니다. 장치의 타입이 다르다는 등의 이유로 장치를 해당 타입으로 변환할 수 없는 경우 타입 변환에 실패하기 때문입니다.LightDevice := customizable_light_device[TaggedActor]
GetCreativeObjectsWithTag()함수의 반환 타입은[]creative_object_interface입니다. 다양한 타입의 액터를 반환할 수 있기 때문에 반환 타입은GetCreativeObjectsWithTag()에 의해 반환될 모든 액터가 구현해야 하는 인터페이스입니다. 자세한 내용은 게임플레이 태그를 참고하세요.for표현식을 사용할 때, 실패 가능 표현식으로 장치를 필터링하고for코드 블록에서 사용할 새로운 변수를 생성할 수 있습니다. 이 예시에서는 이전 단계의 반복작업 표현식 안에customizable_light_device로 타입 변환하는 코드를 추가할 것입니다.for: ActorIndex -> TaggedActor : TaggedActors LightDevice := customizable_light_device[TaggedActor] do: LightDevice- 코드 블록의 마지막 표현식이 코드 블록의 결과입니다.
for표현식은 각 반복작업의 코드 블록 결과를 배열에 담아 반환하므로, 이for표현식의 결과는puzzle_light태그가 달린customize_light_device레퍼런스의 배열입니다.for표현식의 결과를 사용해Lights배열을 직접 업데이트할 수 있습니다.set Lights = for: ActorIndex -> TaggedActor : TaggedActors LightDevice := customizable_light_device[TaggedActor] do: LightDevice for루프는 또한 각 조명이 에디터의 초기LightsState설정을 만족하도록TurnOn()/TurnOff()함수를 호출해야 합니다.for표현식이ActorIndex같은 현재 태그된 장치의 인덱스를 반환하여LightsState배열에서 해당 인덱스의 조명이 켜져 있어야 하는지 꺼져 있어야 하는지 확인할 수 있습니다.set Lights = for: ActorIndex -> TaggedActor : TaggedActors LightDevice := customizable_light_device[TaggedActor] ShouldLightBeOn:= LightsState[ActorIndex] do: LightDevice- 그다음,
ShouldLightBeOn이true인지false인지에 따라TurnOn()또는TurnOff()를 호출합니다.if표현식을 사용해 조건에 따른 여러 표현식, 특히 실패 가능 표현식을 실행할 수 있습니다. 이 예시에서는IsLightOn에 쿼리 연산자?를 사용해 실패 가능 표현식을 실행합니다. 쿼리 연산자는ShouldLightBeOn이true인 경우 성공해TurnOn()을 호출하고ShouldLightBeOn이false인 경우 실패해TurnOff()를 호출합니다.set Lights = for: ActorIndex -> TaggedActor : TaggedActors LightDevice := customizable_light_device[TaggedActor] ShouldLightBeOn := LightsState[ActorIndex] do: if (ShouldLightBeOn?) then LightDevice.TurnOn() else LightDevice.TurnOff() LightDevice - 코드가 예상대로 작동하는지 검증하고 레벨에서 표시되는 조명과 비교할 수 있도록 조명의 인덱스와 시작 값을 출력하는 것도 좋은 방법입니다.
- 스트링 안에
{}를 사용하면,{}안의 표현식이 먼저 평가된 후에 해당 값이 스트링에 추가됩니다. 따라서 스트링 안에if표현식을 사용해 조건부로 값을 추가할 수 있습니다.set Lights = for: ActorIndex -> TaggedActor : TaggedActors LightDevice := customizable_light_device[ActorIndex] ShouldLightBeOn := LightsState[ActorIndex] do: Logger.Print("Adding Light at index {ActorIndex} with State:{if (ShouldLightBeOn?) then "On" else "Off"}") if (ShouldLightBeOn?) then LightDevice.TurnOn() else LightDevice.TurnOff() LightDevice
- 타입 형변환 을 사용해 클래스를 서브클래스로 변환할 수 있습니다. 이때 사용하는 구문은
SetupPuzzleLights()메서드는 다음과 같을 것입니다.SetupPuzzleLights() : void = TaggedActors := GetCreativeObjectsWithTag(puzzle_light{}) <# puzzle_light 태그가 달린 각 장치를 customizable_light_device로 타입 형변환 시도하여 설정 가능한 조명 장치인지 확인합니다. 설정 가능한 조명 장치라면 초기 LightState를 가져와 LightDevice를 TurnOn()하거나 TurnOff()합니다. 태그가 달린 모든 customizable_light_device를 Lights 배열에 저장합니다. #> set Lights = for: ActorIndex -> TaggedActor : TaggedActors LightDevice := customizable_light_device[TaggedActor] ShouldLightBeOn := LightsState[ActorIndex] do: Logger.Print("Adding Light at index {ActorIndex} with State:{if (ShouldLightBeOn?) then "On" else "Off"}") if (ShouldLightBeOn?) then LightDevice.TurnOn() else LightDevice.TurnOff() LightDevice- Visual Studio Code에서 스크립트를 저장합니다.
- UEFN 툴바에서 Verse 스크립트 빌드(Build Verse Scripts) 를 클릭하여 코드를 컴파일합니다.
- UEFN 툴바에서 플레이(Play) 를 클릭하여 레벨을 플레이테스트합니다.
레벨을 플레이테스트할 때, Lights 배열에 추가된 모든 조명을 볼 수 있어야 하며, 출력 로그에 모든 조명의 초기 상태가 출력되어야 합니다.
다음 단계
이 튜토리얼의 다음 단계에서는 플레이어가 버튼을 누를 때 특정 조합의 조명을 켜거나 끄는 방법을 알아보겠습니다.