조명 태그 퍼즐 튜토리얼의 이번 단계에서는 플레이어가 퍼즐을 푼 시점을 탐지해 아이템을 생성하고 이후 퍼즐과 상호작용할 수 없도록 만드는 방법을 알아볼 것입니다.
풀린 퍼즐 탐지하기
이 섹션에서는 플레이어가 올바른 조명 조합을 찾아내 퍼즐을 푼 시점을 탐지하는 방법을 알아봅니다. 퍼즐을 풀면 아이템을 생성하기 위해 아이템 생성 장치가 활성화됩니다.
다음 단계를 따라 플레이어가 퍼즐을 푼 시점을 탐지하세요.
tagged_lights_puzzle클래스에 아이템 생성 장치를 나타내는 편집 가능item_spawner_device필드ItemSpawner를 추가합니다.@editable ItemSpawner:item_spawner_device = item_spawner_device{}- 그다음, 조명이 어떤 상태에 있어야 퍼즐이 풀린 것인지 정의합니다.
logic배열로 조명의 상태를 나타내고 있으므로 쉽게 비교하기 위해 조명의 풀린 상태 또한logic배열로 나타내는 것이 좋습니다.tagged_lights_puzzle클래스에 편집 가능logic배열 필드SolvedLightsState를 생성합니다. 이 예시에서는 플레이어가 모든 조명을 켜면 퍼즐이 풀린 것이므로, 모든 조명이 켜진 것을 나타내기 위해 모든 엘리먼트의 값을true로 초기화합니다.@editable SolvedLightsState : []logic = array{true, true, true, true} - Visual Studio Code에서 파일을 저장합니다.
- UEFN 툴바에서 Verse 스크립트 빌드(Build Verse Scripts) 를 클릭하여 레벨의 Verse 장치를 업데이트합니다.
- 아웃라이너(Outliner) 에서 tagged_lights_puzzle 을 선택하고 디테일(Details) 패널을 엽니다.
- 디테일(Details) 패널에서 아이템 생성 장치(Item Spawner) 프로퍼티를 레벨 내 아이템 생성 장치로 설정합니다.
- 그다음, 현재
LightsState가SolvedLightsState와 일치하는지 확인하는 코드를 작성합니다.tagged_lights_puzzle클래스에 새 메서드IsPuzzleSolved()를 추가합니다. 이 메서드는 퍼즐을 푼 경우 성공하고 풀지 못한 경우 실패하여 호출자에 확인 결과를 알려줍니다. 따라서decides지정자를 사용해 실패 가능 메서드로 선언해야 합니다. 메서드에decides지정자가 있으므로transacts지정자도 있어야 합니다. 이는 메서드 내에서 실패하는 부분이 있을 경우 이 메서드가 수행한 모든 작업이 마치 수행된 적이 없었던 것처럼 롤백된다는 것을 의미합니다.IsPuzzleSolved()<decides><transacts> : void = Logger.Print(“Checking if puzzle is solved”)Verse의 의사 결정에는 성공 또는 실패 여부가 사용됩니다. Verse에서 실패가 어떻게 사용되는지에 대한 자세한 내용은 실패를 참고하세요.
- 장치에서 퍼즐이 풀렸는지 언제 확인해야 할까요?
ToggleLights()메서드 내에서LightsState배열이 업데이트될 때마다 확인하는 것이 최선의 방법입니다.for표현식이LightsState배열을 업데이트한 후,IsPuzzleSolved[]메서드를 호출해 퍼즐이 풀렸는지 확인하고 풀렸다면ItemSpawner.Enable()을 호출해 아이템을 생성합니다.IsPuzzleSolved[]메서드는 호출 시()대신[]가 사용되는 실패 가능 표현식이므로 실패 컨텍스트에서 호출되어야 합니다. 이 예시에서는 퍼즐이 풀렸는지 여부에 따라 표현식을 조건부로 실행하기 위해if표현식을 실패 컨텍스트로 사용합니다.ToggleLights(LightIndices : []int) : void = for: LightIndex : LightIndices IsLightOn := LightsState[LightIndex] Light := Lights[LightIndex] do: Logger.Print("Turning light at index {LightIndex} {if (IsLightOn?) then "Off" else "On"}") NewLightState := if (IsLightOn?): Light.TurnOff() False else: Light.TurnOn() True if (set LightsState[LightIndex] = NewLightState): Logger.Print("Updated the state for light at {LightIndex}") if (IsPuzzleSolved[]): Logger.Print("Puzzle solved!") ItemSpawner.Enable() - 이제
IsPuzzleSolved()메서드가 퍼즐이 풀렸는지 탐지하도록 만듭니다.IsPuzzleSolved()는 실패 컨텍스트이므로 메서드 바디에if표현식과 같은 다른 실패 컨텍스트를 넣지 않아도 실패 가능 표현식을 사용할 수 있습니다. 이 예시에서는 모든 조명의 상태가 풀린 퍼즐의 상태와 일치하는지 확인해야 합니다. 실패 가능 표현식인 같음 연산자=를 사용해 두logic값이 일치하는지 확인할 수 있습니다. 확인하는 두 값이 처음으로 같지 않을 때 표현식이 실패해 메서드가 실패하며, 이 경우 호출자의 컨텍스트인ToggleLights()메서드 내의if표현식으로 값을 반환합니다.IsPuzzleSolved()<decides><transacts> : void = Logger.Print(“Checking if puzzle is solved”) for: LightIndex -> IsLightOn : LightsState IsLightOnInSolution := SolvedLightsState[LightIndex] do: IsLightOn = IsLightOnInSolution - Visual Studio Code에서 변경사항을 저장합니다.
- UEFN 툴바에서 Verse 스크립트 빌드(Build Verse Scripts) 를 클릭하여 코드를 컴파일합니다.
- UEFN 툴바에서 플레이(Play) 를 클릭하여 레벨을 플레이테스트합니다.
이 예시와 같은 세팅에서 레벨을 플레이테스트할 경우, 모든 버튼과 한 번씩 상호작용하면 퍼즐이 풀려 아이템이 생성됩니다.

퍼즐을 풀었을 때 버튼 상호작용 비활성화하기
퍼즐을 완료한 후, 플레이어는 버튼과 상호작용하거나 조명을 켜고 끌 수 없어야 합니다. 이 섹션에서는 이벤트에서 등록을 해제해 플레이어가 버튼과 상호작용해도 이벤트 핸들러가 호출되지 않도록 만드는 방법을 알아봅니다.
장치 이벤트에 Subscribe() 를 호출하면 해당 함수 호출은 cancelable 결과를 가집니다. cancelable 변수에 Cancel() 을 호출하면 이벤트 핸들링 함수를 등록 해제하며, 이후 이벤트가 디스패치되어도 해당 함수가 호출되지 않습니다.
다음 단계를 따라 퍼즐을 풀었을 때 버튼 상호작용을 비활성화해 보세요.
tagged_lights_puzzle클래스에ButtonSubscriptions로 명명된cancelable배열 변수 필드를 추가해 각 버튼의 이벤트에 등록한 결과를 저장하고, 해당 필드를 빈 배열로 초기화합니다.var ButtonSubscriptions : []cancelable = array{} []cancelable = array{}- 이는
for표현식의 마지막 문이므로 모든 성공적인 반복작업의 반환 값은 표현식 반환 타입의 배열에 수집됩니다. 이전에 설명했듯이 이벤트Subscribe호출의 반환 타입은cancelable입니다. 이에 따라cancelable배열[]cancelable을for의 결과로 ToggleLights에 전달합니다. 이는ButtonsSubscription의 타입과 일치하므로for표현식의 결과를ButtonsSubscription배열에 할당할 수 있습니다.OnBegin함수의SetupPuzzleLights다음에 이 코드를 추가합니다.OnBegin<override>()<suspends> : void = SetupPuzzleLights() set ButtonSubscriptions = for: ButtonIndex -> Button : 버튼 LightIndices := ButtonsToLights[ButtonIndex] do: Button.InteractedWithEvent.Subscribe(button_event_handler{Indices := LightIndices, PuzzleDevice := Self}.OnButtonPressed) - 마지막으로 플레이어가 더 이상
LightsState를 변경하지 못하도록 버튼을 비활성화해야 합니다. 각 버튼의cancelable등록을 호출하여InteractedWithEvent핸들러를 등록 해제하면 됩니다.OnBegin에서 이벤트 핸들러가 생성되었을 때ButtonSubscriptions가 저장되었습니다. 이제 이 배열을 반복작업하여 각ButtonSubcription에 cancel을 호출하기만 하면 됩니다.ToggleLights(LightIndices : []int) : void = for: LightIndex : LightIndices IsLightOn := LightsState[LightIndex] Light := Lights[LightIndex] do: Logger.Print("Turning light at index {LightIndex} {if (IsLightOn?) then "Off" else "On"}") NewLightState := if (IsLightOn?): Light.TurnOff() False else: Light.TurnOn() True if (set LightsState[LightIndex] = NewLightState): Logger.Print("Updated the state for light at {LightIndex}") if (IsPuzzleSolved[]): Logger.Print("Puzzle solved!") ItemSpawner.Enable() for (ButtonSubscription : ButtonSubscriptions): ButtonSubscription.Cancel() - Visual Studio Code에서 변경사항을 저장합니다.
- UEFN 툴바에서 Verse 스크립트 빌드(Build Verse Scripts) 를 클릭하여 코드를 컴파일합니다.
- UEFN 툴바에서 플레이(Play) 를 클릭하여 레벨을 플레이테스트합니다.
설정한 기본 프로퍼티에서 모든 버튼과 한 번씩 상호작용하면 퍼즐이 풀려 아이템이 생성되고, 이후 버튼 상호작용이 비활성화될 것입니다.
다음 단계
튜토리얼의 다음 단계에서는 튜토리얼의 완성된 스크립트를 확인하고 이 예시에 추가할 수 있는 기능은 무엇이 있는지 알아봅니다.