Pruebas con el bot
El guion del bot (pruebas/bot.json): pasos, condiciones, señales, enrutador, varios guiones, y qué exige greengames probar para dar una partida por aprobada.
Corresponde aFormato 1, API 1 Para quien escribe código
En esta página
Un juego no está probado hasta que alguien lo juega de principio a fin. En Green Games ese alguien puede ser un bot: maneja a un jugador con las mismas entradas que una persona (una dirección y tres botones) y sigue un guion que escribes tú. El guion es la lista de pasos para jugar la partida completa hasta el final.
El guion vive en pruebas/bot.json y viaja dentro del .ggx. Lo usan tres cosas:
greengames probar, que corre la partida sin pantalla y dice si el juego se puede jugar y terminar;- el piloto automático del reproductor (las demostraciones y las capturas);
- los bots que acompañan al jugador cuando elige jugar con bots.
Un guion real#
El de la plantilla de greengames crear (packages/toolkit/plantilla/pruebas/bot.json): recorre las seis monedas del patio, subiendo a la tarima por la cuña.
{
"$schema": "../../../packages/sdk/esquemas/bot.schema.json",
"formato": 1,
"tiempoMaximo": 70,
"esperado": { "resultado": "victoria" },
"pasos": [
{ "ir": [8, 0, -6] },
{ "ir": [7, 0, -2.6] },
{ "ir": [7, 2, 6], "saltar": "no" },
{ "ir": [3.3, 2, 7] },
{ "ir": [-2, 0, 8] },
{ "ir": [-8, 0, 4] },
{ "ir": [-6, 0, -4] },
{ "ir": [0, 0, 0] }
]
}El segundo paso lleva al bot al pie de la cuña y el tercero lo sube sin saltar. El bot va en línea recta: cada cambio de dirección es un paso.
Pasos#
| Paso | Qué hace |
|---|---|
{ "ir": destino } | Camina en línea recta hasta el destino. Ver El paso ir. |
{ "esperar": segundos } | Se queda quieto ese tiempo. |
{ "esperarPieza": id, ... } | Espera hasta que la pieza cumpla todas las condiciones dadas: cerca + radio, con (tiene la etiqueta), sin (no la tiene), giroY: [desde, hasta]. tiempoMax: 30 s. |
{ "pulsar": accion } | Aprieta saltar, accion o accion2 una vez (unos 3 cuadros). |
{ "mirar": destino } | Gira al avatar para que mire a un punto o a "pieza:id". Sirve en primera persona, antes de pulsar, para que jugador.apunta() dé en el blanco. |
{ "elegir": "menu:opcion" } | Espera a que el menú con ese id se abra y elige esa opción. |
{ "esperarHasta": condicion } | Espera, quieto, hasta que se cumpla una condición. tiempoMax: 30 s. |
{ "mantener": accion, "segundos": n } | Mantiene apretado un botón n segundos, o "hasta": condicion. |
{ "repetir": [pasos], ... } | Repite los pasos: "veces": n, "hasta": condicion (se revisa antes de cada vuelta) o "mientras": condicion. Sin ninguno, hasta que la partida termine. |
{ "si": condicion, "entonces": [pasos], "sino": [pasos] } | Elige una rama. sino es opcional. |
{ "esperarFin": true } | Se queda quieto hasta que la partida termine sola (hasta tiempoMaximo). |
Un guion admite hasta 500 pasos.
El paso ir#
El destino puede ser:
| Destino | Ejemplo | A dónde va |
|---|---|---|
| Un punto | [0, 0, 9] | A esas coordenadas. La y es la altura de los pies. |
| Una pieza | "pieza:movil-1" | A su cara superior. Si la pieza se mueve, la sigue. |
| Una zona | "zona:meta" | Al centro de la zona. |
| Una aparición | "aparicion:control-1" | A ese punto de aparición. |
Opciones:
| Opción | Por defecto | Qué hace |
|---|---|---|
saltar | "auto" | "auto": salta ante un borde, un escalón o un atasco. "no": nunca. "si": salta apenas pueda. |
tolerancia | 0,6 | Distancia horizontal para dar el destino por alcanzado. |
tiempoMax | 15 s | Segundos antes de declarar al bot atascado en este paso. |
control | false | Marca el paso como punto de retorno. Ver Comportamientos que conviene conocer. |
ruta | false | true: en vez de ir en línea recta, busca un camino. Ver El enrutador. |
hasta | Una condición: el paso también termina cuando se cumple ("sigue a la pieza X hasta que tenga la etiqueta Y"). | |
siTeletransportan | "control" | Qué hacer si el juego teletransporta al jugador durante el paso. "control": volver al paso de control más cercano. "siguiente": dar el paso por terminado. "seguir": continuar hacia el destino. |
Escaleras. En un mapa de baldosas, si el destino de un ir queda más arriba o más abajo y el bot está tocando una escalera, la usa. Se le lleva en dos pasos: primero al pie de la escalera y después al punto de arriba, por ejemplo { "ir": [28.5, 0, 0] } y { "ir": [28.5, 5, 0] }.
Esperar el momento justo#
Los peligros con ritmo (plataformas, barreras, luces) no se cruzan caminando sin mirar. El guion espera a que una pieza esté donde conviene. Tres tramos del guion de Circuito Luz Verde (games/circuito-luz-verde/pruebas/bot.json):
{ "esperarPieza": "movil-1", "cerca": [0, -0.3, 32.7], "radio": 0.4 },
{ "ir": "pieza:movil-1" },
{ "esperarPieza": "movil-1", "cerca": [0, -0.3, 38.3], "radio": 0.4 },
{ "ir": [0, 0, 41.9] },Espera a que la plataforma móvil esté en su extremo cercano, se sube, espera a que llegue al otro extremo y baja.
{ "esperarPieza": "brazo", "giroY": [115, 150] },
{ "ir": [3, 4, 61.5] },Espera a que el brazo de la barredora esté en un ángulo que deja libre el paso.
{ "esperarPieza": "semaforo-corredor", "con": "recien-verde" },
{ "ir": [0, 4, 84.2] },Espera a que el semáforo tenga la etiqueta recien-verde. Esa etiqueta la pone el script del juego justo para esto, durante 0,3 segundos cada vez que la luz cambia a verde. Es la regla general: cuando el bot necesita saber algo que no se ve en la posición de una pieza, el script se lo dice con una etiqueta o con una señal.
Condiciones#
Una condición es un objeto. Se cumple si se cumplen todas sus claves.
| Condición | Se cumple cuando |
|---|---|
{ "pieza": "puerta" } | La pieza existe. Con "existe": false, cuando no existe. |
{ "pieza": "puerta", "con": "abierta" } | La pieza tiene esa etiqueta. También sin, cerca + radio y giroY. |
{ "pieza": "torre", "dato": { "clave": "vida", "menor": 20 } } | Un valor de pieza.datos cumple es, mayor o menor. |
{ "senal": "ronda", "es": 3 } | El script dejó esa señal con ese valor. También mayor y menor. |
{ "senal": "puerta-abierta" } | La señal existe y no es false, 0 ni ''. |
{ "jugador": { "enZona": "meta" } } | El jugador del bot cumple eso. También enSuelo, congelado, sobre (id de pieza), cerca + radio, puntosMin, puntosMax. |
{ "escena": "sotano" } | Esa es la escena cargada. |
{ "menu": "inicio" } | Hay un menú abierto con ese id. |
{ "tiempo": 30 } | Pasaron al menos esos segundos de partida. |
{ "todas": [c1, c2] }, { "alguna": [c1, c2] }, { "no": c } | Combinaciones. |
Señales#
juego.senalar(nombre, valor) es la forma de que el guion sepa en qué momento está el juego sin gastar etiquetas. El script deja la señal y el bot la espera (esperarHasta), repite hasta verla (repetir ... hasta) o decide con ella (si).
Este ejemplo está probado con greengames probar sobre una copia de patio-de-monedas, el juego de ejemplo hecho con el editor. Al script se le agregan cuatro líneas, fuera del bloque de reglas:
// Fuera del bloque de reglas: una señal para el guion del bot cuando alguien ya tiene las cinco monedas.
juego.cadaCuadro(() => {
if (jugadores.todos().some((jugador) => jugador.puntos >= 5)) juego.senalar('todas-las-monedas');
});y el guion junta las cinco monedas con el enrutador, espera la señal y recién entonces va a la meta:
{
"formato": 1,
"tiempoMaximo": 110,
"esperado": { "resultado": "victoria", "puntajeMinimo": 5 },
"pasos": [
{ "ir": "pieza:moneda", "ruta": true },
{ "ir": "pieza:moneda-2", "ruta": true },
{ "ir": "pieza:moneda-4", "ruta": true },
{ "ir": "pieza:moneda-3", "ruta": true },
{ "ir": "pieza:moneda-5", "ruta": true },
{ "esperarHasta": { "senal": "todas-las-monedas" }, "tiempoMax": 5 },
{ "ir": "zona:meta", "ruta": true },
{ "esperarFin": true }
]
}Con ese guion, las seis corridas (tres dificultades, dos semillas) terminan en victoria con 5 puntos.
El enrutador#
Con "ruta": true, el bot busca un camino sobre una rejilla de medio metro, midiendo el suelo con rayos. Rodea muros y huecos, sube escalones de hasta 0,45 y baja desniveles de hasta 1,2. Vuelve a calcular cada dos segundos y cuando se atasca, así que sigue a un destino que se mueve.
Sirve para escenarios de un nivel: patios, laberintos, arenas. Sus límites:
- No entiende techos ni pisos superpuestos. Mide el suelo desde arriba: bajo un puente ve el puente.
- Necesita pasillos de al menos 1,5 de ancho.
- No planea saltos. Para saltos y plataformas se siguen dando pasos
ira mano, uno por tramo. Vale también en la vistalateral: en un nivel de plataformas 2D el bot cruza huecos y sube a cada plataforma con unirpor tramo. - No sabe qué piezas son peligrosas. Rodea lo que estorba, no lo que quita puntos. En el ejemplo de arriba, el orden de las monedas está elegido para que ningún tramo cruce la losa de lava del centro; con otro orden, el bot la pisa, el juego lo devuelve al inicio y la prueba falla.
Varios guiones#
Además de pruebas/bot.json (el principal) puede haber pruebas/bot-<nombre>.json. El uso típico es probar que se puede perder. El juego Semáforo trae pruebas/bot-derrota.json, que empieza así:
{
"$schema": "../../../packages/sdk/esquemas/bot.schema.json",
"formato": 1,
"tiempoMaximo": 420,
"esperado": {
"resultado": "derrota"
},greengames probar corre el principal y los adicionales que declaran esperado. Con --guion <nombre> eliges cuáles. Todos van dentro del .ggx.
Para un juego de varios jugadores, greengames probar <slug> --jugadores 4 pone cuatro jugadores en la sala, todos siguiendo el guion.
Campos del guion#
| Campo | Por defecto | Qué hace |
|---|---|---|
formato | Siempre 1. | |
pasos | La lista de pasos. Obligatoria. | |
esperado | Cómo debe terminar la partida: resultado (victoria, derrota o fin), puntajeMinimo, puntajeMaximo. | |
esperadoPorDificultad | Lo esperado en una dificultad, que reemplaza a esperado en ella: { "dificil": { "resultado": "derrota" } }. | |
semillas | [1, 2] | Con qué semillas probar: una lista, o un número N (semillas 1 a N). |
aprobarCon | todas | Cuántas corridas de cada dificultad deben aprobar. |
tiempoMaximo | 180 | Segundos de partida antes de dar la corrida por fallida. |
porDificultad | Pasos distintos para una dificultad, que reemplazan a pasos en ella. |
Para un juego con mucho azar, donde ni un buen guion gana siempre, dilo en el guion. Copa de Bloques (games/copa-de-bloques/pruebas/bot.json) prueba ocho semillas y pide que aprueben cuatro, con un puntaje mínimo:
{
"$schema": "../../../packages/sdk/esquemas/bot.schema.json",
"formato": 1,
"tiempoMaximo": 900,
"semillas": 8,
"aprobarCon": 4,
"esperado": {
"resultado": "victoria",
"puntajeMinimo": 1000
},Qué exige greengames probar#
greengames probar empaqueta el juego a .ggx y lo vuelve a abrir antes de correr: se prueba lo mismo que se publica. Después juega la partida sin pantalla en cada dificultad y con cada semilla (por defecto, la 1 y la 2). Una corrida se aprueba si:
- la partida llega a
juego.terminardentro detiempoMaximo; - el resultado y el puntaje coinciden con
esperado; - ningún evento del script lanza errores;
- no se excede ningún límite (tiempo de script, cambios por cuadro, sonidos);
- el bot no se atasca. Si se atasca, el informe dice en qué paso y en qué coordenadas quedó.
Además, una vez por juego, la primera corrida se repite con la misma semilla y debe dar exactamente lo mismo. Si no, la prueba falla con "el juego no es reproducible": ver Determinismo.
La prueba completa se aprueba cuando, en cada dificultad, aprueban todas las corridas, o las que pide aprobarCon, y ninguna tuvo errores del juego ni límites excedidos. Esos dos nunca se perdonan, pida lo que pida aprobarCon.
Las salidas reales de una prueba aprobada y de una fallida están en La herramienta greengames.
Comportamientos que conviene conocer#
- El bot va en línea recta salvo con
ruta: true. - Funciona igual en todas las vistas. Decide en coordenadas del mundo. En
lateral, sus destinos deben estar sobre el plano. - Las monedas no lo traban. Si el destino de un
ires una pieza que desaparece al tocarla, el paso se da por cumplido. - Un muro bajo no lo detiene. Un muro de menos de 3 unidades no para a un avatar que salta (2,6 de salto más 0,45 de escalón). Si quieres que no salte,
"saltar": "no". - Puntos de control.
control: truemarca un pasoircomo punto de retorno: si el juego hace reaparecer al jugador, el bot retoma desde el paso de control más cercano a donde quedó, dentro del mismo tramo del guion. Después de un cambio de escena no vuelve atrás: sigue con el paso en curso. - Congelado no cuenta. Mientras el juego tiene congelado al jugador, el tiempo de un paso
irno corre. - Cuando se le acaban los pasos, espera 10 segundos. Si el bot agota sus pasos, o se atasca, la prueba espera 10 segundos de partida y corta. Si tu juego termina solo más tarde (por tiempo), el último paso debe ser
{ "esperarFin": true }. pulsares corto. Dura unos 3 cuadros; para mantener apretado usamantener.- Los bots de relleno que acompañan al jugador siguen el guion principal, con pausas al azar.
- Pantalla del bot. Para el script, la pantalla de un bot mide 1280 x 720 y no es táctil.
Si el juego no trae guion#
greengames probar no corre sin pruebas/bot.json: dice que falta y termina con error. El SDK trae guionBasico(paquete), que arma un guion mínimo para un juego sin guion: busca en la escena inicial una zona con id o etiqueta meta, final o llegada y va hasta ella con ruta. Es un punto de partida, no una prueba del juego completo. El editor lo usa al probar y al exportar un juego escrito a mano que no trae guion.
Sigue con#
- La herramienta greengames: opciones de
probary cómo leer su salida. - Caso de estudio: el guion completo de Circuito Luz Verde, paso por paso.
- El bot de prueba en el editor: la misma prueba, sin escribir el archivo.