La sala y el juego
El panel de la derecha del editor de escenas tiene tres pestañas. Object enseña lo que tienes elegido en el lienzo: lo cuentan Capas y Objetos. Esta página cuenta las otras dos:
- Room: los ajustes de la sala abierta. Se guardan en su
.scn. - Game: lo que comparten todas las salas del proyecto (el ritmo del juego, las variables del juego y los controles), en
Scenes/Game.json. Los controles se editan en su propia ventana, Game controls.
Lo que estas dos pestañas generan en el código está en El código que genera.
La pestaña Room
La pestaña Room tiene una sección, ROOM. Arriba están los datos de la sala, y debajo, los grupos CAMERA, PHYSICS, VARIABLES, MORE y BUILD.
Los cambios de esta pestaña se deshacen con Ctrl+Z y se guardan con la sala (Ctrl+S).
Nombre, tamaño y pantalla
| Campo | Qué es | De serie |
|---|---|---|
| Name | El nombre de la sala. Es el prefijo de todo lo que declara su código (Fase1Load, FASE1_TAG_…) y el nombre de su fichero. La línea de BUILD dice cuál: Generates Code\Fase1.gen.aru. | El del fichero .scn |
| Room (px) | Ancho y alto de la sala, en píxeles. | 640 × 480 |
| Tile size | El tamaño de un tile, en píxeles. Es la celda que señala la barra de estado y el tamaño de una zona hecha con un solo clic. | 16 × 16 |
| Snap (px) | La rejilla a la que se ajustan los objetos al arrastrarlos. Solo es del editor: View › Snap to the grid la apaga, y mantener Alt también. | 16 × 16 |
| Screen (px) | La pantalla del dispositivo: el marco verde del lienzo. Pon el tamaño con el que tu juego abre la pantalla: con él se calcula hasta dónde llega la cámara, y el Play abre la pantalla así. | 320 × 240 |
| Background | El color de la sala en el lienzo. Haz clic en el cuadro para elegirlo. El juego no lo usa. | Negro |
Las tildes, los espacios y los guiones del nombre cambian el prefijo del código: lo cuenta Tu primer juego con salas. Pon a las salas nombres sin espacios ni tildes.
Si cambias Room (px) y los límites de la cámara eran la sala entera, los límites siguen al tamaño nuevo. Unos límites puestos a mano no cambian.
Una sala nueva (New Scene en el explorador) copia los ajustes de Room de la sala que tengas abierta: los tamaños, el fondo, la música, los valores de colisión, la cámara, la física y Generate .aru. No copia el nombre, el mapa de colisión, a quién sigue la cámara, las variables ni el código de creación.
Música
Music elige una música del proyecto, o (no music). Suena desde que empieza la sala, en bucle.
Si una regla o un estado de la sala usa Play or stop music, mandan ellos: la música de Music ya no suena sola.
El sonido solo sale después de Sound.init(), también en Windows. El código de una sala que suena ya lo llama al cargarla.
Mapa de colisión
Collision map elige el mapa de tiles que dice qué es sólido. Ese mapa no se pinta: solo sirve para chocar. Puede ser el mismo .map que pinta una capa de tiles, para chocar contra lo que se ve, u otro aparte. Sin mapa de colisión, (no collision map), nada choca con los tiles.
Hay dos formas de leerlo:
- Por valores de celda, como viene. Cada celda del mapa lleva un número que pones en el editor de mapas (Show Cell Values los enseña). Solid values son los valores que bloquean por todos los lados. One-way values son plataformas de un solo sentido: se atraviesan saltando desde abajo y se pisan desde arriba.
- Por número de tile, con el botón Tile numbers encendido. Los campos pasan a llamarse Solid tiles y One-way tiles, y lo que escribes son números de tile (Show Tile Numbers, en el editor de mapas, los enseña). Si una capa de tiles pinta ese mismo mapa, esa capa es a la vez la que se ve y la que choca.
Los números van separados por comas, espacios o punto y coma. Al salir del campo, el editor los deja como 1, 2, 7 y quita lo que no es un número entero; lo dice en la barra de estado. De serie, Solid values es 1 y One-way values es 2. Con un campo vacío, ningún valor bloquea de esa forma.
La colisión se mueve con el Offset (px) de la capa que pinta su mapa, y con nada más. Si esa capa tiene parallax, se mueve sola o se repite (Wrap X, Wrap Y), lo que ves y lo que choca se separan: el panel de problemas lo avisa.
Cámara
| Campo | Qué es | De serie |
|---|---|---|
| Bounds min, Bounds max | La esquina de arriba a la izquierda y la de abajo a la derecha del área que la cámara puede enseñar, en píxeles de la sala. | La sala entera |
| Use bounds | Encendido, la cámara no enseña nada fuera de Bounds. Apagado, la cámara no tiene límites, y Mode X / Y no hace nada. | Encendido |
| Mode X / Y | Qué hace la cámara al llegar a los límites, en cada eje: CLAMP se para, FREE no los mira y WRAP da la vuelta. | CLAMP y CLAMP |
| Follow | El objeto al que sigue la cámara, o (free camera) para ninguno. | (free camera) |
| Smooth % | Lo pegada que va la cámara al objeto: con 100 va pegada; con menos, se queda atrás y lo alcanza poco a poco; con 0 no se mueve. | 10 |
Bounds es el área que la cámara puede enseñar, no la posición de la cámara. El código generado hace la cuenta: la esquina de la cámara va de Bounds min a Bounds max menos la pantalla (Screen (px)). Si el área es más pequeña que la pantalla, la cámara se queda centrada. Con WRAP, Bounds es el periodo: la cámara da la vuelta cada Bounds max − Bounds min píxeles.
Follow solo ofrece los sprites con nombre de las capas de objetos que no son de decorado (Decor). Un objeto sin nombre no se puede seguir. El panel de problemas avisa si el objeto seguido ya no existe o no tiene nombre, y si Smooth % está a 0.
La cámara sigue al objeto cuando el juego llama a <Sala>FollowCamera(room), una vez, después de cargar la sala. Esa función solo existe si Follow tiene un objeto: ver El código que genera.
En el lienzo, el marco verde es la pantalla. Arrástralo por su etiqueta para ver qué enseñará la cámara: se mueve dentro de los mismos límites que en el juego. View › Camera bounds dibuja los límites con una línea discontinua, y View › Device screen esconde el marco.
Lo que hace la cámara en el juego lo cuenta la página del módulo Scene.
Física
| Campo | Qué es | De serie |
|---|---|---|
| Enabled | Enciende el mundo físico de la sala. | Apagado |
| Iters | Las pasadas del solver en cada paso de física, de 1 a 20: más es más rígido y más lento. | 3 |
| Gravity | La gravedad de la sala, hacia abajo, en píxeles por segundo al cuadrado. Admite decimales con punto o con coma. | 500 |
| Step rate (Hz) | Los pasos de física por segundo, de 0 a 240. Con 0 hay un paso por fotograma, y en un PC rápido eso hace parpadear onGround() y pierde saltos. | 60 |
Con Enabled apagado, los otros tres campos se quedan grises y la sala no simula cuerpos: los comportamientos mueven los objetos cambiando su posición. Con la física encendida, les dan velocidad y la física los mueve.
El cuerpo de cada objeto (Dynamic, Static…), su masa y su rebote están en Objetos. Con física, el ritmo del juego (Rate (fps), en la pestaña Game) tiene que ser 20 o más, o 0. Y Step rate (Hz) no debe pasar de 4 veces ese ritmo: cada fotograma da como mucho 4 pasos de física, y con más la sala va a cámara lenta. El panel de problemas no lo avisa.
Variables de la sala
El grupo VARIABLES es la lista de las variables de la sala, con su valor de salida (Variable y Starts at).
- Para crear una: escribe el nombre en la caja new name, elige el tipo (int, float, bool o string) y pulsa Add. Nace con el cero de su tipo:
0,falseo el texto vacío. - Para cambiar su valor de salida: escríbelo en la columna Starts at. Si no es de su tipo, el editor deja el de antes y dice por qué en la barra de estado.
- Para cambiar su tipo: elígela en la lista y cambia el tipo. Si su valor no vale para el tipo nuevo, vuelve al cero.
- Para quitarla: elígela y pulsa Remove.
Como dice el panel, vuelven a su valor de salida cada vez que se carga la sala. Lo que tenga que pasar de una sala a otra (los puntos, las vidas) va en las variables del juego, en la pestaña Game.
Las usan los comportamientos y las reglas de la sala, que las eligen por su nombre, y tu código, como room.vars.nombre.
El nombre lleva letras sin tilde, cifras y _, no empieza por una cifra y no puede ser una palabra reservada de JARU. El panel de problemas avisa si dos nombres dan el mismo campo en el código, si un valor de salida no es de su tipo y si una variable de la sala se llama como una del juego: las reglas que la nombran cambiarían la de la sala.
Código de creación
MORE › Creation code... abre una ventana con el código de creación de la sala: código JARU tuyo que se ejecuta una vez, al final de <Sala>Load. Como dice la ventana, la sala ya está montada: tienes room.scene, room.sprites, room.named, room.grids y las variables de la sala.
La ventana se edita como el editor de código del IDE, con colores y autocompletado, también de room. y room.game.. Lo que escribes pasa a la sala al cerrar la ventana (Close) o al salir de ella, y se guarda con la sala.
Corre después de crear los objetos y antes de que empiece la música de Music y de las reglas When the room starts.
El código de creación va dentro de <Sala>Load: una func que declares en él es local. La acción Call a function of yours de una regla no la encuentra, y el juego se para cuando la regla salta. Escribe esas funciones en un .aru del proyecto. El panel de problemas lo avisa.
El código de cada objeto se escribe en su ficha: ver Objetos. MORE › Room logic... abre las reglas de la sala: ver Reglas y estados.
Generate .aru
BUILD › Generate .aru viene encendido: el Build escribe el código de la sala. Apagado, el Build se la salta, guardarla no escribe su .gen.aru y el Play no la juega. Sirve para una sala a medio hacer que tu juego todavía no usa. Más en El código que genera.
La pestaña Game
La pestaña Game tiene lo que comparten todas las salas del proyecto. Se edita aunque no haya ninguna sala abierta, con el proyecto abierto. No hay una sala inicial: la primera sala la carga tu código.
- Se guarda en
Scenes/Game.jsoncon la sala: conCtrl+S, Save, Play, Generate y Compile. - Mientras tiene cambios sin guardar, la pestaña se llama Game *.
- En esta pestaña,
Ctrl+ZyCtrl+Ydeshacen y rehacen los cambios del juego, no los de la sala. - Un proyecto sin
Game.jsonempieza con las cuatro variables fijas y los cinco controles de serie, o con los controles que traían sus salas si son de una versión anterior.
FRAME RATE
Rate (fps) es el ritmo de todo el juego: cuántos fotogramas por segundo pinta como mucho, de 0 a 120. Es Display.fps: Display.update() espera hasta que toca el siguiente fotograma.
- Con 0, que es como viene, lo decide tu código.
- Con otro valor, el código generado pone
Display.fpsuna vez, al arrancar el juego. Tu código lo puede cambiar después. - Con física, pon 20 o más: por debajo, la sala va a cámara lenta, porque la física simula como mucho 0,05 s por fotograma. Sin física, 10 o más. El panel de problemas avisa en los dos casos.
- En el ESP32-P4, 30 o 60 dan un movimiento más regular.
VARIABLES
Las variables del juego: las que pasan de una sala a otra. Como dice el panel, se quedan como están al cambiar de sala, y solo Start a new game las devuelve a su valor de salida (o SceneGameReset(), desde tu código).
Las cuatro primeras están siempre y salen en gris. No se quitan, no se renombran ni cambian de tipo: solo cambia su valor de salida.
| Variable | De serie | Quién la usa |
|---|---|---|
score | 0 | Los puntos. |
lives | 3 | La acción Lose a life, que le resta una. |
health | 3 | La salud. El comportamiento Health la puede usar para el jugador, y Lose a life la devuelve a su valor de salida. |
maxHealth | 3 | El tope de health. |
health se queda entre 0 y maxHealth: el editor la recorta al guardar, y las reglas, al cambiar cualquiera de las dos. Si las cambia tu código, llama después a SceneGameClamp().
Las tuyas se crean, se cambian y se quitan igual que las de la sala, con la caja new name, el tipo, Add y Remove.
En el código, son room.game.nombre en todas las salas: room.game es el mismo objeto en todas. Fuera de una sala, son sceneGame.nombre.
CONTROLS
Los controles del juego: los mismos en todas las salas, catorce como mucho. El panel enseña un resumen, y se editan en la ventana Game controls.
| Columna | Qué es |
|---|---|
| Control | El nombre del control. |
| Key | Su tecla en Windows. |
| Pad | Su botón del mando I2C, o -. |
| Pins | Su GPIO en las placas. Con una familia de placas en uso, el número (GPIO 37) o none; con varias, en cuántas lo tiene (2 of 3). En ámbar, si le falta en una placa donde otros controles sí tienen: ahí no responderá. |
La última línea dice si el mando I2C está encendido y en qué dirección: I2C gamepad: on, at 0x50.
- Haz clic en un control, o en Edit controls..., para abrir la ventana Game controls. Con un clic en la línea del mando también se abre.
- Defaults pone los cinco controles de serie:
left,right,up,downyjump, con las teclasLEFT,RIGHT,UP,DOWNySPACE, sin pines ni botones del mando.
La ventana Game controls
La ventana Game controls edita los controles del juego, uno a uno.
- A la izquierda, la lista CONTROLS, con cuántos hay de los catorce posibles (
5 of 14). Cada fila lleva el nombre, la tecla y el botón del mando.- Para crear uno, escribe su nombre en new name y pulsa Add. Nace con la tecla
SPACE, sin pines ni botón. - Remove quita el elegido.
- Defaults pone los cinco de serie.
- Para crear uno, escribe su nombre en new name y pulsa Add. Nace con la tecla
- A la derecha, el control elegido. Al lado de su nombre, su número de acción tal como lo lee tu código:
In your code: Input.pressed(4).
Los cambios van al deshacer del juego: Ctrl+Z y Ctrl+Y valen en la ventana. Esc o Close la cierran sin perder lo escrito. El juego se guarda con la sala, con Ctrl+S en el editor.
La tecla
El grupo KEYBOARD (Windows and Play) tiene la tecla del control. Pulsa Press a key... y luego la tecla; Esc cancela. Solo vale una tecla que Input.map conozca: la lista está en el módulo Input.
La tecla es la de Windows y la del Play del editor.
Los pines de cada placa
El grupo BUTTONS ON THE BOARD (GPIO) tiene el GPIO del botón del control en cada familia de placas: Classic ESP32, ESP32-S3, ESP32-P4 y ESP32-S31.
- Salen las familias de las placas del proyecto (las de Config › ESP32, con su nombre a la derecha) y las que ya tienen algún pin. Show every board enseña las cuatro.
- El GPIO es un número de 0 a 63. Vacío, el control no tiene botón en esa placa.
- La caja sale en ámbar si al control le falta el pin en una placa donde otros controles lo tienen: ahí no responderá.
El mando I2C
El grupo I2C GAMEPAD es para el mando Adafruit Mini I2C Gamepad (seesaw, producto 5743), el único que hay.
- El botón del control: haz clic en el dibujo del mando, sobre el botón que lo maneja. Valen A, B, X, Y, Start, Select y el joystick como cuatro direcciones. Un botón maneja un solo control: los de otros controles salen en gris, y al hacer clic en uno pasa a este. Otro clic en el suyo lo quita.
- Gamepad on / Gamepad off enciende o apaga el mando para todo el juego. Apagado, no se genera nada del mando y los botones se ignoran.
- Address es su dirección I2C:
0x50, o de0x51a0x53si se cortan los puentes A0 y A1. En la Waveshare S3 2.8, el reloj de la placa ocupa la0x51. - Dead zone es cuánto se aparta el joystick del centro antes de que cuente una dirección: de 0 a 511, sobre un recorrido de 0 a 1023 con el centro en 512. De serie, 200.
- The game opens the bus: enciéndelo si tu código ya llama a
I2C.init, como pasa en el ESP32-P4 por su códec de audio. Entonces el código generado no abre el bus: solo arranca el mando.
Los pines del bus I2C salen de los perfiles de placa del proyecto (Config › ESP32, grupo I2C Bus): el mando arranca en las placas cuyo perfil los tiene. Si el perfil de tu placa no los tiene, en ella no arranca, y el juego lo dice en la consola. En Windows y en el Play no hay mando: valen las teclas.
Con el mando encendido, el editor copia su driver a Code/Drivers la primera vez que genera el código. Cada sala lee el mando en su <Sala>Update. Donde no corre ninguna sala (un título, un fin) o en una sala sin <Sala>Update, llama a SceneInputRead() en cada fotograma.
Cómo llegan los controles al juego
Los controles los mapea SceneInputMap(), una función del código generado. Nadie la llama por ti: tu juego la llama una vez, al arrancar. El Play sí la llama.
- En cada familia de placas con algún pin, mapea el GPIO de cada control y después arranca el mando, si está encendido.
- En una placa sin pines, arranca el mando, si está encendido: es su única entrada.
- En Windows, mapea las teclas.
- Tu código lee cada control con
Input.pressed(número), con el número que enseña la ventana.
Si tu juego mapea más acciones con Input.map, usa números que no tenga ningún control.
En una placa sin controles
Si en una placa ningún control tiene GPIO y el mando no contesta (o está apagado), el juego arranca sin entrada. En la consola de la placa sale Controls: no GPIO buttons for this board in Game > Controls, so no input, o un aviso parecido si el mando está encendido.
Es así porque en el ESP32, el ESP32-S3 y el ESP32-P4 Input.map solo admite un GPIO: con el nombre de una tecla, el juego se pararía al arrancar. El ESP32-S31 sí lee teclas, de un teclado USB: si ningún control tiene pin en él y el mando está apagado, usa las teclas de Windows.
Si el destino del Build (Target) es una placa y ningún control responde en ella, el panel de problemas lo avisa.
Lo que se guarda
- La pestaña Room, en el
.scnde la sala, en la carpeta Scenes. - La pestaña Game y la ventana Game controls, en
Scenes/Game.json. Solo se escribe lo que tiene valor: el mando, si está encendido; el ritmo, si no es 0; y los pines y botones de cada control, si los tiene.
{
"version" : 1,
"variables" : [
{ "name" : "score", "type" : "int", "value" : "0" },
{ "name" : "lives", "type" : "int", "value" : "3" },
{ "name" : "health", "type" : "int", "value" : "3" },
{ "name" : "maxHealth", "type" : "int", "value" : "3" },
{ "name" : "monedas", "type" : "int", "value" : "0" }
],
"gamepad" : { "enable" : true, "type" : "seesaw", "address" : 80, "deadZone" : 200, "openBus" : false },
"fps" : 30,
"controls" : [
{ "name" : "left", "id" : 0, "key" : "LEFT", "gpioEsp32" : 39, "pad" : "joyLeft" },
{ "name" : "jump", "id" : 4, "key" : "SPACE", "gpioEsp32" : 37, "pad" : "A" }
]
}
Con el código
| En el editor | En tu código |
|---|---|
| Una variable de la sala | room.vars.nombre |
| Una variable del juego | room.game.nombre, o sceneGame.nombre |
| Empezar una partida nueva | SceneGameReset() |
| Los controles | SceneInputMap() una vez; después, Input.pressed(número) |
| La cámara que sigue a un objeto | <Sala>FollowCamera(room), una vez |
| La física, la cámara y los sprites de la sala | room.scene, un Scene |
Dónde va cada llamada y qué más genera cada sala: El código que genera.
Problemas conocidos
- La sala tiene dos nombres. Name da el nombre de su
.gen.aruy de sus funciones, y es el que pide Ask for another room con (this room). El nombre del fichero.scnes el que ofrece Ask for another room para las demás salas, el que buscaSceneLoady el que sigue el Play al cambiar de sala. Si cambias uno, el otro no le sigue: el.gen.arucon el nombre viejo se queda enCode, y el juego lo sigue compilando. Deja Name igual que el nombre del fichero; si cambias los dos, quita el.gen.aruviejo. - Un
Game.jsonque no se puede leer (editado a mano, o con un conflicto de git) deja la pestaña Game en solo lectura. El Build genera entonces el juego sin sus controles ni las variables que hayas creado, y no avisa: compila y no responde a nada. Si la pestaña diceRead only, arregla el fichero o recupéralo. - Cada pulso de las flechas de Rate (fps) es un paso de deshacer. Subirlo de 0 a 60 con la flecha llena el historial del juego. Escribe el número en el campo.
- Defaults no pregunta: cambia los controles por los cinco de serie y borra sus pines y sus botones del mando. Si lo pulsas sin querer,
Ctrl+Z. - Un nombre que empieza por
_lo pierde en el código. Una variable del juego_liveschoca conlives, y el código generado no compila. No empieces por_los nombres de las variables.