Ao concluir esta etapa no tutorial Quebra-cabeça de luzes marcadas, você aprenderá a acender e apagar um grupo de luzes com base no botão com o qual o jogador interage.
Alternando Luzes
Você precisará criar um mapeamento entre um botão e o grupo de luzes que ele deve acender ou apagar quando o jogador interagir com o botão. Para fazer isso, você pode mapear cada botão para os índices das luzes na matriz Lights.
Este exemplo usando o seguinte mapeamento entre botões e luzes:
- O botão 1 é mapeado para a luz no índice 0 e a luz no índice 3
- O botão 2 é mapeado para a luz no índice 0, a luz no índice 1 e a luz no índice 2
- O botão 3 é mapeado para a luz no índice 0 e a luz no índice 1
- O botão 4 é mapeado para a luz no índice 1
Você pode representar esse mapeamento com uma matriz denominada ButtonsToLights, em que cada elemento de ButtonsToLights é outra matriz que contém os índices das luzes. O tipo de ButtonsToLights é então [][]int para especificar que ButtonsToLights é uma matriz de matrizes inteiras.
| Índice | 0 | 1 | 2 | 3 |
| Elemento | array{0, 3} | array{0, 1, 2} | array{0, 1} | array{1} |
Siga estas etapas para acender ou apagar as luzes:
- Crie uma matriz de matrizes inteiras denominada
ButtonsToLightse inicialize-a com o mapeamento de botões para índices de luz descrito na tabela acima. ~~~(verse) ButtonsToLights : [][]int = array{array{0, 3}, array{0, 1, 2}, array{0, 1}, array{1}} ~~~Os índices de uma matriz começam em 0 e vão até o número de elementos menos 1. Portanto, o primeiro elemento de
ButtonsToLightsestá no índice 0 e o último elemento, no índice 3. - Adicione um novo método chamado
ToggleLights()à classetagged_lights_puzzle. Esse método alternará entre acender/apagar as luzes na matrizLightscom base nos índices fornecidos para a função como uma matriz inteira (para corresponder aos elementos da matrizButtonsToLights) e atualizará os elementos nos mesmos índices emLightsState.- Adicione o parâmetro
LightIndices : []intao métodoToggleLights()e imprima cada índice no Log de Saída usando a expressãofor. ~~~(verse) ToggleLights(LightIndices : []int) : void = for: LightIndex : LightIndices do: Logger.Print("Alternando luz em {LightIndex}") ~~~ - Chame
ToggleLights()emOnBegin()para testar o método conforme você o cria. Use o primeiro elemento deButtonsToLightscomo teste. Como a indexação em uma matriz é uma expressão falível, você terá que acessar a matriz a partir de um contexto de falha. Este exemplo usa a expressãoifpara o contexto de falha.
OnBegin<override>()<suspends> : void = SetupPuzzleLights() # Use o primeiro elemento de ButtonsToLights para testar o método ToggleLights if (LightIndices : []int = ButtonsToLights[0]): ToggleLights(LightIndices) - Adicione o parâmetro
- Agora que você tem o
LightIndex, acesse as matrizesLightseLightsStatenesse índice para obter a referência do Dispositivo de Luz Personalizável e seu estado atual. Alternar uma luz significa: se a luz estiver acesa, apagá-la e, se a luz estiver apagada, acendê-la. Atualize a instrução de impressão para dizer qual será o novo estado da luz.ToggleLights(LightIndices : []int) : void = for: LightIndex : LightIndices Light := Lights[LightIndex] IsLightOn := LightsState[LightIndex] do: Logger.Print("Acendendo a luz {LightIndex} {if (IsLightOn?) then "Apagada" else "Acesa"}") - Agora, atualize o estado do Dispositivo de Luz Personalizável no jogo e na matriz
LightsState.- Chame
TurnOn()na luz seIsLightOnforfalseeTurnOff()na luz seIsLightOnfortrue. A última expressão em um bloco de código é o resultado. Portanto, definirfalseoutruecomo a última expressão significa que o valor será armazenado emNewLightState. ~~~(verse) ToggleLights(LightIndices : []int) : void = for: LightIndex : LightIndices Light := Lights[LightIndex] IsLightOn := LightsState[LightIndex] do: Logger.Print("Acendendo a luz {LightIndex} {if (IsLightOn?) then "Apagada" else "Acesa"}") NewLightState := if (IsLightOn?): Light.TurnOff() false else: Light.TurnOn() true ~~~ - Atualize o elemento
LighsStateemLightIndexcom o valor emNewLightState. Como a indexação de matriz é uma expressão falível, a definição deLightsStatedeve ser encapsulada em um contexto de falha. Neste exemplo, o contexto de falha é a expressãoif. Imprima no Log de Saída que o estado foi atualizado. ~~~(verse) ToggleLights(LightIndices : []int) : void = for: LightIndex : LightIndices IsLightOn := LightsState[LightIndex] Light := Lights[LightIndex] do: Logger.Print("Acendendo a luz {LightIndex} {if (IsLightOn?) then "Apagada" else "Acesa"}") NewLightState := if (IsLightOn?): Light.TurnOff() false else: Light.TurnOn() true if (set LightsState[LightIndex] = NewLightState): Logger.Print("Estado da luz atualizado em {LightIndex}") ~~~
É uma boa ideia imprimir no log de saída ao usar contextos de falha. Se alguma expressão falhar em um contexto de falha, todas as alterações feitas nesse contexto de falha serão revertidas, como se nunca tivessem acontecido. Se você imprimir no registro de saída, poderá verificar novamente se a alteração foi feita se o texto aparecer no registro de saída, sem depender apenas do estado do jogo para verificar se a alteração foi bem-sucedida.
- Chame
Como conectar pressionamentos de botão para acender ou apagar luzes
Agora que você definiu como alternar as luzes, a próxima etapa é conectar os pressionamentos de botão para acender ou apagar as luzes.
Você pode fazer isso assinando o InteractedWithEvent do botão. Consulte Como programar interações entre dispositivos para obter mais detalhes sobre assinatura de eventos.
O InteractedWithEvent espera um manipulador de eventos com um parâmetro InPlayer : agent e um tipo de retorno void, mas o manipulador de eventos também precisa saber a quais luzes o botão que enviou o evento está conectado e também manter uma referência ao tagged_lights_puzzle do seu dispositivo Verse para poder chamar seu método ToggleLights().
Você pode agrupar todas essas informações em um objeto personalizado criando uma nova classe que contém os índices e a função a ser assinada. Dessa forma, cada botão tem seu próprio estado pessoal e manipulador de eventos, conforme representado por essa nova classe.
Siga estas etapas para criar um objeto personalizado para manipulação de eventos:
- Crie uma nova classe chamada
button_event_handler. A definição de classe deve ter o seguinte:- Uma matriz inteira chamada
Indices. - Um campo
tagged_lights_puzzlechamadoPuzzleDevice, que é a referência ao seu dispositivo Verse, para que você possa chamar o métodoToggleLights(). -
Um método chamado
OnButtonPressed()com o parâmetroInPlayer : agente um tipo de retornovoid, que chamaToggleLights()noPuzzleDevice. ~~~(verse) button_event_handler := class(): # Posições usadas para acessar as luzes que este botão controla. Indices : []int# tagged_lights_puzzle que criou este button_event_handler para que possamos chamar funções nele. PuzzleDevice : tagged_lights_puzzle
OnButtonPressed(InPlayer : agent) : void = # Diga a PuzzleDevice para alternar as luzes nas posições que este botão controla. PuzzleDevice.ToggleLights(Indices) ~~~
- Uma matriz inteira chamada
- Crie um campo de matriz
button_deviceeditável na classetagged_lights_puzzlereferenciando os botões com os quais o jogador pode interagir: ~~~(verse) @editable Buttons : []button_device = array{} ~~~ - Agora, atualize
OnBegin()na classetagged_lights_puzzlepara criar uma instânciabutton_event_handlerpara cada botão. O button_event_handler precisa das seguintes informações:- Índices das luzes associados ao botão, que você pode obter da matriz
ButtonsToLightsusando oButtonIndexfornecido pela expressãofor. Você pode obter isso como uma condição de filtro da expressãoforusada para iterar por todos osButtons. Isso também funciona como uma salvaguarda que protege o código de indexar dados inválidos; se a indexação falhar, o programa ainda será válido, pois a iteração com falha é ignorada (essa falha pode acontecer se você esquecer de combinar o número deButtonsToLightscom o número deButtons). - Uma referência ao seu dispositivo Verse, a instância de
tagged_lights_puzzle. Para obter uma referência ao objeto atual de dentro de uma definição de classe, você pode usarSelf. -
A criação de um objeto
button_event_handlercom esses dados se parece com o seguinte: ~~~(verse) OnBegin() : void = SetupPuzzleLights() for: ButtonIndex -> Button : Buttons LightIndices := ButtonsToLights[ButtonIndex] do: button_event_handler{Indices := LightIndices, PuzzleDevice := Self} ~~~
- Índices das luzes associados ao botão, que você pode obter da matriz
-
Agora, você pode usar a função
OnButtonPressed()do manipulador recém-criado para assinar oInteractedWithEventdo dispositivo Button. Quando a funçãoOnButtonPressed()é chamada, você tem acesso aos índices de luz e uma referência ao dispositivotagged_lights_puzzleassociado ao botão com o qual o jogador interagiu. ~~~(verse) OnBegin() : void = SetupPuzzleLights() for: ButtonIndex -> Button : Buttons LightIndices := ButtonsToLights[ButtonIndex] do: Button.InteractedWithEvent.Subscribe(button_event_handler{Indices := LightIndices, PuzzleDevice := Self}.OnButtonPressed) ~~~
- Salve o script no Visual Studio Code.
- Na barra de ferramentas do UEFN, clique em Compilar scripts do Verse para atualizar seu dispositivo Verse no nível com o novo código.
- No Organizador, selecione o dispositivo tagged_lights_puzzle para abrir seu painel Detalhes.
- No painel Detalhes, adicione quatro elementos à matriz
Buttonse atribua um botão diferente a cada um. Você não precisa modificar as outras propriedades porque o script as preencherá. - Na barra de ferramentas do UEFN, clique em Jogar para testar o nível.
Ao testar seu nível agora, você deve ser capaz de interagir com os botões, e cada botão deve alternar um conjunto diferente de luzes com base na configuração de ButtonsLightsIndices. Lembre-se de que GetCreativeObjectsWithTag() não garante uma ordem específica, portanto, as luzes que são alternadas com base na ordem do script podem não corresponder à ordem que você vê no nível.

Próxima etapa
Na próxima etapa deste tutorial, você aprenderá a detectar quando o jogador resolve o enigma para que você possa gerar um item e evitar mais interação com o enigma