Servicio interfaz
Referencia del servicio interfaz. Lo que ve cada jugador sobre el juego: HUD, mensajes, cronómetros, marcador, menús y rótulos en el mundo.
Corresponde aFormato 1, API 1 Para quien escribe código Esta página se genera desde las fuentes del SDK.
En esta página
- Funciones y propiedades de interfaz
- interfaz.t
- interfaz.hud
- interfaz.cronometro
- interfaz.mensaje
- interfaz.marcador
- interfaz.menu
- interfaz.cerrarMenu
- interfaz.alElegir
- interfaz.rotulo
- interfaz.flotante
- interfaz.marcadorDePuntos
- interfaz.barraRapida
- interfaz.marcarBloque
- Cronometro
- cronometro.iniciar
- cronometro.detener
- cronometro.reiniciar
- cronometro.sumar
- cronometro.quitar
- Texto
- Notas de comportamiento
- Ejemplos completos
- interfaz: HUD, mensajes y cronómetro
- interfaz: menú
- interfaz: marcador
- interfaz: rótulos, barras y números en el mundo
- interfaz: mensajes que no estorban, menú con opción deshabilitada, textos anidados
- Sigue con
Lo que ve cada jugador sobre el juego: HUD, mensajes, cronómetros, marcador, menús y rótulos en el mundo.
Los tipos que aparecen en las firmas (Vec3, Texto, el selector) están en la referencia de la API.
Funciones y propiedades de interfaz#
interfaz.t#
interfaz.t(clave: string, vars?: Record<string, string | number>): TextoClaveArma un texto traducible a partir de una clave de textos del manifiesto.
De docs/EJEMPLOS.md, «mundo: zonas»:
mundo.alSalir('zona-segura', (_zona, j) => interfaz.mensaje(interfaz.t('cuidado'), { para: j, tipo: 'peligro' }));interfaz.hud#
interfaz.hud(id: string, elemento: { texto: Texto; icono?: Icono; lugar?: LugarHud; estilo?: 'normal' | 'destacado' | 'peligro' } | null, para?: Jugador): voidPone o actualiza un elemento del HUD. Con null lo quita.
De docs/EJEMPLOS.md, «interfaz: mensajes que no estorban, menú con opción deshabilitada, textos anidados»:
// 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#
interfaz.cronometro(id: string, opciones?: { lugar?: LugarHud; cuentaRegresiva?: number; alTerminar?: () => void; para?: Jugador }): CronometroCronómetro en el HUD. Lo dibuja el reproductor cuadro a cuadro: no hay que actualizarlo.
De docs/EJEMPLOS.md, «interfaz: mensajes que no estorban, menú con opción deshabilitada, textos anidados»:
interfaz.cronometro('reloj', { cuentaRegresiva: 90, formato: 'segundos' });interfaz.mensaje#
interfaz.mensaje(texto: Texto, opciones?: { duracion?: number; tipo?: 'info' | 'exito' | 'peligro'; para?: Jugador }): voidMensaje breve. Por defecto, grande y al centro. lugar lo sube o lo baja; tamano: 'chico' no tapa el juego; cola: true espera a que termine el mensaje anterior en vez de apilarse.
De docs/EJEMPLOS.md, «mundo: zonas»:
mundo.alSalir('zona-segura', (_zona, j) => interfaz.mensaje(interfaz.t('cuidado'), { para: j, tipo: 'peligro' }));interfaz.marcador#
interfaz.marcador(def: { titulo: Texto; filas: { nombre: Texto; valor: Texto | number; destacado?: boolean }[] } | null, para?: Jugador): voidTabla a la vista (posiciones, vueltas). Con null la quita. Sin llamar a esto no hay marcador.
De docs/EJEMPLOS.md, «interfaz: marcador»:
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#
interfaz.menu(def: { id: string; titulo: Texto; texto?: Texto; opciones: { id: string; texto: Texto }[] }, para?: Jugador): voidAbre un menú de opciones para un jugador (o para todos). La partida no se pausa.
De docs/EJEMPLOS.md, «interfaz: mensajes que no estorban, menú con opción deshabilitada, textos anidados»:
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#
interfaz.cerrarMenu(id: string, para?: Jugador): voidCierra el menú con ese id, para un jugador o para todos.
De games/defensa-del-faro/scripts/principal.ts:
interfaz.cerrarMenu('inicio');interfaz.alElegir#
interfaz.alElegir(fn: (menu: string, opcion: string, jugador: Jugador) => void): voidUn jugador eligió una opción. El menú ya se cerró.
De docs/EJEMPLOS.md, «interfaz: menú»:
interfaz.alElegir((menu, opcion, j) => {
if (menu !== 'camino') return;
j.teletransportar(opcion === 'corto' ? 'inicio-corto' : 'inicio-largo');
j.congelado = false;
});interfaz.rotulo#
interfaz.rotulo(id: string, def: { en: Vec3 | Pieza | Actor | Jugador; texto?: Texto; barra?: number; color?: string; altura?: number; estilo?; alcance?: number } | null, para?: Jugador): voidPone, actualiza o (con null) quita un rótulo en el mundo: texto y barra sobre una pieza, un actor, un jugador o un punto.
De docs/EJEMPLOS.md, «interfaz: rótulos, barras y números en el mundo»:
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#
interfaz.flotante(texto: Texto, en: Vec3 | Pieza | Actor | Jugador, opciones?: { tipo?; duracion?: number; para?: Jugador }): voidTexto que sale de un punto del mundo, sube y se desvanece ("+10", "-3").
De docs/EJEMPLOS.md, «interfaz: rótulos, barras y números en el mundo»:
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#
interfaz.marcadorDePuntos(def: { titulo: Texto } | null): voidMarcador automático con el contador puntos de cada jugador, ordenado. Con null lo quita.
De docs/EJEMPLOS.md, «interfaz: mensajes que no estorban, menú con opción deshabilitada, textos anidados»:
interfaz.marcadorDePuntos({ titulo: interfaz.t('puntos') });interfaz.barraRapida#
interfaz.barraRapida(def: { ranuras: { color?: string; icono?: Icono; texto?: Texto; cantidad?: number }[] } | null, para?: Jugador): voidBarra rápida: una fila de hasta 9 ranuras abajo al centro. La elegida es jugador.ranura. En pantallas táctiles cada ranura se toca. Con null se quita.
De games/valle-abierto/scripts/comun.ts:
interfaz.barraRapida({ ranuras }, j);interfaz.marcarBloque#
interfaz.marcarBloque(posicion: Vec3 | null, opciones?: { avance?: number; color?: string }, para?: Jugador): voidMarca un bloque del terreno con un recuadro (el bloque apuntado). avance de 0 a 1 muestra cuánto falta para romperlo. Con null se quita. Cada jugador tiene su marca.
De games/valle-abierto/scripts/principal.ts:
interfaz.marcarBloque(a.posicion, { avance, color }, j);Cronometro#
Un cronómetro del HUD: lo que devuelve interfaz.cronometro.
| Propiedad | Tipo | Descripción |
|---|---|---|
cronometro.valor | number | Solo lectura. Segundos transcurridos (o restantes, si es cuenta regresiva). |
cronometro.corriendo | boolean | Solo lectura. true mientras avanza. |
cronometro.iniciar#
cronometro.iniciar(): voidLo pone a correr.
De docs/EJEMPLOS.md, «interfaz: HUD, mensajes y cronómetro»:
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#
cronometro.detener(): voidLo detiene.
De games/circuito-luz-verde/scripts/principal.ts:
let crono: Cronometro;
// ...
crono.detener();cronometro.reiniciar#
cronometro.reiniciar(): voidVuelve a 0 (o al total de la cuenta regresiva) y lo detiene.
cronometro.sumar#
cronometro.sumar(segundos: number): voidSuma segundos (una penalización) o los resta con un número negativo.
De games/isla-taller/scripts/principal.ts:
let crono: Cronometro;
// ...
crono.sumar(-AJUSTES.bono);cronometro.quitar#
cronometro.quitar(): voidLo quita del HUD.
De games/defensa-del-faro/scripts/principal.ts:
let crono: Cronometro | null = null;
// ...
crono?.quitar();Texto#
Un Texto es interfaz.t('clave', { n: 3 }) (lo recomendado: lo traduce cada reproductor), { es, en } o una cadena tal cual (solo para números y nombres propios). interfaz.t devuelve un objeto, no una cadena: no lo concatenes; pon las variables en la plantilla ("monedas": "{n} de {total}").
type Texto = string | { es: string; en: string } | TextoClave;
interface TextoClave {
clave: string;
vars?: Record<string, string | number | TextoClave | { es: string; en: string }>;
}Notas de comportamiento#
- Iconos:
moneda,reloj,corazon,estrella,bandera,llave,rayo,jugador,escudo,espada,martillo,casa,gota,hoja,fuego,engranaje,diana,diamante,calavera,flecha,caja,pregunta,luz,ola. - Lugares:
arriba-izquierda,arriba-centro,arriba-derecha,abajo-izquierda,abajo-centro,abajo-derecha. - El cronómetro lo dibuja el reproductor cuadro a cuadro: no hay que actualizarlo.
- Un menú no pausa la partida. Si quieres que nadie se mueva, congela a los jugadores. Una opción con
deshabilitada: truese ve pero no se puede elegir. El menú hace scroll si no cabe. interfaz.mensajeadmitelugar('centro','arriba','abajo'),tamano('chico','normal','grande') ycola: true(espera a que termine el mensaje anterior en vez de apilarse). Un mensaje chico arriba no tapa el juego.interfaz.cronometroadmiteformato:'centesimas'(1:23.45, por defecto),'segundos'(1:23) o'entero'(83).cronometro.sumar(n)sumanal tiempo transcurrido: en una cuenta regresiva,sumar(5)quita 5 segundos de los que quedan ysumar(-5)regala 5.- Una variable de
interfaz.tpuede ser otro texto traducible:interfaz.t('ganaste', { premio: interfaz.t('copa') }). interfaz.rotulopone texto, una barra (barrade 0 a 1), o las dos cosas, sobre una pieza, un actor, un jugador o un punto del mundo; sigue a lo que esté pegado. Con el mismoidse actualiza; connullse quita.interfaz.flotantemuestra un texto que sale de un punto, sube y se desvanece ("+10").jugador.puntosno se dibuja solo.interfaz.marcadorDePuntos({ titulo })muestra un marcador automático con los puntos de cada jugador; o dibuja los tuyos coninterfaz.hudointerfaz.marcador.- El HUD hace salto de línea en pantallas angostas, y el marcador va en la columna de arriba a la derecha, bajo los chips, sin montarse.
- La pantalla de inicio (portada, dificultad, controles), la pausa y el panel de fin los pone el reproductor: el juego no los programa.
Ejemplos completos#
Scripts completos de docs/EJEMPLOS.md. Cada uno supone una escena con lo que nombra, y las claves de texto (interfaz.t('...')) deben existir en textos de juego.json.
interfaz: HUD, mensajes y cronómetro#
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: menú#
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: marcador#
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: rótulos, barras y números en el mundo#
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: mensajes que no estorban, menú con opción deshabilitada, textos anidados#
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));
});Sigue con#
- Servicio sonido
- Referencia de la API: los once servicios y los tipos comunes.
- Scripts: las reglas de un script y cómo corre dentro de la sala.