Antes de adentrarte en la escritura de cualquier código en Verse para el puzle de luces marcadas, es buena idea pensar en la mejor manera de conseguir lo que quieres hacer. Esta sección muestra cómo abordar la creación de una mecánica de puzle. Al final de este paso, tendrás seudocódigo que represente el algoritmo para crear este puzle. El siguiente paso mostrará cómo aplicar este algoritmo en Verse y UEFN.
Identificar objetivos, requisitos y limitaciones
El primer paso es identificar tus objetivos, requisitos y limitaciones. Los requisitos suelen surgir de la descomposición de objetivos más amplios en partes más pequeñas.
| Objetivos |
|
| Requisitos |
|
| Limitaciones |
|
Dividir el problema
Ahora que entiendes lo que quieres y con qué estás trabajando, divide el problema en problemas más pequeños que puedan ser más fáciles de razonar. Hacer preguntas puede ayudar a desglosar un problema mayor:
- ¿Cómo puede interactuar el jugador con el puzle?
- ¿Cómo se utilizan las etiquetas de jugabilidad para encontrar las luces?
- ¿Cómo se definen las condiciones iniciales y las soluciones que se pueden modificar en el editor?
- ¿Cómo se hace corresponder el estado del juego almacenado en una estructura de Verse con los elementos visuales del juego?
- ¿Cómo puede una interacción del jugador actualizar un conjunto específico de luces?
- ¿Cómo se desactiva la interacción con el jugador una vez resuelto el puzle?
A continuación, identifica las posibles dependencias entre estos problemas más pequeños. En este caso, parece que los problemas son independientes, pero merece la pena tenerlo en cuenta:
- Las preguntas 1, 5 y 6 están débilmente relacionadas.
- Para las preguntas 1 y 6, la forma en que el jugador interactúa con el puzle no puede determinar cómo se desactiva la interacción una vez resuelto el puzle.
- En las preguntas 1 y 5, una sola interacción activa varias luces a la vez. Esto informará de la estructura de datos que se utilizará para la asignación de la interacción con las luces.
- La pregunta 2 es una consideración de diseño importante. El funcionamiento de las etiquetas de mecánica de juego API podría influir en cómo se controlan las luces en el código. Esto afecta a las preguntas 4 y 5, porque necesitarás cambiar el estado de las luces en el juego, y por tanto deberías encontrar una forma común de hacerlo.
- Las preguntas 3 y 4 deberían converger probablemente en una única solución para la estructura de datos subyacente para los estados inicial, actual y solución.
Idear posibles soluciones
Ahora que el problema está dividido en problemas más pequeños, céntrate en responder a las preguntas relacionadas con los problemas más pequeños:
1. ¿Cómo puede interactuar el jugador con el puzle?
Hay múltiples soluciones a esta pregunta. En general, puedes utilizar cualquier dispositivo con el que el jugador pueda interactuar y que Verse pueda utilizar para detectar la interacción. El conjunto de herramientas del modo Creativo tiene muchos dispositivos que cumplen estos requisitos, como los dispositivos Activador, los dispositivos Botón, los dispositivos Casilla que cambia de color y los dispositivos Activador de percepción.
En este ejemplo se utiliza el dispositivo Button y su evento InteractedWithEvent, que se envía cada vez que el jugador interactúa con el botón, siempre que el botón esté activado. Para obtener más información sobre eventos, consulta Programación de interacciones con dispositivos.
2. ¿Cómo se utilizan las etiquetas de jugabilidad para encontrar las luces?
Con las etiquetas de jugabilidad, puedes recuperar grupos de actores que tengan asignada una etiqueta personalizada que definas en tu código de Verse.
Puedes utilizar la función GetCreativeObjectsWithTag() para obtener un conjunto de todos los actores a los que se les ha asignado tu etiqueta personalizada. El resultado de la función es un conjunto de todos los objetos que implementan creative_object_interface. El customizable_light_device es la representación en Verse de un dispositivo de luz personalizable y es una clase que implementa creative_object_interface.
No hay un orden garantizado para la lista de dispositivos devuelta por GetCreativeObjectsWithTag(), y la llamada de función puede tardar en devolver todos los dispositivos, sobre todo si hay muchos dispositivos en el nivel, por lo que es buena idea almacenar las luces para acceder rápidamente a ellas más tarde. Esto se llama guardar en caché, y a menudo puede mejorar el rendimiento. Como las luces son una colección del mismo tipo, puedes utilizar una matriz para guardarlas todas juntas.
Esto significa que puedes:
- Crea una nueva etiqueta nombrada
puzzle_light. - Marca todas las luces del puzle con la etiqueta
puzzle_light. - Llama a
GetCreativeObjectsWithTag(puzzle_light)para obtener todos los actores que tengan la etiquetapuzzle_light. - Determina cuál de los resultados de la llamada a función es un
customizable_light_device. - Guarda la lista de objetos
customizable_light_deviceen una matriz para poder acceder a ellos más tarde.
3. ¿Cómo se definen las condiciones iniciales y las soluciones que se pueden modificar en el editor?
Una luz solo tiene dos estados: encendida o apagada. Puedes usar el tipo logic en Verse para representar el estado de encendido/apagado de una luz, ya que los valores del tipo logic solo pueden ser true o false. Como hay varias luces, puedes utilizar aquí también una matriz para almacenar todos los valores logic y hacer que la posición de la matriz, o índice, de un estado de luz coincida con el índice de la luz a la que está asociado.
Esta matriz de valores logic se puede utilizar para definir el estado inicial de las luces del puzle y también contiene el estado actual de las luces durante el juego. Puedes exponer esta matriz al editor con el atributo @editable. Las luces del principio del juego pueden encenderse o apagarse para que coincidan visualmente con el estado almacenado en la matriz.
La solución del puzle debe coincidir con el tipo utilizado para almacenar el estado actual de las luces, de modo que puedas comprobar si el puzle está resuelto comparando ambos. Esto significa que tendrás dos matrices logic editables, una que representará el estado actual de las luces y otra que representará la solución del puzle. Esto significa que puedes cambiar el estado inicial de las luces del puzle y la solución del puzle desde el editor y así poder reutilizar el puzle con diferentes configuraciones.
4. ¿Cómo se hace corresponder el estado del juego almacenado en una estructura de Verse con los elementos visuales del juego?
Puedes encender o apagar un customizable_light_device en el juego utilizando las funciones TurnOn() y TurnOff(). Así, cada vez que actualices el estado actual de las luces, representado por la matriz lógica, deberás llamar también a TurnOn() y TurnOff() para hacer coincidir los visuales del juego con el estado del juego.
5. ¿Cómo puede una interacción del jugador actualizar un conjunto específico de luces?
A partir de la primera pregunta, ya has determinado que el jugador va a interactuar con el puzle utilizando el dispositivo Botón. Puedes suscribirte a un controlador de eventos de InteractedWithEvent del botón que cambiará las luces cuando el jugador interactúe con el dispositivo Botón. Como el jugador puede utilizar varios botones, puedes volver a utilizar aquí una matriz para mantenerlos juntos.
Ahora tienes que identificar cómo asignar cada evento de botón independiente al conjunto de luces que debe conmutar.
Como el orden de las luces en la matriz customizable_light_device va a ser el mismo que el de la matriz lógica para representar el estado de las luces, puedes crear un mapeo entre un botón y los índices de las luces a las que va a afectar. Esta asignación puede representarse en una matriz, donde el orden de los elementos coincide con el orden de los botones y los elementos son matrices de índices.
Puedes hacer que la matriz sea editable, de modo que puedas cambiar la asignación de botones a luces en el editor y poder reutilizar el puzle sin cambiar el código en sí.
6. ¿Cómo se desactiva la interacción con el jugador una vez resuelto el puzle?
Ya sabes que el jugador está interactuando con el puzle mediante el dispositivo Botón, que se detecta a través de InteractedWithEvent.
Una vez resuelto el puzle, ¿cómo puede el dispositivo del puzle dejar de recibir entradas del jugador para que este ya no pueda cambiar el puzle?
Hay al menos tres formas de hacerlo:
- Desactiva los botones del juego cuando el puzle esté resuelto.
- Añade un campo
logicatagged_lights_puzzleque se modifica cuando se resuelve el puzle. Cada vez que se actualiza el estado del juego, hay que comprobar primero este campologicpara asegurarse de que el puzle no se ha resuelto ya. - Anula la suscripción de
InteractedWithEventde los botones cuando se resuelva el puzle para que ya no se llame a los controladores de eventos.
La tercera opción es la mejor porque es una solución sencilla y eficaz. No necesitas crear nuevos campos para comprobar la ejecución condicional del código. El concepto de anular la suscripción de un evento de dispositivo también es reutilizable en otras situaciones. En general, es una buena práctica suscribirse a un evento cuando quieras recibir notificaciones sobre él y anular la suscripción cuando ya no lo necesites. Los detalles de implementación para anular la suscripción se explican más adelante en este tutorial.
Combinar las soluciones y planificar con seudocódigo
Ahora que tienes soluciones a los problemas más pequeños, combínalas para resolver el problema original. Formaliza el algoritmo para construir la solución utilizando seudocódigo.
¿Qué ocurre cuando empieza el juego? Se configuran las luces. Te suscribes a InteractedWithEvent de los botones, buscas todos los dispositivos con la etiqueta puzzle_light y los almacenas en caché. También puedes encender/apagar las luces del juego en función del LightState inicial.
OnBegin:
El resultado de GetCreativeObjectsWithTag(puzzle_light) se almacena en la variable FoundDevices
para cada dispositivo en FoundDevices:
si el dispositivo es un dispositivo de luz personalizable:
Almacenar la luz
if ShouldLightBeOn?:
Encender la luz
else:
Apagar la luz
para cada Botón:
Suscribirse a InteractedWithEvent del botón con el controlador OnButtonInteractedWith
Una versión en sseudocódigo de OnButtonInteractedWith podría tener este aspecto, donde InteractedButtonIndex representa el índice de la matriz button_device que coincide con el botón con el que interactuó el jugador. Verás cómo recibir esta información dentro del controlador de eventos más adelante en el tutorial.
OnButtonInteractedWith:
Obtiene las luces asociadas al botón con el que se ha interactuado utilizando la matriz ButtonsToLights y las almacena en la variable Luces
# Conmuta las luces
para cada Luz en Luces:
if IsLightOn?:
Establecer el estado de la luz en el juego como apagada
Apagar la luz
else:
Establecer el estado de la luz en el juego como encendida
Encender la luz
if IsPuzzleSolved():
Habilitar el generador de objetos
para cada Botón:
Anular suscripción de InteractedWithEvent del botón
El sseudocódigo de PuzleResuelto comprueba si el estado actual de las luces coincide con la solución. Si el estado actual no coincide con la solución, la comprobación falla y no se ejecuta el bloque si PuzleResuelto del seudocódigo anterior. Si el estado actual coincide con la solución, la comprobación tiene éxito y se ejecuta el bloque si PuzleResuelto.
IsPuzzleSolved:
para cada Luz:
si IsLightOn es distinto de IsLightOnInSolution
falla y regresa
éxito
¡Ya has desarrollado tu algoritmo!
Siguiente paso
En el siguiente paso de este tutorial, trasladarás este algoritmo al lenguaje de programación Verse y pondrás a prueba tu proyecto para ver estos pasos en acción.