The mundo service
Reference for the mundo service. What is in the scene: pieces, zones, spawn points, lights and tile maps, plus the touch, enter and collide events.
DescribesFormato 1, API 1 For those who write code This page is generated from the SDK sources.
On this page
- Functions and properties of mundo
- mundo.pieza
- mundo.existe
- mundo.piezas
- mundo.crear
- mundo.eliminar
- mundo.zona
- mundo.zonas
- mundo.aparicion
- mundo.apariciones
- mundo.alTocar
- mundo.alDejarDeTocar
- mundo.alEntrar
- mundo.alSalir
- mundo.rayo
- mundo.mientrasToca
- mundo.alChocar
- mundo.piezasEn
- mundo.jugadoresEn
- mundo.grupo
- mundo.crearZona
- mundo.mapa
- mundo.mapas
- mundo.luz
- mundo.luces
- mundo.crearLuz
- mundo.ambiente
- mundo.modelo
- mundo.modelos
- mundo.crearModelo
- Pieza
- pieza.tiene
- pieza.etiquetar
- pieza.desetiquetar
- pieza.moverA
- pieza.girar
- pieza.detener
- pieza.impulsar
- pieza.alTocar
- pieza.eliminar
- pieza.reproducir
- pieza.pararAnimacion
- pieza.alTerminarClip
- Grupo
- grupo.piezas
- grupo.mover
- grupo.moverA
- grupo.girarY
- grupo.detener
- grupo.etiquetar
- grupo.desetiquetar
- grupo.eliminar
- Luz
- luz.eliminar
- Zona
- zona.tiene
- zona.jugadores
- zona.actores
- zona.eliminar
- Mapa
- mapa.leer
- mapa.poner
- mapa.celdaEn
- mapa.centro
- mapa.buscar
- mapa.colision
- Terreno
- terreno.bloques
- terreno.biomas
- terreno.info
- terreno.bloque
- terreno.poner
- terreno.romper
- terreno.llenar
- terreno.altura
- terreno.suelo
- terreno.bioma
- terreno.clima
- terreno.buscarBioma
- terreno.buscarBloque
- terreno.rayo
- terreno.ruido
- terreno.alRomper
- terreno.alPoner
- terreno.alGenerar
- terreno.guardar
- terreno.restaurar
- terreno.borrarGuardado
- terreno.regenerar
- Behavior notes
- How to use the terrain
- Complete examples
- mundo: touching pieces by tag and by id
- mundo: creating pieces from the script
- mundo: moving pieces
- mundo: zones
- mundo: ray
- mundo: groups, queries, collisions, staying in touch
- mundo: lights, environment and zones created by the script
- Next
What is in the scene: pieces, zones, spawn points, lights and tile maps, plus the touch, enter and collide events.
The types used in the signatures (Vec3, Texto, the selector) are in the API reference.
Functions and properties of mundo#
| Property | Type | Description |
|---|---|---|
mundo.gravedad | number | Vertical acceleration (negative is down). |
mundo.terreno | Terreno | The cube terrain of the scene (open world). It always exists: in a scene without terreno, activo is false and its methods fail with a clear message. Added in version 1.1. |
mundo.pieza#
mundo.pieza(id: string): PiezaThe piece with that id. Fails with a clear message if it does not exist (use mundo.existe to ask first).
From docs/EJEMPLOS.md, «interfaz: rótulos, barras y números en el mundo»:
const torre = mundo.pieza('torre');mundo.existe#
mundo.existe(id: string): booleanTells whether a piece with that id exists.
From games/isla-taller/scripts/principal.ts:
if (!mundo.existe(`pad-${o.id}`)) continue;mundo.piezas#
mundo.piezas(etiqueta?: string): Pieza[]Every piece with that tag (without the hash sign). With no argument, every piece.
From docs/EJEMPLOS.md, «azar»:
const losas = azar.mezclar(mundo.piezas('losa'));mundo.crear#
mundo.crear(def: PiezaDef): PiezaCreates a new piece. Same format as in the scene file.
From docs/EJEMPLOS.md, «mundo: crear piezas desde el script»:
const moneda = mundo.crear({
forma: 'cilindro',
posicion: [azar.entre(-10, 10), 1, azar.entre(-10, 10)],
rotacion: [90, 0, 0],
tamano: [0.9, 0.16, 0.9],
material: { color: 'ambar', acabado: 'brillante' },
solida: false,
etiquetas: ['moneda']
});mundo.eliminar#
mundo.eliminar(pieza: Pieza | string): voidRemoves a piece. Takes the piece or its id.
From games/isla-taller/scripts/principal.ts:
function quitarFugaz(cristal: Pieza): void {
const haz = cristal.datos.haz as string;
if (mundo.existe(haz)) mundo.eliminar(haz);
cristal.eliminar();
}mundo.zona#
mundo.zona(id: string): ZonaThe zone with that id.
From games/isla-taller/scripts/principal.ts:
mundo.zona(`zona-${id}`).activa = false;mundo.zonas#
mundo.zonas(etiqueta?: string): Zona[]Every zone with that tag. With no argument, every zone.
mundo.aparicion#
mundo.aparicion(id: string): { id; posicion; rotacionY }The spawn point with that id: its position and the direction it faces.
mundo.apariciones#
mundo.apariciones(): Aparicion[]Every spawn point in the scene.
mundo.alTocar#
mundo.alTocar(selector: Selector, fn: (pieza: Pieza, jugador: Jugador) => void): voidA player starts touching a piece (solid or not).
From docs/EJEMPLOS.md, «jugadores: mover, teletransportar y cambiar habilidades»:
mundo.alTocar('#trampolin', (_p, j) => j.impulsar([0, 20, 0]));mundo.alDejarDeTocar#
mundo.alDejarDeTocar(selector: Selector, fn: (pieza: Pieza, jugador: Jugador) => void): voidA player stops touching a piece.
From docs/EJEMPLOS.md, «mundo: tocar piezas por etiqueta y por id»:
mundo.alDejarDeTocar('#placa', (placa) => (placa.material = 'gris'));mundo.alEntrar#
mundo.alEntrar(selector: Selector, fn: (zona: Zona, jugador: Jugador) => void): voidA player enters a zone.
From docs/EJEMPLOS.md, «juego: cambiar de escena»:
mundo.alEntrar('tesoro', (_zona, j) => juego.terminar({ resultado: 'victoria', puntaje: 1, de: j }));mundo.alSalir#
mundo.alSalir(selector: Selector, fn: (zona: Zona, jugador: Jugador) => void): voidA player leaves a zone.
From docs/EJEMPLOS.md, «mundo: zonas»:
mundo.alSalir('zona-segura', (_zona, j) => interfaz.mensaje(interfaz.t('cuidado'), { para: j, tipo: 'peligro' }));mundo.rayo#
mundo.rayo(origen: Vec3, direccion: Vec3, distanciaMaxima: number): { pieza: Pieza | null; punto: Vec3; distancia: number } | nullCasts a ray against solid pieces. direccion does not need to be normalized.
From docs/EJEMPLOS.md, «mundo: rayo»:
for (const j of jugadores.todos()) {
const p = j.posicion;
const hacia: [number, number, number] = [p[0] - ojo[0], p[1] + 1 - ojo[1], p[2] - ojo[2]];
const distancia = Math.hypot(hacia[0], hacia[1], hacia[2]);
const impacto = mundo.rayo(ojo, hacia, distancia);
j.datos.visto = impacto === null || impacto.distancia > distancia - 0.6;
}mundo.mientrasToca#
mundo.mientrasToca(selector: Selector, fn: (pieza: Pieza, jugador: Jugador, dt: number) => void): voidCalled every frame while a player keeps touching the piece (damage per second, conveyor belts, ice).
From docs/EJEMPLOS.md, «mundo: grupos, consultas, choques, permanencia»:
// Lava: quita vida mientras se pisa. dt siempre vale 1/60.
mundo.mientrasToca('#lava', (_lava, j, dt) => { j.datos.vida = (j.datos.vida as number) - 10 * dt; });mundo.alChocar#
mundo.alChocar(selector: Selector, fn: (pieza: Pieza, otra: Pieza) => void): voidA dynamic piece matching the selector starts touching another piece (the ball hits the goal).
From docs/EJEMPLOS.md, «mundo: grupos, consultas, choques, permanencia»:
// Una pelota (pieza dinamica con "rebote": 0.8) toca el arco.
mundo.alChocar('pelota', (_pelota, otra) => { if (otra.tiene('arco')) juego.registro('gol'); });mundo.piezasEn#
mundo.piezasEn(centro: Vec3, radioOTamano: number | Vec3, etiqueta?: string): Pieza[]Pieces (solid or not) touching a sphere of that radius, or a box of that size, centered at centro.
From docs/EJEMPLOS.md, «mundo: grupos, consultas, choques, permanencia»:
// Explosion: todo lo que haya a 4 unidades con la etiqueta "caja".
mundo.alTocar('bomba', (bomba) => {
for (const caja of mundo.piezasEn(bomba.posicion, 4, 'caja')) caja.impulsar([0, 12, 0]);
bomba.eliminar();
});mundo.jugadoresEn#
mundo.jugadoresEn(centro: Vec3, radio: number): Jugador[]Players whose body is closer than radio to the point.
mundo.grupo#
mundo.grupo(nombre: string): GrupoThe group of pieces with that name (the grupo property of the pieces).
From docs/EJEMPLOS.md, «mundo: grupos, consultas, choques, permanencia»:
// Las piezas con "grupo": "puerta" en la escena se mueven juntas.
const puerta = mundo.grupo('puerta');mundo.crearZona#
mundo.crearZona(def: ZonaDef): ZonaCreates a new zone. Same format as in the scene file.
From docs/EJEMPLOS.md, «mundo: luces, ambiente y zonas creadas por el script»:
// Una zona de premio que aparece en un lugar nuevo cada vez.
const zona = mundo.crearZona({ id: 'premio', forma: 'esfera', posicion: [5, 1, 5], tamano: [3, 3, 3], datos: { puntos: 5 } });mundo.mapa#
mundo.mapa(id: string): MapaA tile map of the current scene. Fails if it does not exist.
From docs/EJEMPLOS.md, «Láminas y mapas de baldosas (2D)»:
// Abre un paso: borra tres baldosas del piso.
const nivel = mundo.mapa('nivel');mundo.mapas#
mundo.mapas(): Mapa[]The tile maps of the current scene.
From docs/CONTRATO.md, «Tile maps»:
mundo.mapas();mundo.luz#
mundo.luz(id: string): LuzThe light with that id (declared in the scene or created with mundo.crearLuz).
mundo.luces#
mundo.luces(): Luz[]Every light the script can change.
From docs/EJEMPLOS.md, «mundo: luces, ambiente y zonas creadas por el script»:
// Anochece en 20 segundos y se encienden los faroles (luces con "id" en la escena).
reloj.despues(30, () => {
mundo.ambiente({ cielo: 'noche', luzAmbiente: 0.25, sol: { intensidad: 0.1 }, niebla: { desde: 10, hasta: 60 } }, 20);
for (const luz of mundo.luces()) luz.encendida = true;
sonido.ruido({ duracion: 3, filtro: 600, volumen: 0.4, ataque: 1 });
});mundo.crearLuz#
mundo.crearLuz(def: LuzDef): LuzCreates a point light. At most 8 can exist at once.
From docs/EJEMPLOS.md, «mundo: luces, ambiente y zonas creadas por el script»:
const faro = mundo.crearLuz({ id: 'faro', posicion: [0, 8, 0], color: 'ambar', intensidad: 3, alcance: 30 });mundo.ambiente#
mundo.ambiente(cambios: { cielo?, luzAmbiente?, sol?, niebla? }, duracion?: number): void // day and night, stormsChanges the environment while playing: sky, ambient light, sun and fog. Only what you pass. duracion, in seconds, makes it gradual.
From docs/EJEMPLOS.md, «mundo: luces, ambiente y zonas creadas por el script»:
// Anochece en 20 segundos y se encienden los faroles (luces con "id" en la escena).
reloj.despues(30, () => {
mundo.ambiente({ cielo: 'noche', luzAmbiente: 0.25, sol: { intensidad: 0.1 }, niebla: { desde: 10, hasta: 60 } }, 20);
for (const luz of mundo.luces()) luz.encendida = true;
sonido.ruido({ duracion: 3, filtro: 600, volumen: 0.4, ataque: 1 });
});mundo.modelo#
mundo.modelo(id: string): ModeloDelJuegoData of a model in the game (modelos/<id>.glb). Fails with a clear message if it does not exist.
From docs/CONTRATO.md, «Models, textures and sounds (version 1.2)»:
mundo.modelo('robot'); // { id, tamano, clips: [{ nombre, duracion }], triangulos }mundo.modelos#
mundo.modelos(): string[]Ids of the models in the game.
From docs/CONTRATO.md, «Models, textures and sounds (version 1.2)»:
mundo.modelos(); // ids de los modelos del juegomundo.crearModelo#
mundo.crearModelo(modelo: string, def: ModeloEnMundo): PiezaCreates a piece with shape 'modelo' at its natural size (times escala). A shortcut for crear so you do not have to work out tamano.
From docs/CONTRATO.md, «Models, textures and sounds (version 1.2)»:
const robot = mundo.crearModelo('robot', { id: 'r1', posicion: [0, 0.9, 5], escala: 1 }); // pieza a tamaño naturalPieza#
A piece in the world: one declared by the scene or one created with mundo.crear.
| Property | Type | Description |
|---|---|---|
pieza.id | string | Read-only. Id of the piece. |
pieza.forma | Forma | Read-only. Shape of the piece. |
pieza.fisica | Fisica | Read-only. How it takes part in physics: 'fija' (fixed), 'dinamica' (dynamic) or 'ninguna' (none). |
pieza.existe | boolean | Read-only. false once the piece has been removed. Using a removed piece does not fail, but does nothing. |
pieza.posicion | Vec3 | Center of the piece. Reading it gives a copy; to move the piece, assign a new vector. |
pieza.rotacion | Vec3 | Degrees. |
pieza.tamano | Vec3 | Width (X), height (Y) and length (Z). |
pieza.material | MaterialDef | The name of a palette color, or an object with color, finish and pattern. |
pieza.visible | boolean | false: it is not drawn. |
pieza.solida | boolean | false: players walk through it, but it still reports touches. |
pieza.velocidad | Vec3 | Dynamic pieces only. |
pieza.etiquetas | readonly string[] | Read-only. The tags of the piece. Change them with etiquetar and desetiquetar. |
pieza.datos | Record<string, unknown> | Free data for the script. Starts with the datos declared in the scene. |
pieza.grupo | string | Read-only. Name of the group it belongs to, or ''. |
pieza.rebote | number | How much it bounces (0 to 1.5). |
pieza.friccion | number | Friction (0 to 2). |
pieza.opacidad | number | From 0, invisible, to 1, opaque. |
pieza.emision | number | From 0 to 1: its own glow. |
pieza.velocidadDeGiro | Vec3 | Dynamic pieces only: spin speed in degrees per second. |
pieza.lamina | string | Sprite pieces only: id of the sprite it shows ('' on every other piece). It can be changed to another sprite of the package. |
pieza.animacion | string | number | null | Sprite pieces only: the animation (a name) or fixed frame (a number) it shows. null: the first animation. Assigning it restarts the animation. |
pieza.espejo | boolean | Sprite pieces only: drawn mirrored horizontally. |
pieza.modelo | string | Read-only. Models only: id of the model it shows ('' on other pieces). |
pieza.clips | readonly string[] | Read-only. Models only: names of the model’s clips (empty on other pieces). |
pieza.tiene#
pieza.tiene(etiqueta: string): booleanTells whether the piece has that tag.
From docs/EJEMPLOS.md, «mundo: grupos, consultas, choques, permanencia»:
// Una pelota (pieza dinamica con "rebote": 0.8) toca el arco.
mundo.alChocar('pelota', (_pelota, otra) => { if (otra.tiene('arco')) juego.registro('gol'); });pieza.etiquetar#
pieza.etiquetar(etiqueta: string): voidAdds a tag. Events with a '#tag' selector take it into account from then on.
From docs/EJEMPLOS.md, «azar»:
for (const trampa of losas.slice(0, 3)) trampa.etiquetar('peligro'); // tres trampas distintas cada partidapieza.desetiquetar#
pieza.desetiquetar(etiqueta: string): voidRemoves a tag.
From games/circuito-luz-verde/scripts/principal.ts:
const semaforo = mundo.pieza('semaforo-corredor');
// ...
reloj.despues(0.3, () => semaforo.desetiquetar('recien-verde'));pieza.moverA#
pieza.moverA(destino: Vec3, opciones: { duracion: number; suavizado?: 'lineal' | 'suave'; vaiven?: boolean; espera?: number; alLlegar?: () => void }): voidMoves the piece smoothly to destino. Replaces any previous movement.
From docs/EJEMPLOS.md, «mundo: mover piezas»:
// Ida y vuelta para siempre.
mundo.pieza('plataforma').moverA([0, 0, 20], { duracion: 3, vaiven: true, espera: 0.5 });pieza.girar#
pieza.girar(gradosPorSegundo: Vec3): voidSpins forever at gradosPorSegundo on each axis. [0, 0, 0] stops the spin.
From docs/EJEMPLOS.md, «mundo: crear piezas desde el script»:
for (let i = 0; i < 12; i++) {
const moneda = mundo.crear({
forma: 'cilindro',
posicion: [azar.entre(-10, 10), 1, azar.entre(-10, 10)],
rotacion: [90, 0, 0],
tamano: [0.9, 0.16, 0.9],
material: { color: 'ambar', acabado: 'brillante' },
solida: false,
etiquetas: ['moneda']
});
moneda.girar([0, 160, 0]);
}pieza.detener#
pieza.detener(): voidStops moverA and girar.
From games/copa-de-bloques/scripts/principal.ts:
for (const p of publico) {
p.pieza.detener();
p.pieza.posicion = p.base;
}pieza.impulsar#
pieza.impulsar(velocidad: Vec3): voidDynamic pieces only: an instant push (a change of velocity).
From docs/EJEMPLOS.md, «mundo: grupos, consultas, choques, permanencia»:
for (const caja of mundo.piezasEn(bomba.posicion, 4, 'caja')) caja.impulsar([0, 12, 0]);pieza.alTocar#
pieza.alTocar(fn: (jugador: Jugador) => void): voidShortcut for mundo.alTocar(pieza.id, ...).
pieza.eliminar#
pieza.eliminar(): voidRemoves the piece from the world. Events registered with pieza.alTocar go with it.
From docs/EJEMPLOS.md, «jugadores: mover, teletransportar y cambiar habilidades»:
mundo.alTocar('#botas', (botas, j) => { botas.eliminar(); j.saltosExtra = 1; j.rapidez = 11; });pieza.reproducir#
pieza.reproducir(clip: string, opciones?: OpcionesClip): voidModels only: plays a clip from the start. Fails with a clear message if the model does not have it. The animation is only drawn: it does not move the piece or change how it collides.
From docs/CONTRATO.md, «Models, textures and sounds (version 1.2)»:
const robot = mundo.crearModelo('robot', { id: 'r1', posicion: [0, 0.9, 5], escala: 1 }); // pieza a tamaño natural
// ...
robot.reproducir('saludar', { repetir: false, mezcla: 0.2, velocidad: 1 }); // desde el principiopieza.pararAnimacion#
pieza.pararAnimacion(mezcla?: number): voidModels only: stops animating and returns to the rest pose, blending for mezcla seconds (0.2 by default).
From docs/CONTRATO.md, «Models, textures and sounds (version 1.2)»:
const robot = mundo.crearModelo('robot', { id: 'r1', posicion: [0, 0.9, 5], escala: 1 }); // pieza a tamaño natural
// ...
robot.pararAnimacion(0.3); // vuelve al reposo mezclando 0,3 spieza.alTerminarClip#
pieza.alTerminarClip(fn: (clip: string) => void): voidModels only: tells you when a clip that does not repeat reaches its end. The moment comes from the clip’s length and the match clock: it is the same on every computer, whatever speed it draws at.
From docs/CONTRATO.md, «Models, textures and sounds (version 1.2)»:
const robot = mundo.crearModelo('robot', { id: 'r1', posicion: [0, 0.9, 5], escala: 1 }); // pieza a tamaño natural
// ...
robot.alTerminarClip((clip) => robot.reproducir('quieto')); // solo clips que no se repitenGrupo#
Several pieces handled together. It is built from the grupo property of each piece. There is no hierarchy: these are batch operations.
| Property | Type | Description |
|---|---|---|
grupo.nombre | string | Read-only. Name of the group. |
grupo.centro | Vec3 | Read-only. Center of the group (the average of the positions). |
grupo.visible | boolean | Applies to every piece in the group. |
grupo.solida | boolean | Applies to every piece in the group. |
grupo.material | MaterialDef | Applies to every piece in the group. |
grupo.piezas#
grupo.piezas(): Pieza[]The live pieces of the group.
grupo.mover#
grupo.mover(delta: Vec3): voidShifts every piece.
grupo.moverA#
grupo.moverA(destino: Vec3, opciones: OpcionesMover): voidMoves the group smoothly until its center is at destino, keeping its shape.
From docs/EJEMPLOS.md, «mundo: grupos, consultas, choques, permanencia»:
// Las piezas con "grupo": "puerta" en la escena se mueven juntas.
const puerta = mundo.grupo('puerta');
// ...
mundo.alTocar('boton', () => puerta.moverA([0, 6, 10], { duracion: 1.5 }));grupo.girarY#
grupo.girarY(grados: number, pivote?: Vec3): void // rotates the whole set around a vertical axisRotates the group by grados around the Y axis through pivote (its center by default).
grupo.detener#
grupo.detener(): voidStops the group's movement.
grupo.etiquetar#
grupo.etiquetar(etiqueta: string): voidAdds the tag to every piece in the group.
grupo.desetiquetar#
grupo.desetiquetar(etiqueta: string): voidRemoves the tag from every piece in the group.
grupo.eliminar#
grupo.eliminar(): voidRemoves every piece in the group.
Luz#
A point light the script can change.
| Property | Type | Description |
|---|---|---|
luz.id | string | Read-only. Id of the light. |
luz.posicion | Vec3 | Where the light is. |
luz.color | string | A palette color. |
luz.intensidad | number | How bright it is, from 0 to 10. |
luz.alcance | number | How far it reaches, in units. |
luz.encendida | boolean | When off it gives no light (it keeps its intensity for when you turn it back on). |
luz.eliminar#
luz.eliminar(): voidRemoves the light from the world.
Zona#
A zone from the scene, or one created with mundo.crearZona: it reports when someone enters or leaves.
| Property | Type | Description |
|---|---|---|
zona.id | string | Read-only. Id of the zone. |
zona.posicion | Vec3 | Read-only. Center of the zone. |
zona.tamano | Vec3 | Read-only. Width (X), height (Y) and length (Z). |
zona.etiquetas | readonly string[] | Read-only. The tags of the zone. |
zona.activa | boolean | A deactivated zone does not report anyone entering or leaving. |
zona.datos | Record<string, unknown> | Free data for the script. Starts with the datos declared in the scene. |
zona.tiene#
zona.tiene(etiqueta: string): booleanTells whether the zone has that tag.
zona.jugadores#
zona.jugadores(): Jugador[]Players inside right now.
From games/circuito-luz-verde/scripts/principal.ts:
jugadores.alAccion('accion', (j) => {
if (ascensorOcupado || !mundo.zona('zona-ascensor').jugadores().includes(j)) return;
subirAscensor();
});zona.actores#
zona.actores(): Actor[]Actors inside right now.
zona.eliminar#
zona.eliminar(): voidRemoves the zone from the world.
From docs/EJEMPLOS.md, «mundo: luces, ambiente y zonas creadas por el script»:
mundo.alEntrar('premio', (z, j) => { j.puntos += z.datos.puntos as number; z.eliminar(); });Mapa#
A tile map of the scene. Columns grow toward +X; rows grow downward ('xy') or toward +Z ('xz').
| Property | Type | Description |
|---|---|---|
mapa.id | string | Read-only. The id of the map in the scene. |
mapa.plano | 'xy' | 'xz' | Read-only. 'xy': a vertical map, the one for the lateral view. 'xz': a ground map, the one for the views from above and for 3D worlds. |
mapa.columnas | number | Read-only. How many columns it has: the length of its longest row. |
mapa.filas | number | Read-only. How many rows it has. |
mapa.celda | number | Read-only. Size of one tile, in units. |
mapa.leer#
mapa.leer(columna: number, fila: number, capa?: number | string): string | nullCharacter of the tile in that cell, or null if it is empty. capa: a number or an id; by default, the first layer that is not a background.
From docs/CONTRATO.md, «Tile maps»:
const nivel = mundo.mapa('nivel'); // falla con un mensaje claro si no existe
// ...
nivel.leer(3, 2); // '=' o null. Tercer parámetro: capa (número o id); por defecto, la primera que no es fondomapa.poner#
mapa.poner(columna: number, fila: number, baldosa: string | null, capa?: number | string): voidChanges a tile (null erases it). Collision and drawing update on their own in the next frame.
From docs/EJEMPLOS.md, «Láminas y mapas de baldosas (2D)»:
mundo.alTocar('#vida', (vida, j) => {
vida.eliminar();
// Abre un paso: borra tres baldosas del piso.
const nivel = mundo.mapa('nivel');
for (let c = 9; c <= 11; c++) nivel.poner(c, 5, null);
sonido.tocar('poder', { para: j });
});mapa.celdaEn#
mapa.celdaEn(punto: Vec3): { columna: number; fila: number }The cell that contains a point of the world (it may fall outside the map).
From docs/CONTRATO.md, «Tile maps»:
const nivel = mundo.mapa('nivel'); // falla con un mensaje claro si no existe
// ...
nivel.celdaEn(jugador.posicion); // { columna, fila }mapa.centro#
mapa.centro(columna: number, fila: number): Vec3Center of a cell in the world. In ground maps ('xz') it lies flush with the floor.
From docs/CONTRATO.md, «Tile maps»:
const nivel = mundo.mapa('nivel'); // falla con un mensaje claro si no existe
// ...
nivel.centro(3, 2); // Vec3 del centro de la celdamapa.buscar#
mapa.buscar(baldosa: string, capa?: number | string): { columna: number; fila: number }[]Every cell that has that tile.
From docs/CONTRATO.md, «Tile maps»:
const nivel = mundo.mapa('nivel'); // falla con un mensaje claro si no existe
// ...
nivel.buscar('^'); // todas las celdas con esa baldosamapa.colision#
mapa.colision(columna: number, fila: number): ColisionBaldosaHow that cell collides, looking at every layer that is not a background. 'ninguna' if it is empty.
From docs/CONTRATO.md, «Tile maps»:
const nivel = mundo.mapa('nivel'); // falla con un mensaje claro si no existe
// ...
nivel.colision(3, 2); // 'plataforma', 'ninguna', ...Terreno#
Cube terrain: a world generated from a seed and from the biome table of the scene. Block coordinates are integers: block [x, y, z] spans x to x+1, y to y+1 and z to z+1. The world is 64 blocks tall (y from 0 to 63). You get it with mundo.terreno.
| Property | Type | Description |
|---|---|---|
terreno.activo | boolean | Read-only. The scene has terrain. |
terreno.semilla | number | Read-only. Seed of the world: the terreno.semilla of the scene or, if it has none, the seed of the match. |
terreno.nivelDelMar | number | Read-only. Sea level: the generator fills with water up to there. |
terreno.alto | number | Read-only. Height of the world in blocks (64). |
terreno.limite | number | Read-only. The world reaches this distance from the origin on X and on Z. |
terreno.cambios | number | Read-only. How many blocks differ today from the generated world. |
terreno.bloques#
terreno.bloques(): string[]Ids of the declared blocks, in order.
terreno.biomas#
terreno.biomas(): string[]Ids of the declared biomes, in order.
terreno.info#
terreno.info(bloque: string): InfoBloqueThe data of a declared block: id, solido, transparente, liquido, dureza, luz, color and etiquetas.
From games/valle-abierto/scripts/comun.ts:
export const terreno = mundo.terreno;
// ...
const info = terreno.info(id);terreno.bloque#
terreno.bloque(x: number, y: number, z: number): stringId of the block in that cell. 'aire' if it is empty or outside the world.
terreno.poner#
terreno.poner(x: number, y: number, z: number, bloque: string, por?: Jugador): booleanPlaces a block ('aire' removes it). Returns false if the cell already had that block or is outside the world. Notifies alPoner.
terreno.romper#
terreno.romper(x: number, y: number, z: number, por?: Jugador): stringRemoves the block from the cell and returns its id ('aire' if there was nothing). Notifies alRomper.
terreno.llenar#
terreno.llenar(desde: Vec3, hasta: Vec3, bloque: string): numberFills the box between two cells (inclusive) with a block. Returns how many changed. Does not notify alPoner or alRomper. Up to 4096 cells.
terreno.altura#
terreno.altura(x: number, z: number): numberHeight of the highest solid block in the column, plus one: where the feet end up. Trees and anything built count.
terreno.suelo#
terreno.suelo(x: number, z: number): numberHeight of the natural ground the generator gives for that column, without trees or changes. It is cheap: useful for far-away places.
terreno.bioma#
terreno.bioma(x: number, z: number): stringId of the biome of that column.
terreno.clima#
terreno.clima(x: number, z: number): { temperatura: number; humedad: number }Climate of that column, from 0 to 1.
terreno.buscarBioma#
terreno.buscarBioma(bioma: string, desde: Vec3, radio?: number): Vec3 | nullThe column of the requested biome closest to desde, or null if there is none within radio (512 by default, up to 2000). Returns the feet: [x + 0.5, ground, z + 0.5].
terreno.buscarBloque#
terreno.buscarBloque(bloque: string, desde: Vec3, radio?: number, alto?: number): Vec3 | nullThe cell closest to desde with that block, within radio horizontally (24 by default, up to 48), or null. With alto, only cells no farther than that vertical distance from desde count (what is within arm's reach). It generates the chunks it checks.
terreno.rayo#
terreno.rayo(origen: Vec3, direccion: Vec3, distancia: number): BloqueApuntado | nullFirst block a ray hits (liquids and air do not count), up to 64 units.
terreno.ruido#
terreno.ruido(x: number, z: number, escala?: number, canal?: number): numberReproducible noise from -1 to 1 at a point of the plane, tied to the seed of the world. escala is the size of its patches in blocks (32 by default); canal gives independent noises.
terreno.alRomper#
terreno.alRomper(fn: (cambio: CambioDeBloque) => void): voidCalled every time romper removes a block, with the position, what was there, what is left and the player who did it, if any.
terreno.alPoner#
terreno.alPoner(fn: (cambio: CambioDeBloque) => void): voidCalled every time poner changes a block, with the same data as alRomper.
terreno.alGenerar#
terreno.alGenerar(fn: (trozo: { x: number; z: number }) => void): voidGeneration hook: called when the room loads a 16 x 16 chunk for the first time (near a player). It receives the corner of the chunk. Whatever the script changes there with poner or llenar stays as part of the world.
terreno.guardar#
terreno.guardar(jugador: Jugador): { bloques: number; bytes: number }Saves the changes of the world (only what differs from the generated one) in the progress of the player. Returns how many blocks and how many bytes it took.
terreno.restaurar#
terreno.restaurar(jugador: Jugador): numberApplies again the changes saved by guardar. Returns how many blocks it restored (0 if there was nothing or the seed is another one).
terreno.borrarGuardado#
terreno.borrarGuardado(jugador: Jugador): voidDeletes the saved changes of that player.
terreno.regenerar#
terreno.regenerar(semilla: number): voidReplaces the world with that of another seed (a "new world"): it forgets the changes and sends the players back to their spawn point.
Behavior notes#
A selector is an id ('meta') or a tag with a hash sign ('#moneda'). Tags are evaluated at the moment of the touch: you can tag and untag pieces while the game runs (pieza.etiquetar('peligro')).
alTocar fires when a player starts touching a piece, solid or not (standing on it counts). rayo only hits solid pieces and ignores players.
Careful: pieza.posicion[0] = 5 moves nothing (it changes a copy). Write pieza.posicion = [5, y, z].
How to use the terrain#
The cube terrain of the scene. It always exists: in a scene without terreno, activo is false and its methods fail with a message that says how to turn it on. Blocks are named by their id ('pasto'); empty space is 'aire'.
Breaking and placing are decided by the script: the engine gives the ray, changes the block and notifies. The skeleton of all building (it is complete in the mundo-abierto template):
juego.cadaCuadro(() => {
for (const j of jugadores.todos()) {
const a = j.apuntaBloque(5);
interfaz.marcarBloque(a ? a.posicion : null, {}, j);
if (a && j.pulsa('primaria')) terreno.romper(a.posicion[0], a.posicion[1], a.posicion[2], j);
}
});
jugadores.alAccion('secundaria', (j) => {
const a = j.apuntaBloque(5);
if (a) terreno.poner(a.vecino[0], a.vecino[1], a.vecino[2], 'tabla', j);
});Worth knowing:
ponerdoes not let you wall anyone in: it returnsfalseif there is a player or an actor in that cell. Someone who only brushes it (up to a fifth of a block) is nudged that little bit.llenardoes not check.- The bottom of the world cannot be touched (
y = 0), nor what lies outsidelimiteor abovey = 63. - Saving. The world is not saved: it is generated again from its seed.
terreno.guardar(jugador)writes to the progress of that player only what differs from the generated world, per chunk, at 4 characters per block, together with the seed.terreno.restaurar(jugador)goes back to that world (if the scene does not fix a seed, it switches to the saved one) and puts the changes on top. Caps: 60,000 changed blocks at a time (on reaching it,ponerandromperfail with a clear message: checkterreno.cambios) and 320 KB of save data, apart from the 64 KB ofprogreso. The key it uses (_terreno:<escena>) is reserved. - Cost.
bloque,alturaandbuscarBloquegenerate the chunk if it was not there (about 1 ms the first time);suelo,bioma,climaandbuscarBiomagenerate nothing. - Stepping into generation. An author who wants more than the table has three ways:
estructurasin the data, direct changes at the start (llenara camp, a lighthouse), andalGenerar, which runs when the room loads each chunk near a player (what is changed there stays as part of the world and travels to everyone). The hook does not run for far-away chunks that are only drawn: what it adds appears when you get close.
Complete examples#
Complete scripts from docs/EJEMPLOS.md. Each one assumes a scene containing what it names, and the text keys (interfaz.t('...')) must exist in textos of juego.json.
mundo: touching pieces by tag and by id#
import { juego, mundo } from '@greengames/sdk';
juego.alIniciar(() => {
mundo.alTocar('#moneda', (moneda, j) => { // todas las piezas con la etiqueta "moneda"
moneda.eliminar();
j.puntos++;
});
mundo.alTocar('boton-rojo', (boton) => { // la pieza con id "boton-rojo"
boton.material = { color: 'verde', acabado: 'neon' };
mundo.pieza('puerta').solida = false;
mundo.pieza('puerta').visible = false;
});
mundo.alDejarDeTocar('#placa', (placa) => (placa.material = 'gris'));
});mundo: creating pieces from the script#
import { azar, juego, mundo } from '@greengames/sdk';
juego.alIniciar(() => {
for (let i = 0; i < 12; i++) {
const moneda = mundo.crear({
forma: 'cilindro',
posicion: [azar.entre(-10, 10), 1, azar.entre(-10, 10)],
rotacion: [90, 0, 0],
tamano: [0.9, 0.16, 0.9],
material: { color: 'ambar', acabado: 'brillante' },
solida: false,
etiquetas: ['moneda']
});
moneda.girar([0, 160, 0]);
}
});mundo: moving pieces#
import { juego, mundo, reloj } from '@greengames/sdk';
juego.alIniciar(() => {
// Ida y vuelta para siempre.
mundo.pieza('plataforma').moverA([0, 0, 20], { duracion: 3, vaiven: true, espera: 0.5 });
// Una vez, con aviso al llegar.
mundo.pieza('puente').moverA([0, 0, 8], { duracion: 1.5, alLlegar: () => juego.registro('puente listo') });
});
// A mano, cuadro a cuadro: una pieza en órbita. Se asigna un vector nuevo.
juego.cadaCuadro(() => {
const a = reloj.ahora * 2;
mundo.pieza('satelite').posicion = [Math.cos(a) * 5, 3, Math.sin(a) * 5];
});mundo: zones#
import { interfaz, juego, mundo } from '@greengames/sdk';
juego.alIniciar(() => {
mundo.alEntrar('#control', (zona, j) => {
j.aparicion = zona.id; // hay una aparición con el mismo id que la zona
interfaz.mensaje(interfaz.t('control'), { para: j, tipo: 'exito' });
});
mundo.alSalir('zona-segura', (_zona, j) => interfaz.mensaje(interfaz.t('cuidado'), { para: j, tipo: 'peligro' }));
mundo.alEntrar('meta', (_zona, j) => juego.terminar({ resultado: 'victoria', puntaje: j.puntos, de: j }));
});mundo: ray#
import { juego, jugadores, mundo } from '@greengames/sdk';
// ¿La torre ve al jugador? Un rayo desde la torre hasta su pecho: si choca antes con una pieza, está oculto.
juego.cadaCuadro(() => {
const ojo: [number, number, number] = [0, 6, 0];
for (const j of jugadores.todos()) {
const p = j.posicion;
const hacia: [number, number, number] = [p[0] - ojo[0], p[1] + 1 - ojo[1], p[2] - ojo[2]];
const distancia = Math.hypot(hacia[0], hacia[1], hacia[2]);
const impacto = mundo.rayo(ojo, hacia, distancia);
j.datos.visto = impacto === null || impacto.distancia > distancia - 0.6;
}
});mundo: groups, queries, collisions, staying in touch#
import { juego, mundo } from '@greengames/sdk';
juego.alIniciar(() => {
// Las piezas con "grupo": "puerta" en la escena se mueven juntas.
const puerta = mundo.grupo('puerta');
mundo.alTocar('boton', () => puerta.moverA([0, 6, 10], { duracion: 1.5 }));
// Explosion: todo lo que haya a 4 unidades con la etiqueta "caja".
mundo.alTocar('bomba', (bomba) => {
for (const caja of mundo.piezasEn(bomba.posicion, 4, 'caja')) caja.impulsar([0, 12, 0]);
bomba.eliminar();
});
// Una pelota (pieza dinamica con "rebote": 0.8) toca el arco.
mundo.alChocar('pelota', (_pelota, otra) => { if (otra.tiene('arco')) juego.registro('gol'); });
// Lava: quita vida mientras se pisa. dt siempre vale 1/60.
mundo.mientrasToca('#lava', (_lava, j, dt) => { j.datos.vida = (j.datos.vida as number) - 10 * dt; });
});mundo: lights, environment and zones created by the script#
import { juego, mundo, reloj, sonido } from '@greengames/sdk';
juego.alIniciar(() => {
// Anochece en 20 segundos y se encienden los faroles (luces con "id" en la escena).
reloj.despues(30, () => {
mundo.ambiente({ cielo: 'noche', luzAmbiente: 0.25, sol: { intensidad: 0.1 }, niebla: { desde: 10, hasta: 60 } }, 20);
for (const luz of mundo.luces()) luz.encendida = true;
sonido.ruido({ duracion: 3, filtro: 600, volumen: 0.4, ataque: 1 });
});
const faro = mundo.crearLuz({ id: 'faro', posicion: [0, 8, 0], color: 'ambar', intensidad: 3, alcance: 30 });
reloj.cada(0.5, () => (faro.encendida = !faro.encendida));
// Una zona de premio que aparece en un lugar nuevo cada vez.
const zona = mundo.crearZona({ id: 'premio', forma: 'esfera', posicion: [5, 1, 5], tamano: [3, 3, 3], datos: { puntos: 5 } });
mundo.alEntrar('premio', (z, j) => { j.puntos += z.datos.puntos as number; z.eliminar(); });
juego.registro('zona creada', zona.id);
});Next#
- The jugadores service
- API reference: the eleven services and the common types.
- Scripts: the rules of a script and how it runs inside the room.