Docs Extensiones de juego

Lienzo

Dibuja sobre la imagen del juego cuadros de texto, paneles, barras de progreso, imágenes, círculos pegados al suelo y rutas con flecha. El runtime lo dibuja él mismo en cada fotograma sin cambiar el estado del juego, así que también es seguro en multijugador; desde Python, por HTTP o escribiendo directamente en memoria compartida.

Un programa externo puede dibujar sobre la imagen del juego cuadros de texto, paneles, barras de progreso, imágenes, círculos en el suelo y rutas en el suelo (con flecha), y el runtime los dibuja él mismo en cada fotograma. Sirve para tu propio HUD, líneas de ayuda, avisos, anotaciones didácticas o paneles de información para directos.

Lienzo o funciones visuales de JASS: cuál elegir

Lienzo (esta página)Funciones visuales de JASS
Quién dibujaEl runtime, por su cuentaEl propio juego (texto flotante, efectos, paneles, diálogo con retrato…)
MultijugadorSeguro: solo dibuja en tu pantalla, no crea objetos del juego ni cambia su estadoSolo en partidas de un jugador
EstiloLibre: fuentes propias (también con caracteres chinos), esquinas redondeadas, semitransparencia, bordes, cualquier color, imágenes localesEstilo nativo del juego
Seguir algoUnidades, coordenadas del mundo, posiciones de pantalla; los círculos en el suelo siguen el relieve del terrenoDepende de la función
CosteMedido: 0.2 ~ 0.35 ms por fotograma (9 elementos)Unos 13 ms por llamada

Se pueden usar las dos a la vez: JASS para los efectos con estilo nativo, el lienzo para paneles propios, líneas de ayuda y avisos.

Python

c = g.canvas                               # la primera vez, el runtime instala el hook de dibujo (unos 0.1 s)
c.text("title", "Hola, esto es el lienzo", screen=(40, 110), color=(255, 220, 80),
       bg=(0, 0, 0, 170), border="#C49C40", size=22, bold=True)
c.panel("status", "Compañero · Luz", ["Ánimo: feliz", "Bajas: 12"], screen=(16, 330))
c.bar("hp", 0.62, unit=hero, lift=260, width=100, height=12, color=(80, 220, 80), text="62%")   # sigue a la unidad
c.text("tag", "¡El jefe va a lanzar su ataque definitivo!", unit=boss, lift=320, color=(255, 80, 80), size=22, bold=True)
c.circle("danger", (x, y), 300, color=(255, 60, 60), fill=(255, 60, 60, 60), width=3)          # zona peligrosa en el suelo
c.circle("aura", hero, 450, color=(80, 200, 255, 220))                                         # círculo que sigue a la unidad
c.path("route", [(x1, y1), (x2, y2), (x3, y3)], color=(255, 220, 0), width=5, arrow=True)
c.image("icon", "icon.png", screen=(40, 170), width=64, height=64)
c.remove("danger"); c.hide("tag"); c.clear()   # clear solo borra lo que dibujaste tú
c.expire("tag", 5)                         # desaparece por sí mismo a los 5 s
with c.batch(): ...                        # cambia muchos elementos y escribe una sola vez en memoria compartida
c.stats()                                  # si drawnFrames sube, de verdad se está dibujando

Cada elemento se identifica con una key: dibujar otra vez con la misma key lo actualiza.

Clicables: añade clickable=True a un cuadro de texto o a un panel (el color al pasar el ratón se fija con hover=); al hacer clic llega un ui.click al flujo de eventos, con ev.key igual a esa key, y el juego no recibe ese clic. Para botones, tarjetas de elección, atajos de teclado y clics en el suelo ya listos, ver Interfaz y entrada.

Posición (una por elemento):

  • screen=(x, y): píxeles de pantalla; los negativos cuentan desde la derecha / desde abajo; center=True alinea por el centro;
  • frac=(0.5, 0.1): fracción de la pantalla;
  • world=(x, y): coordenadas del mundo;
  • unit=unidad: sigue a una unidad. El texto y las barras sobre el mundo o sobre una unidad se anclan por el punto medio del borde inferior; lift los sube.

Por defecto, los elementos del mundo y de unidades evitan la consola de abajo y el orbe de día y noche de arriba (over_ui=True los dibuja por encima). Los colores se pueden escribir como (r, g, b), (r, g, b, a), "#RRGGBB" o "#RRGGBBAA".

MétodoQué dibujaParámetros habituales
text(key, texto, ...)Cuadro de texto; \n para varias líneascolor, bg color de fondo (transparente si no se indica), border, size, bold, shadow, width (ajusta las líneas a este ancho), radius esquinas redondeadas
panel(key, título, [líneas...], ...)Panel (fondo oscuro semitransparente, borde dorado)Igual que text
bar(key, 0..1, ...)Barra de progreso: vida, enfriamiento, barra de cargawidth, height, color, bg, border, text
image(key, ruta, ...)Imagen local (png / jpg / bmp / gif)width, height (tamaño original si no se indican)
circle(key, unidad_o_punto, radio, ...)Círculo en el suelo, pegado al terrenocolor color de línea, fill relleno (con transparencia), width grosor de línea
path(key, [puntos...], ...)Línea quebrada en el suelocolor, width, arrow flecha al final; los puntos pueden ser coordenadas o unidades

HTTP (cualquier lenguaje)

Backend de Farsight (solo escucha en local):

POST /api/instances/20/canvas
{"set": [
   {"key": "banner", "kind": "text", "text": "Lienzo desde HTTP", "frac": [0.5, 0.12], "center": true,
    "color": "#FFDC50", "bg": [0, 0, 0, 180]},
   {"key": "hp", "kind": "bar", "value": 0.8, "unit": 596125988, "lift": 260, "text": "80%"},
   {"key": "zone", "kind": "circle", "center": 596125988, "radius": 600, "color": [255, 200, 0], "width": 4},
   {"key": "route", "kind": "path", "points": [[-4587, -9092], [-5387, -8792]], "color": "#50C8FF"}
 ],
 "remove": ["old"], "clear": false}

GET  /api/instances/20/canvas        qué elementos hay dibujados ahora + cuántos fotogramas se han dibujado

kind es el nombre del método de Python y los parámetros se llaman igual; para una unidad se escribe su dirección addr de la instantánea.

Escribir directamente en memoria compartida

También se puede sin pasar por Python ni por Farsight: primero se envía una vez el comando semántico canvas_enable (código de operación 73 de W3P) y el runtime crea el bloque de memoria compartida Local\War3Canvas_<pid>: cabecera de 64 bytes + 256 entradas × 112 bytes + un pool de 64 KB para texto / puntos. Se escribe con seqlock (el número de secuencia pasa a impar → se escriben las entradas y el pool → el número de secuencia pasa a par); el runtime lo lee una vez por fotograma, si encuentra una escritura a medias sigue usando el fotograma anterior, y devuelve el número de fotogramas dibujados, el número de elementos y el contador de fallos. La implementación de referencia en Python es sdk/python/w3canvas.py y las estructuras están definidas en el header del protocolo; ver Protocolo W3P.

Varios programas dibujando a la vez

Los mods, Farsight, MCP y la pasarela pueden dibujar a la vez en la misma partida, pero solo hay un lienzo. La regla es: cada programa solo toca sus propios elementos.

  • Antes de escribir se toma un bloqueo con nombre, se leen los elementos que ya hay, se dejan los de los demás, se ponen los propios y se vuelve a escribir;
  • Cada elemento guarda quién lo dibujó (ID de proceso + número de secuencia dentro del proceso); si el programa que lo dibujó termina, se limpia la próxima vez que alguien escriba, y sus botones dejan de interceptar clics;
  • Los números de elemento salen de un contador compartido, así que no chocan.

El SDK de Python ya lo hace así, y clear() solo borra lo propio. Si escribes tú directamente en la memoria compartida, sigue estas reglas; si no, borrarás lo que han dibujado otros. Los detalles de la estructura están en Protocolo W3P.

Medidas y precauciones

  • Medido el 25 de septiembre de 2026 (1920×1080, velocidad 2×): 9 elementos, 0.27 ~ 0.34 ms por fotograma, unos 63 fotogramas / s, 0 fallos; escribir 9 entradas lleva 6 ms; cuando el héroe se mueve, los círculos, el texto y las barras de vida que lo siguen van a la par. La textura solo se vuelve a generar si cambia el contenido; si solo cambia la posición, no.
  • Se dibuja después de la interfaz del juego y antes del puntero del ratón: cubre las barras de vida, las unidades y la interfaz del propio juego, y el puntero queda por encima. Evita la consola de abajo y el orbe de día y noche de arriba, pero no evita los paneles del propio mapa (la tabla de clasificación y la cuenta atrás de la esquina superior derecha): no pongas tus paneles arriba a la derecha.
  • Fuera de una partida (menú principal, pantalla de resultados), los elementos colocados en coordenadas del mundo o sobre unidades no se dibujan; los que están en una posición de pantalla sí.
  • Los círculos en el suelo proyectan sobre el terreno cada uno de los 64 puntos de la circunferencia, así que cuando el terreno tiene desniveles la forma sube y baja con él; es lo correcto: se dibuja sobre el suelo real.
  • La primera vez hay que instalar el hook y precalentar las fuentes, lo que lleva alrededor de 1 segundo; mientras tanto no se dibujan los elementos de texto, pero los círculos y las líneas sí.
  • Si se produce un fallo durante el dibujo, deja de dibujar durante el resto de la sesión (la misma protección que las burbujas); faults en stats() pasa a 1.
  • Texto, rutas de imágenes y puntos comparten 64 KB, con un máximo de 256 elementos; las rutas de imagen deben ser rutas locales que el proceso del juego pueda leer.

El panel de estado del compañero IA está dibujado con el lienzo: barra de vida, qué está haciendo, ánimo, bajas y curas.