Skip to content
Docs

The interfaz service

Reference for the interfaz service. What each player sees on top of the game: HUD, messages, timers, scoreboard, menus and labels in the world.

DescribesFormato 1, API 1 For those who write code This page is generated from the SDK sources.

On this page

What each player sees on top of the game: HUD, messages, timers, scoreboard, menus and labels in the world.

The types used in the signatures (Vec3, Texto, the selector) are in the API reference.

Functions and properties of interfaz#

interfaz.t#

ts
interfaz.t(clave: string, vars?: Record<string, string | number>): TextoClave

Builds a translatable text from a key in the manifest's textos.

From docs/EJEMPLOS.md, «mundo: zonas»:

ts
mundo.alSalir('zona-segura', (_zona, j) => interfaz.mensaje(interfaz.t('cuidado'), { para: j, tipo: 'peligro' }));

interfaz.hud#

ts
interfaz.hud(id: string, elemento: { texto: Texto; icono?: Icono; lugar?: LugarHud; estilo?: 'normal' | 'destacado' | 'peligro' } | null, para?: Jugador): void

Adds or updates a HUD item. null removes it.

From docs/EJEMPLOS.md, «interfaz: mensajes que no estorban, menú con opción deshabilitada, textos anidados»:

ts
// Textos mas cortos en telefonos verticales.
jugadores.alCambiarPantalla((j) => interfaz.hud('ayuda', { texto: interfaz.t(j.pantalla.vertical ? 'ayudaCorta' : 'ayuda'), lugar: 'abajo-centro' }, j));

interfaz.cronometro#

ts
interfaz.cronometro(id: string, opciones?: { lugar?: LugarHud; cuentaRegresiva?: number; alTerminar?: () => void; para?: Jugador }): Cronometro

A timer in the HUD. The player draws it frame by frame: you do not need to update it.

From docs/EJEMPLOS.md, «interfaz: mensajes que no estorban, menú con opción deshabilitada, textos anidados»:

ts
interfaz.cronometro('reloj', { cuentaRegresiva: 90, formato: 'segundos' });

interfaz.mensaje#

ts
interfaz.mensaje(texto: Texto, opciones?: { duracion?: number; tipo?: 'info' | 'exito' | 'peligro'; para?: Jugador }): void

A short message. By default, large and centered. lugar moves it up or down; tamano: 'chico' does not cover the game; cola: true waits for the previous message to finish instead of stacking.

From docs/EJEMPLOS.md, «mundo: zonas»:

ts
mundo.alSalir('zona-segura', (_zona, j) => interfaz.mensaje(interfaz.t('cuidado'), { para: j, tipo: 'peligro' }));

interfaz.marcador#

ts
interfaz.marcador(def: { titulo: Texto; filas: { nombre: Texto; valor: Texto | number; destacado?: boolean }[] } | null, para?: Jugador): void

An on-screen table (standings, laps). null removes it. Without calling this there is no scoreboard.

From docs/EJEMPLOS.md, «interfaz: marcador»:

ts
reloj.cada(0.5, () => {
  const filas = jugadores.todos()
    .sort((a, b) => b.puntos - a.puntos)
    .map((j) => ({ nombre: j.nombre, valor: j.puntos, destacado: !j.esBot }));
  interfaz.marcador({ titulo: interfaz.t('posiciones'), filas });
});

interfaz.menu#

ts
interfaz.menu(def: { id: string; titulo: Texto; texto?: Texto; opciones: { id: string; texto: Texto }[] }, para?: Jugador): void

Opens a menu of options for one player (or for everyone). The match is not paused.

From docs/EJEMPLOS.md, «interfaz: mensajes que no estorban, menú con opción deshabilitada, textos anidados»:

ts
interfaz.menu({ id: 'tienda', titulo: interfaz.t('tienda'), opciones: [
  { id: 'botas', texto: interfaz.t('botas') },
  { id: 'alas', texto: interfaz.t('alas'), deshabilitada: true }
] });

interfaz.cerrarMenu#

ts
interfaz.cerrarMenu(id: string, para?: Jugador): void

Closes the menu with that id, for one player or for everyone.

From games/defensa-del-faro/scripts/principal.ts:

ts
interfaz.cerrarMenu('inicio');

interfaz.alElegir#

ts
interfaz.alElegir(fn: (menu: string, opcion: string, jugador: Jugador) => void): void

A player picked an option. The menu has already closed.

From docs/EJEMPLOS.md, «interfaz: menú»:

ts
interfaz.alElegir((menu, opcion, j) => {
  if (menu !== 'camino') return;
  j.teletransportar(opcion === 'corto' ? 'inicio-corto' : 'inicio-largo');
  j.congelado = false;
});

interfaz.rotulo#

ts
interfaz.rotulo(id: string, def: { en: Vec3 | Pieza | Actor | Jugador; texto?: Texto; barra?: number; color?: string; altura?: number; estilo?; alcance?: number } | null, para?: Jugador): void

Adds, updates or (with null) removes a label in the world: text and a bar over a piece, an actor, a player or a point.

From docs/EJEMPLOS.md, «interfaz: rótulos, barras y números en el mundo»:

ts
const pintar = () => interfaz.rotulo('vida-torre', { en: torre, texto: interfaz.t('torre'), barra: (torre.datos.vida as number) / 10, color: 'coral', altura: 1 });

interfaz.flotante#

ts
interfaz.flotante(texto: Texto, en: Vec3 | Pieza | Actor | Jugador, opciones?: { tipo?; duracion?: number; para?: Jugador }): void

Text that pops out of a point in the world, rises and fades ("+10", "-3").

From docs/EJEMPLOS.md, «interfaz: rótulos, barras y números en el mundo»:

ts
mundo.alTocar('torre', (_torre, j) => {
  torre.datos.vida = (torre.datos.vida as number) - 1;
  interfaz.flotante('-1', torre, { tipo: 'peligro', para: j });
  if ((torre.datos.vida as number) <= 0) interfaz.rotulo('vida-torre', null);
  else pintar();
});

interfaz.marcadorDePuntos#

ts
interfaz.marcadorDePuntos(def: { titulo: Texto } | null): void

An automatic scoreboard with each player's puntos counter, sorted. null removes it.

From docs/EJEMPLOS.md, «interfaz: mensajes que no estorban, menú con opción deshabilitada, textos anidados»:

ts
interfaz.marcadorDePuntos({ titulo: interfaz.t('puntos') });

interfaz.barraRapida#

ts
interfaz.barraRapida(def: { ranuras: { color?: string; icono?: Icono; texto?: Texto; cantidad?: number }[] } | null, para?: Jugador): void

Hotbar: a row of up to 9 slots at the bottom center. The selected one is jugador.ranura. On touch screens each slot can be tapped. With null it is removed.

From games/valle-abierto/scripts/comun.ts:

ts
interfaz.barraRapida({ ranuras }, j);

interfaz.marcarBloque#

ts
interfaz.marcarBloque(posicion: Vec3 | null, opciones?: { avance?: number; color?: string }, para?: Jugador): void

Marks a terrain block with an outline (the block pointed at). avance from 0 to 1 shows how much is left to break it. With null it is removed. Each player has their own mark.

From games/valle-abierto/scripts/principal.ts:

ts
interfaz.marcarBloque(a.posicion, { avance, color }, j);

Cronometro#

A timer in the HUD: what interfaz.cronometro returns.

PropertyTypeDescription
cronometro.valornumberRead-only. Seconds elapsed (or remaining, for a countdown).
cronometro.corriendobooleanRead-only. true while it is running.

cronometro.iniciar#

ts
cronometro.iniciar(): void

Starts it.

From docs/EJEMPLOS.md, «interfaz: HUD, mensajes y cronómetro»:

ts
juego.alIniciar(() => {
  const crono = interfaz.cronometro('tiempo', {
    cuentaRegresiva: 60,
    alTerminar: () => juego.terminar({ resultado: 'derrota' })
  });
  crono.iniciar();

  jugadores.alEntrar((j) => {
    interfaz.hud('puntos', { icono: 'estrella', texto: interfaz.t('puntos', { n: 0 }), lugar: 'arriba-izquierda' }, j);
  });
  interfaz.mensaje(interfaz.t('objetivo'), { duracion: 3 });
});

cronometro.detener#

ts
cronometro.detener(): void

Stops it.

From games/circuito-luz-verde/scripts/principal.ts:

ts
let crono: Cronometro;
// ...
crono.detener();

cronometro.reiniciar#

ts
cronometro.reiniciar(): void

Resets it to 0 (or to the countdown total) and stops it.

cronometro.sumar#

ts
cronometro.sumar(segundos: number): void

Adds seconds (a penalty) or subtracts them with a negative number.

From games/isla-taller/scripts/principal.ts:

ts
let crono: Cronometro;
// ...
crono.sumar(-AJUSTES.bono);

cronometro.quitar#

ts
cronometro.quitar(): void

Removes it from the HUD.

From games/defensa-del-faro/scripts/principal.ts:

ts
let crono: Cronometro | null = null;
// ...
crono?.quitar();

Texto#

A Texto is interfaz.t('clave', { n: 3 }) (recommended: each player translates it), { es, en } or a plain string (only for numbers and proper names). interfaz.t returns an object, not a string: do not concatenate it; put the variables in the template ("monedas": "{n} de {total}").

ts
type Texto = string | { es: string; en: string } | TextoClave;
interface TextoClave {
  clave: string;
  vars?: Record<string, string | number | TextoClave | { es: string; en: string }>;
}

Behavior notes#

  • Icons: moneda, reloj, corazon, estrella, bandera, llave, rayo, jugador, escudo, espada, martillo, casa, gota, hoja, fuego, engranaje, diana, diamante, calavera, flecha, caja, pregunta, luz, ola.
  • Places: arriba-izquierda, arriba-centro, arriba-derecha, abajo-izquierda, abajo-centro, abajo-derecha.
  • The player draws the timer frame by frame: you do not need to update it.
  • A menu does not pause the match. If you want nobody to move, freeze the players. An option with deshabilitada: true is shown but cannot be chosen. The menu scrolls if it does not fit.
  • interfaz.mensaje accepts lugar ('centro', 'arriba', 'abajo'), tamano ('chico', 'normal', 'grande') and cola: true (waits for the previous message to finish instead of stacking). A small message at the top does not cover the game.
  • interfaz.cronometro accepts formato: 'centesimas' (1:23.45, the default), 'segundos' (1:23) or 'entero' (83). cronometro.sumar(n) adds n to the elapsed time: in a countdown, sumar(5) takes 5 seconds off what is left and sumar(-5) gives 5 back.
  • A variable of interfaz.t can be another translatable text: interfaz.t('ganaste', { premio: interfaz.t('copa') }).
  • interfaz.rotulo puts text, a bar (barra from 0 to 1), or both, over a piece, an actor, a player or a point in the world; it follows whatever it is attached to. With the same id it is updated; with null it is removed.
  • interfaz.flotante shows a text that pops out of a point, rises and fades ("+10").
  • jugador.puntos is not drawn by itself. interfaz.marcadorDePuntos({ titulo }) shows an automatic scoreboard with each player's points; or draw your own with interfaz.hud or interfaz.marcador.
  • The HUD wraps lines on narrow screens, and the scoreboard goes in the top-right column, below the chips, without overlapping them.
  • The start screen (cover, difficulty, controls), the pause menu and the end panel are provided by the player: the game does not program them.

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.

interfaz: HUD, messages and timer#

scripts/principal.ts
import { interfaz, juego, jugadores } from '@greengames/sdk';

juego.alIniciar(() => {
  const crono = interfaz.cronometro('tiempo', {
    cuentaRegresiva: 60,
    alTerminar: () => juego.terminar({ resultado: 'derrota' })
  });
  crono.iniciar();

  jugadores.alEntrar((j) => {
    interfaz.hud('puntos', { icono: 'estrella', texto: interfaz.t('puntos', { n: 0 }), lugar: 'arriba-izquierda' }, j);
  });
  interfaz.mensaje(interfaz.t('objetivo'), { duracion: 3 });
});

interfaz: menu#

scripts/principal.ts
import { interfaz, juego, jugadores } from '@greengames/sdk';

juego.alIniciar(() => {
  for (const j of jugadores.todos()) j.congelado = true;       // un menú no pausa la partida
  interfaz.menu({
    id: 'camino',
    titulo: interfaz.t('elige'),
    opciones: [{ id: 'corto', texto: interfaz.t('caminoCorto') }, { id: 'largo', texto: interfaz.t('caminoLargo') }]
  });
  interfaz.alElegir((menu, opcion, j) => {
    if (menu !== 'camino') return;
    j.teletransportar(opcion === 'corto' ? 'inicio-corto' : 'inicio-largo');
    j.congelado = false;
  });
});

interfaz: scoreboard#

scripts/principal.ts
import { interfaz, juego, jugadores, reloj } from '@greengames/sdk';

juego.alIniciar(() => {
  reloj.cada(0.5, () => {
    const filas = jugadores.todos()
      .sort((a, b) => b.puntos - a.puntos)
      .map((j) => ({ nombre: j.nombre, valor: j.puntos, destacado: !j.esBot }));
    interfaz.marcador({ titulo: interfaz.t('posiciones'), filas });
  });
});

interfaz: labels, bars and numbers in the world#

scripts/principal.ts
import { interfaz, juego, mundo } from '@greengames/sdk';

juego.alIniciar(() => {
  const torre = mundo.pieza('torre');
  torre.datos.vida = 10;
  const pintar = () => interfaz.rotulo('vida-torre', { en: torre, texto: interfaz.t('torre'), barra: (torre.datos.vida as number) / 10, color: 'coral', altura: 1 });
  pintar();
  mundo.alTocar('torre', (_torre, j) => {
    torre.datos.vida = (torre.datos.vida as number) - 1;
    interfaz.flotante('-1', torre, { tipo: 'peligro', para: j });
    if ((torre.datos.vida as number) <= 0) interfaz.rotulo('vida-torre', null);
    else pintar();
  });
});

interfaz: unobtrusive messages, a menu with a disabled option, nested texts#

scripts/principal.ts
import { interfaz, juego, jugadores } from '@greengames/sdk';

juego.alIniciar(() => {
  interfaz.mensaje(interfaz.t('pista'), { lugar: 'arriba', tamano: 'chico', cola: true, duracion: 4 });
  interfaz.mensaje(interfaz.t('ganaste', { premio: interfaz.t('copa') }), { tamano: 'grande', tipo: 'exito' });
  interfaz.cronometro('reloj', { cuentaRegresiva: 90, formato: 'segundos' });
  interfaz.marcadorDePuntos({ titulo: interfaz.t('puntos') });
  interfaz.menu({ id: 'tienda', titulo: interfaz.t('tienda'), opciones: [
    { id: 'botas', texto: interfaz.t('botas') },
    { id: 'alas', texto: interfaz.t('alas'), deshabilitada: true }
  ] });
  // Textos mas cortos en telefonos verticales.
  jugadores.alCambiarPantalla((j) => interfaz.hud('ayuda', { texto: interfaz.t(j.pantalla.vertical ? 'ayudaCorta' : 'ayuda'), lugar: 'abajo-centro' }, j));
});

Next#