Wykonując ten krok w samouczku Łamigłówka z otagowanymi światłami, nauczysz się przełączać grupę świateł zgodnie z tym, który przycisk naciśnie gracz.
Przełączanie świateł
Trzeba utworzyć mapowanie między przyciskiem a grupą świateł, które przycisk będzie przełączał, gdy gracz go naciśnie. W tym celu można zmapować każdy przycisk do indeksów świateł w tablicy Lights
.
W tym przykładzie zastosowano następujące mapowania między przyciskami i światłami:
- Przycisk 1 jest mapowany do światła pod indeksem 0 oraz światła pod indeksem 3
- Przycisk 2 jest mapowany do światła pod indeksem 0, światła pod indeksem 1 oraz światła pod indeksem 2
- Przycisk 3 jest mapowany do światła pod indeksem 0 oraz światła pod indeksem 1
- Przycisk 4 jest mapowany do światła pod indeksem 1
Można utworzyć reprezentację tego mapowania za pomocą tablicy o nazwie ButtonsToLights
, w której każdy element tablicy ButtonsToLights
jest kolejną tablicą zawierającą indeksy świateł. Następnie dla tablicy ButtonsToLights
ustawia się typ [][]int
, aby wskazać, że ButtonsToLights
jest tablicą złożoną z tablic liczb całkowitych.
Indeks | 0 | 1 | 2 | 3 |
Element | array{0, 3} | array{0, 1, 2} | array{0, 1} | array{1} |
Aby przełączać światła, wykonaj następujące instrukcje:
- Utwórz tablicę o nazwie
ButtonsToLights
składającą się z tablic liczb całkowitych i zainicjuj ją poprzez mapowanie przycisków do indeksów świateł zgodnie z opisem zawartym w powyższej tabeli.ButtonsToLights : [][]int = array{array{0, 3}, array{0, 1, 2}, array{0, 1}, array{1}}
Indeksy tablic rozpoczynają się od 0, aż do maksymalnej liczby odpowiadającej liczbie elementów pomniejszonej o 1. W związku z tym pierwszy element tablicy
ButtonsToLights
znajduje się pod indeksem 0, a jej ostatni element pod indeksem 3. - Dodaj nową metodę o nazwie
ToggleLights()
do klasytagged_lights_puzzle
. Metoda ta będzie włączać lub wyłączać światła w tablicyLights
w oparciu o indeksy nadane funkcji jako tablicy liczb całkowitych (zgodnie z liczbą elementów tablicyButtonsToLights
) oraz aktualizować elementy zachowane pod tymi samymi indeksami w tablicyLightsState
.- Dodaj parametr
LightIndices : []int
do metodyToggleLights()
i za pomocą polecenia print wyświetl każdy indeks w rejestrze wyjściowym za pomocą wyrażeniafor
.ToggleLights(LightIndices : []int) : void = for: LightIndex : LightIndices do: Logger.Print("Przełączanie światła pod indeksem {LightIndex}")
- Wywołaj metodę
ToggleLights()
w metodzieOnBegin()
, aby przetestować ją w trakcie tworzenia. Na potrzeby testu wykorzystaj pierwszy element tablicyButtonsToLights
. Indeksowanie do tablicy jest wyrażeniem zawodnym, dlatego konieczne jest uzyskanie dostępu do tablicy z poziomu kontekstu niepowodzenia. W tym przykładzie zastosowano wyrażenieif
do kontekstu niepowodzenia.
OnBegin<override>()<suspends> : void = SetupPuzzleLights() # Użyj pierwszego elementu tablicy ButtonsToLights do przetestowania metody ToggleLights if (LightIndices : []int = ButtonsToLights[0]): ToggleLights(LightIndices)
- Dodaj parametr
- Masz już wartość
LightIndex
. Teraz przejdź do tablicLights
iLightsState
pod tym indeksem, aby uzyskać odwołanie do urządzenia konfigurowalnego światła oraz jego bieżący stan. Przełączenie światła oznacza włączenie go, jeśli jest wyłączone, oraz wyłączenie, jeśli jest włączone. Zaktualizuj instrukcję print, uwzględniając, jaki będzie nowy stan światła.ToggleLights(LightIndices : []int) : void = for: LightIndex : LightIndices Light := Lights[LightIndex] IsLightOn := LightsState[LightIndex] do: Logger.Print("Światło pod indeksem {LightIndex} {if (IsLightOn?) then "– wyłączanie" else "– włączanie"}")
- Teraz zaktualizuj stan urządzenia konfigurowalnego światła zarówno w grze, jak i w tablicy
LightsState
.- Wywołaj funkcję
TurnOn()
dla światła, którego stanIsLightOn
przyjmuje wartośćfalse
, i funkcjęTurnOff()
, dla światła, którego stanIsLightOn
przyjmuje wartośćtrue
. Ostatnie wyrażenie w bloku kodu jest wynikiem, dlatego ustawieniefalse
lubtrue
jako ostatniego wyrażenia oznacza, że wartość zostanie zapisana w zmiennejNewLightState
.ToggleLights(LightIndices : []int) : void = for: LightIndex : LightIndices Light := Lights[LightIndex] IsLightOn := LightsState[LightIndex] do: Logger.Print("Światło pod indeksem {LightIndex} {if (IsLightOn?) then "– wyłączanie" else "– włączanie"}") NewLightState := if (IsLightOn?): Light.TurnOff() false else: Light.TurnOn() true
- Zaktualizuj element
LighsState
pod pozycjąLightIndex
o wartość zmiennejNewLightState
. Indeksowanie tablicy jest wyrażeniem zawodnym, dlatego ustawienie stanuLightsState
musi być osadzone w kontekście niepowodzenia. W tym przykładzie kontekstem niepowodzenia jest wyrażenieif
. Za pomocą polecenia print wyświetl w rejestrze wyjściowym informację o aktualizacji stanu.ToggleLights(LightIndices : []int) : void = for: LightIndex : LightIndices IsLightOn := LightsState[LightIndex] Light := Lights[LightIndex] do: Logger.Print("Światło pod indeksem {LightIndex} {if (IsLightOn?) then "– wyłączanie" else "– włączanie"}") NewLightState := if (IsLightOn?): Light.TurnOff() false else: Light.TurnOn() true if (set LightsState[LightIndex] = NewLightState): Logger.Print("Zaktualizowano stan światła pod indeksem {LightIndex}")
Podczas korzystania z kontekstów niepowodzenia dobrym rozwiązaniem jest przekazywanie informacji do rejestru wyjściowego za pomocą polecenia print. Jeśli jakiekolwiek wyrażenie w kontekście niepowodzenia zakończy się niepowodzeniem, wówczas wszelkie zmiany wprowadzone w kontekście niepowodzenia zostaną cofnięte tak, jakby nigdy nie zostały wprowadzone. Wysłanie informacji do rejestru wyjściowego za pomocą polecenia print pozwala upewnić się, że zmiana została wprowadzona po tekście rejestru wyjściowego, dzięki czemu stan samej gry nie jest jedynym wskaźnikiem, na podstawie którego można stwierdzić, że zmiana została wdrożona pomyślnie.
- Wywołaj funkcję
Łączenie naciśnięć przycisków z przełączaniem świateł
Masz już zdefiniowany sposób przełączania świateł. Kolejnym krokiem będzie połączenie naciśnięć przycisków z włączaniem lub wyłączaniem świateł.
Można to zrobić, subskrybując zdarzenie InteractedWithEvent
przycisku. Więcej szczegółów na temat subskrypcji zdarzeń, patrz Kodowanie interakcji z urządzeniem.
Zdarzenie InteractedWithEvent
oczekuje procedury obsługi zdarzeń z jednym parametrem InPlayer : agent
oraz typem informacji zwrotnej void
, jednak procedura obsługi zdarzeń musi również wiedzieć, z którymi światłami połączony jest przycisk wysyłający zdarzenie, a także zawierać odwołanie do urządzenia tagged_lights_puzzle
w Verse, aby móc wywołać jego metodę ToggleLights()
.
Wszystkie te informacje można zebrać razem w jeden obiekt niestandardowy, tworząc nową klasę zawierającą indeksy oraz funkcję do subskrypcji. W ten sposób każdy przycisk będzie miał własny odrębny stan oraz procedurę obsługi zdarzeń reprezentowane przez tę nową klasę.
Aby utworzyć niestandardowy obiekt do obsługi przez handler zdarzeń, wykonaj następujące instrukcje:
- Utwórz klasę o nazwie
button_event_handler
. Definicja klasy powinna zawierać następujące elementy:- Tablica liczb całkowitych o nazwie
Indices
. - Pole urządzenia
tagged_lights_puzzle
o nazwiePuzzleDevice
będące odwołaniem do twojego urządzenia Verse, aby można było wywołać metodęToggleLights()
. - Metoda o nazwie
OnButtonPressed()
zawierająca parametrInPlayer : agent
oraz typ informacji zwrotnejvoid
, która wywołuje metodęToggleLights()
dla polaPuzzleDevice
.button_event_handler := class(): # Pozycje używane w celu uzyskania dostępu do świateł kontrolowanych tym przyciskiem. Indices : []int # Urządzenie tagged_lights_puzzle, które utworzyło tę procedurę obsługi zdarzeń button_event_handler, aby można było wywoływać w nim funkcje. PuzzleDevice : tagged_lights_puzzle OnButtonPressed(InPlayer : agent) : void = # Przekaż do PuzzleDevice instrukcję przełączenia świateł w pozycjach kontrolowanych tym przyciskiem. PuzzleDevice.ToggleLights(Indices)
- Tablica liczb całkowitych o nazwie
- Utwórz edytowalne pole tablicy
button_device
w klasietagged_lights_puzzle
, aby utworzyć odwołania do przycisków, z którymi gracz może wchodzić w interakcje:@editable Buttons : []button_device = array{}
- Teraz zaktualizuj metodę
OnBegin()
w klasietagged_lights_puzzle
, aby utworzyć instancję procedury obsługi zdarzeńbutton_event_handler
dla każdego przycisku. Procedura obsługi zdarzeń button_event_handler musi zawierać następujące informacje:- Indeksy świateł powiązanych z przyciskiem, które można pobrać z tablicy
ButtonsToLights
za pomocą członuButtonIndex
w wyrażeniufor
. Można go potraktować jako warunek filtra wyrażeniafor
używanego do iterowania po wszystkich przyciskachButtons
. Pozwala to również chronić kod przed indeksowaniem nieprawidłowych danych. Jeśli indeksowanie się nie powiedzie, program nadal będzie prawidłowy, ponieważ taka iteracja zakończona niepowodzeniem zostanie pominięta (takie niepowodzenie może wystąpić, jeśli zapomnisz uzgodnić liczbę tablicButtonsToLights
z liczbą przyciskówButtons
). - Odwołanie do twojego urządzenia Verse, instancji
tagged_lights_puzzle
. Aby uzyskać odwołanie do bieżącego obiektu z definicji klasy, możesz użyć identyfikatoraSelf
. - Obiekt
button_event_handler
utworzony za pomocą tych danych wygląda następująco:OnBegin<override>()<suspends> : void = SetupPuzzleLights() for: ButtonIndex -> Button : Buttons LightIndices := ButtonsToLights[ButtonIndex] do: button_event_handler{Indices := LightIndices, PuzzleDevice := Self}
- Indeksy świateł powiązanych z przyciskiem, które można pobrać z tablicy
- Teraz można użyć funkcji
OnButtonPressed()
nowo utworzoną procedurę obsługi w subskrypcji zdarzeniaInteractedWithEvent
urządzenia przycisku. Po wywołaniu funkcjiOnButtonPressed()
masz dostęp do indeksów świateł oraz odwołania do urządzeniatagged_lights_puzzle
powiązanego z przyciskiem, z którym gracz wszedł w interakcję.OnBegin<override>()<suspends> : void = SetupPuzzleLights() for: ButtonIndex -> Button : Buttons LightIndices := ButtonsToLights[ButtonIndex] do: Button.InteractedWithEvent.Subscribe(button_event_handler{Indices := LightIndices, PuzzleDevice := Self}.OnButtonPressed)
- Zapisz skrypt w Visual Studio Code.
- Na pasku narzędzi UEFN kliknij opcję Kompiluj skrypty Verse, aby zaktualizować urządzenie Verse w poziomie o nowy kod.
- W obszarze Outliner wybierz urządzenie tagged_lights_puzzle, aby otworzyć jego panel Szczegóły.
- W panelu Szczegóły dodaj cztery elementy do tablicy
Buttons
i przypisz do każdego inny przycisk. Nie musisz modyfikować innych właściwości, ponieważ skrypt je uzupełni. - Na pasku narzędzi UEFN kliknij przycisk Odtwórz, aby przetestować poziom w grze.
W trakcie testowania poziomu w grze powinna pojawić się możliwość interakcji z przyciskami, a każdy przycisk powinien przełączać inny zestaw świateł zgodnie z konfiguracją ButtonsLightsIndices
. Pamiętaj, że funkcja GetCreativeObjectsWithTag()
nie gwarantuje konkretnej kolejności, dlatego światła przełączane w kolejności przyjętej w skrypcie mogą nie odpowiadać kolejnością efektowi wizualnemu uzyskanemu w poziomie.

Następny krok
W kolejnym kroku tego samouczka nauczysz się wykrywać, gdy gracz rozwiąże łamigłówkę, aby zespawnować przedmiot i uniemożliwić graczowi dalszą interakcję z łamigłówką.