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 dibuja | El runtime, por su cuenta | El propio juego (texto flotante, efectos, paneles, diálogo con retrato…) |
| Multijugador | Seguro: solo dibuja en tu pantalla, no crea objetos del juego ni cambia su estado | Solo en partidas de un jugador |
| Estilo | Libre: fuentes propias (también con caracteres chinos), esquinas redondeadas, semitransparencia, bordes, cualquier color, imágenes locales | Estilo nativo del juego |
| Seguir algo | Unidades, coordenadas del mundo, posiciones de pantalla; los círculos en el suelo siguen el relieve del terreno | Depende de la función |
| Coste | Medido: 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=Truealinea 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;liftlos 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étodo | Qué dibuja | Parámetros habituales |
|---|---|---|
text(key, texto, ...) | Cuadro de texto; \n para varias líneas | color, 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 carga | width, 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 terreno | color color de línea, fill relleno (con transparencia), width grosor de línea |
path(key, [puntos...], ...) | Línea quebrada en el suelo | color, 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);
faultsenstats()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.