Al completar este paso del tutorial Puzzle de luces etiquetadas, aprenderás cómo conmutar un grupo de luces con base en el botón con el que interactúa el jugador.
Conmutación de luces
Deberás crear un mapeo entre un botón y el grupo de luces que debería conmutar cuando el jugador interactúa con él. Para ello, puedes mapear cada botón a los índices de las luces del array Lights.
Este ejejmplo usa el siguiente mapeo entre los botones y las luces:
- El botón 1 se mapea a la luz en el índice 0 y la luz en el índice 3.
- El botón 2 se mapea a la luz en el índice 0, la luz en el índice 1 y la luz en el índice 2.
- El botón 3 se mapea a la luz en el índice 0 y la luz en el índice 1.
- El botón 4 se mapea a la luz en el índice 1.
Puedes representar este mapeo con un array denominada ButtonsToLights, donde cada elemento de ButtonsToLights es otro array que contiene los índices de las luces. El tipo de ButtonsToLights [][]int, para especificar que ButtonsToLights es un array de arrays de enteros.
| Índice | 0 | 1 | 2 | 3 |
| Elemento | matriz{0, 3} | matriz{0, 1, 2} | matriz{0, 1} | matriz{1} |
Realiza lo siguiente para conmutar la luces:
- Crea una matriz de matrices de enteros denominada
ButtonsToLightse inicialízala con el mapeo de índices botón a luz descrito en la tabla anterior.ButtonsToLights : [][]int = array{array{0, 3}, array{0, 1, 2}, array{0, 1}, array{1}}Los índices de una matriz comienzan en 0 y aumentan al número de elementos menos 1. Por lo tanto, el primer elemento de
ButtonsToLightsestá en el índice 0 y el último en el índice 3. - Añade un nuevo método denominado
ToggleLights()a la clasetagged_lights_puzzle. Este método conmutará las luces de la matrizLightsentre encendidas y apagadas de acuerdo con los índices dados a la función como una matriz de enteros (para que coincidan con los elementos de la matrizButtonsToLights) y actualizará los elementos en los mismos índices deLightsState.- Añade el parámetro
LightIndices : []intal métodoToggleLights()e imprime todos los índices en el registro de salida con la expresiónfor.ToggleLights(LightIndices : []int) : void = for: LightIndex : LightIndices do: Logger.Print("Alternando luz en {LightIndex}") - Llama a
ToggleLights()enOnBegin()para probar el método a medida que lo creas. Usa el primer elemento deButtonsToLightscomo prueba. Debido a que la indexación a un array es una expresión falible, deberás acceder al array desde un contexto de fallo. Este ejemplo usa la expresiónifpara el contexto de fallo.
OnBegin<override>()<suspends> : void = SetupPuzzleLights() # Usa el primer elemento de ButtonsToLights para probar el método ToggleLights if (LightIndices : []int = ButtonsToLights[0]): ToggleLights(LightIndices) - Añade el parámetro
- Ahora que tienes
LightIndex, accede a las matricesLightsyLightsStateen dicho índice para obtener la referencia al dispositivo de luz personalizable y su estado actual. Conmutar una luz significa: si la luz está encendida, apagarla; si la luz está apagada, encenderla. Actualiza la declaración de impresión para decir cuál será el nuevo estado de la luz.ToggleLights(LightIndices : []int) : void = for: LightIndex : LightIndices Light := Lights[LightIndex] IsLightOn := LightsState[LightIndex] do: Logger.Print("Encendiendo luz en {LightIndex} {if (IsLightOn?) entonces "Apagar" else "Encender"}") - Ahora actualiza el estado del dispositivo de luz personalizable tanto en el juego como en la matriz
LightsState.- Llama a
TurnOn()en la luz siIsLightOnesfalsoy aTurnOff()en la luz siIsLightOnesverdadero. La última expresión en un bloque de código es el resultado; por lo tanto, si se definefalsooverdaderocomo la última expresión significa que el valor se almacenará enNewLightState.ToggleLights(LightIndices : []int) : void = for: LightIndex : LightIndices Light := Lights[LightIndex] IsLightOn := LightsState[LightIndex] do: Logger.Print("Encendiendo luz en {LightIndex} {if (IsLightOn?) entonces "Apagar" else "Encender"}") NewLightState := if (IsLightOn?): Light.TurnOff() false else: Light.TurnOn() true - Actualiza el elemento
LighsStateenLightIndexcon el valor enNewLightState. Dado que la indexación de matrices es una expresión falible, la configuración deLightsStatedebe envolverse en un contexto de fracaso. En este ejemplo, el contexto de fracaso es la expresión `expresión if. Imprime en el registro de salida que se actualizó el estado.ToggleLights(LightIndices : []int) : void = for: LightIndex : LightIndices IsLightOn := LightsState[LightIndex] Light := Lights[LightIndex] do: Logger.Print("Encendiendo luz en {LightIndex} {if (IsLightOn?) entonces "Apagar" else "Encender"}") NewLightState := if (IsLightOn?): Light.TurnOff() false else: Light.TurnOn() true if (set LightsState[LightIndex] = NewLightState): Logger.Print("Se actualizó el estado de la luz en {LightIndex}")
Cuando se usan contextos de fallo, es buena idea imprimir el registro de salida. Si cualquiera de las expresiones falla en un contexto de fallo, los cambios que se realizan en el contexto de fallo se revierten como si nunca hubieran ocurrido. Si imprimes el registro de salida, puedes comprobar si se ha realizado el cambio si el texto aparece en el registro de salida para no confiar únicamente en que el estado en el juego verifique si el cambio tuvo éxito.
- Llama a
Conectar las pulsaciones de los botones con la conmutación de las luces
Ahora que has definido cómo conmutar las luces, el siguiente paso es conectar las pulsaciones de los botones a la conmutación de las luces entre encendidas y apagadas.
Puedes hacerlo si suscribes al InteractedWithEvent del botón. Si deseas obtener más detalles sobre la suscripción a eventos, consulta Codificación de interacciones entre dispositivos.
InteractedWithEvent espera un controlador de eventos con un parámetro InPlayer : agent y un tipo de devolución void, pero el controlador de eventos también necesita saber a cuál luz está conectado el botón que envió el evento y, además, incluir una referencia a tagged_lights_puzzle del dispositivo de Verse para poder llamar al método ToggleLights().
Puedes agrupar toda esta información en un objeto personalizado al crear una nueva clase que contenga los índices y la función a suscribir. De esta manera, cada botón tiene su propio estado personal y controlador de eventos representado por esta nueva clase.
Realiza lo siguiente para crear un objeto personalizado para controlar los eventos:
- Crea una nueva clase denominada
button_event_handler. La definición de la clase debería tener lo siguiente:- Un array de enteros denominada
Indices. - Un campo
tagged_lights_puzzledenominadoPuzzleDevice, que es la referencia al dispositivo de Verse para poder llamar al métodoToggleLights(). - Un método denominado
OnButtonPressed()con el parámetroInPlayer : agenty un tipo de devoluciónvoidque llama aToggleLights()enPuzzleDevice.button_event_handler := class(): # Posiciones que se usan para acceder a las luces que controla este botón. Indices : []int # tagged_lights_puzzle que crearon este button_event_handler para poder llamar funciones a él. PuzzleDevice : tagged_lights_puzzle OnButtonPressed(InPlayer : agent) : void = # Decir a PuzzleDevice que conmute las luces en las posiciones que controla este botón. PuzzleDevice.ToggleLights(Indices)
- Un array de enteros denominada
- Crea un campo de matriz
button_deviceeditable en la clasetagged_lights_puzzlepara hacer referencia a los botones con los que el jugador puede interactuar:@editable Buttons : []button_device = array{} - Ahora, actualiza
OnBegin()en la clasetagged_lights_puzzlepara crear una instancia debutton_event_handlerpara cada botón. button_event_handler necesita la siguiente información:- Índices de las luces asociadas con el botón, que pueden obtenerse del array
ButtonsToLightsconButtonIndexsuministrado por la expresiónfor. Puedes obtener esto como una condición de filtro de la expresiónforusada para iterar en todos losBotones. Esto también actúa como salvaguarda que protege el código de indexar datos no válidos; si la indexación fracasa, el programa todavía será válido ya que la iteración que fracasa se omite (este fracaso podría ocurrir si olvidas hacer coincidir el número deButtonsToLightscon el número deButtons). - Una referencia al dispositivo de Verse, la instancia de
tagged_lights_puzzle. Para obtener una referencia al objeto actual desde dentro de una definición de clase, puedes usarSelf. - Crear un objeto
button_event_handlercon estos datos es similar a lo siguiente:OnBegin<override>()<suspends> : void = SetupPuzzleLights() for: ButtonIndex -> Button : Buttons LightIndices := ButtonsToLights[ButtonIndex] do: button_event_handler{Indices := LightIndices, PuzzleDevice := Self}
- Índices de las luces asociadas con el botón, que pueden obtenerse del array
- Ahora puedes usar la función del controlador
OnButtonPressed()recientemente creada para suscribir aInteractedWithEventdel dispositivo botón. Cuando se llama a la funciónOnButtonPressed(), tienes acceso a los índices de luces y una referencia al dispositivotagged_lights_puzzleasociado con el botón con el que ha interactuado el jugador.OnBegin<override>()<suspends> : void = SetupPuzzleLights() for: ButtonIndex -> Button : Buttons LightIndices := ButtonsToLights[ButtonIndex] do: Button.InteractedWithEvent.Subscribe(button_event_handler{Indices := LightIndices, PuzzleDevice := Self}.OnButtonPressed) - Guarda tu secuencia de comandos en Visual Studio Code.
- En la barra de herramientas de UEFN, haz clic en «Compilar scripts de Verse** para actualizar el dispositivo de Verse en el nivel con el nuevo código.
- En el esquematizador, selecciona el dispositivo tagged_lights_puzzle para abrir el panel Detalles.
- En el panel de detalles, añade cuatro elementos al array
Buttonsy asigna un botón distinto a cada uno de ellos. No necesitas modificar el resto de las propiedades porque el script propagará dichos propiedades. - En la barra de herramientas de UEFN, haz clic en Jugar para probar el nivel.
Cuando pruebes el juego, podrás interactuar con los botones y cada uno de ellos deberá conmutar un conjunto de luces diferente con base en la configuración de ButtonsLightsIndices. Ten en cuenta que GetCreativeObjectsWithTag() no garantiza un orden específico, por lo que las luces conmutadas en base al orden de la secuencia de comandos pueden no coincidir con el orden que ves en el nivel.

Próximo paso
En el siguiente paso de este tutorial, aprenderás cómo detectar cuando el jugador resuelve el puzzle para que puedas generar un elemento e impedir más interacciones con el puzzle.