Good practices and quality checklist
What is worth doing when you make a game, the quality checklist with boxes to tick, and the table of common errors with their cause and their fix.
DescribesFormat 1, API 1 For those who write code
On this page
A game that passes the validator can still be confusing, unfair or impossible to play on a phone. This page gathers what the Green Games author's guide asks for beyond "having no errors".
Before you write#
Decide the game in one sentence: what the player does, how they win, how they lose and which number measures how well they did.
Cross the circuit to the goal; you win by arriving, you lose if time runs out; the score is the time.
If you cannot write that sentence, the game is not decided yet. Everything else (the scene, the script, the bot script, the score table) comes from it.
When you build the scene#
- Start with the floor and the spawn points. The
posicionof a piece is its center; that of a spawn point is the avatar's feet. - Design with the avatar's measurements: gaps of up to 4 units, steps of up to 0.45 without jumping, jumps of up to 2.6 high.
- Tags for everything that repeats (
moneda,peligro,control); anidonly for what the script or the bot names one by one. - What changes with the difficulty goes in the scene, with
dificultadeson the piece or the zone. - What always moves the same way goes in the scene, with
movimiento. What depends on the game, from the script. - Named colors only. For dangers,
{ "color": "coral", "acabado": "neon" }: it is understood with no explanation. - If the game is 2D, the level is a tile map, not piece by piece, and the drawings are sprites. Use the same
zinvista.plano, in the map'sorigenand in loose pieces. See Tile maps.
When you write the script#
- Register everything inside
juego.alIniciar. - Per-player state in
jugador.datos; match state in variables of the file. Do not write with "the player" in mind: there may be bots and several people on the same computer. See Several players. - Texts always with
interfaz.t('clave', { variables }), with the key in both languages of the manifest. - Time with
relojandinterfaz.cronometro; randomness withazar. NosetTimeout,DateorMath.random. - To move a piece, assign a new vector (
pieza.posicion = [x, y, z]) or usepieza.moverA(...). - Always finish:
juego.terminar({ resultado, puntaje, tabla }). - Think of the small screen. On phones, long texts get cut off: use
jugador.pantalla.verticalto pick a short text, messages withtamano: 'chico'for secondary things andcola: trueso they do not pile up.
When you write the bot script#
- The bot must be able to win on every difficulty.
- In a single-level setting (a yard, a maze, an arena), use
{ "ir": "zona:meta", "ruta": true }: it goes around walls and gaps by itself. - One
irstep per stretch when there are jumps and platforms: withoutruta, the bot goes in a straight line. - Leave signals from the script (
juego.senalar('ronda', 2)) so the bot script knows what moment the game is in. - For dangers with a rhythm, have the script give notice: tag a piece when it is safe to pass and wait with
{ "esperarPieza": "id", "con": "libre" }. - Also test that you can lose, if the game can be lost:
pruebas/bot-derrota.jsonwith"esperado": { "resultado": "derrota" }.
Before you share the game#
- Test it where it will be played: import the
.ggxinto the launcher and play a whole match. See Import a .ggx. - If it is for several players, test it with several:
greengames probar <slug> --jugadores 4, and a real match with two people on the same computer.
Quality checklist#
This is the list used to decide whether a game enters the Green Games catalog. It works just as well for a game you are going to share as a file. gb is the greengames tool.
- It is understood in 10 seconds. At the start, a message or the level itself says what to do. The description in the manifest explains it in one or two sentences.
- It has a goal, a score and an ending. It can be won; if it can be lost, that ends too. It always reaches
juego.terminarwith apuntajeand a table declared inpuntajes. - Three difficulties (
facil,normal,dificil) that change something real: time, speed of the dangers, aids. - Spanish and English in the name, description, actions, difficulties, tables and all the
textos. With accents. No text written directly in the script. - It works with keyboard, touch and gamepad. It uses only movement, camera and the declared actions (
saltar,accion,accion2). Nothing demands precision that a touch stick cannot give. - It passes
gb validarwith no errors and with the warnings reviewed. - It passes
gb probaron all three difficulties (the bot wins). - It looks good on the catalog cover:
recursos/portada.svgin 16:9, your own, with no third-party brands or characters. - It is fair: dangers can be seen coming (coral color, alert sound), there are checkpoints if the course is long, and falling into the void returns you to the last checkpoint.
- It uses sound for what matters (collecting, a hit, the ending) and does not overdo it.
- It does not make up data: the author is real, and there are no fake records, users or figures.
- It performs: less than 1 ms of script per frame in
gb probarand fewer than 600 pieces if possible.
The two numbers of the last item appear on every line of greengames probar: script 0.022 ms/cuadro and 12 piezas. See Performance.
Common errors#
The quoted messages are the ones the tools print, in Spanish.
| Symptom | Cause and fix |
|---|---|
| The player appears and falls into the void | The spawn point is not over a solid piece. Its posicion is the feet: set y equal to the top face of the platform. |
| "falta la propiedad obligatoria tamano" | Keys carry no accents and no ñ: tamano, posicion, rotacion, cuna. |
A piece does not move when you change posicion[0] | Reading posicion gives a copy. Assign a new vector: p.posicion = [x, y, z]. |
| The touch does not fire | The piece has fisica: "ninguna". For something you pass through but that still reports, use solida: false. |
| The text comes out as the key | The key is not in textos for that language. gb validar detects it if you use interfaz.t('literal'). |
| The bot "no llegó al destino" | There is an obstacle in the straight line, the gap is too long or the destination is at another height. Add intermediate steps. |
| "el juego no es reproducible" | You use Math.random, Date or depend on the order of an object. Use azar and reloj. See Determinism. |
| A wedge cannot be climbed | The slope is over 50 degrees: lengthen the piece or lower it. |
interfaz.t(...) + ' algo' shows [object Object] | t returns a translatable object. Put the whole text in the template, with variables; a variable can be another interfaz.t(...). |
| The bot wins with one seed and loses with another | The game has randomness. Improve the bot script (signals, repetir ... hasta) or declare "semillas" and "aprobarCon". |
| "el bot completó sus pasos y la partida no había terminado" | The game ends by itself later: add { "esperarFin": true } at the end of the bot script. Or the call to juego.terminar is missing. |
| A ball does not bounce | Give the dynamic piece "rebote": 0.8 (and a low "friccion"). |
| The record shows up on a defeat | It does not happen: a defeat does not enter the table. To record anyway, finish with resultado: 'fin'. |
| The game works in the portal and not in an old launcher | Launchers 0.1.0 and 0.2.0 ship an earlier engine. Update to launcher 0.4.0. See Before you share the game. |
Next#
- Case study: a game that meets the checklist, read from the inside.
- The validator: what each error code means.
- Game card and export: the same review, from the editor.