Canevas
Dessinez sur l’écran du jeu des zones de texte, des panneaux, des barres de progression, des images, des cercles plaqués au sol et des tracés fléchés. Le runtime les dessine lui-même à chaque frame, sans modifier l’état du jeu : sans risque en multijoueur. Depuis Python, en HTTP ou en écrivant directement dans la mémoire partagée.
Un programme externe peut dessiner sur l’écran du jeu des zones de texte, panneaux, barres de progression, images, cercles au sol et tracés au sol (avec flèche), que le runtime dessine lui-même à chaque frame. Idéal pour votre propre HUD, des lignes d’aide, des indications, des annotations pédagogiques ou un panneau d’infos pour le streaming.
Canevas ou fonctions d’affichage JASS : que choisir
| Canevas (cette page) | Fonctions d’affichage JASS | |
|---|---|---|
| Qui dessine | Le runtime lui-même | Le jeu lui-même (texte flottant, effets spéciaux, panneaux, dialogue avec portrait…) |
| Multijoueur | Sans risque : dessiné uniquement sur l’écran local, sans créer d’objet de jeu ni modifier l’état du jeu | Parties solo uniquement |
| Style | Libre : polices au choix (chinois compris), coins arrondis, semi-transparence, bordures, n’importe quelle couleur, images locales | Style natif du jeu |
| Suivre quelque chose | Une unité, des coordonnées du monde, une position à l’écran ; les cercles au sol épousent le relief | Selon la fonction |
| Coût | Mesuré : 0.2 à 0.35 ms par frame (9 éléments) | Environ 13 ms par appel |
Les deux approches se combinent : JASS pour les effets au style natif, le canevas pour les panneaux personnalisés, les lignes d’aide et les indications.
Python
c = g.canvas # au premier usage, le runtime installe le hook de dessin (environ 0.1 s)
c.text("title", "Bonjour, ceci est le canevas", screen=(40, 110), color=(255, 220, 80),
bg=(0, 0, 0, 170), border="#C49C40", size=22, bold=True)
c.panel("status", "Compagnon · Lumi", ["Humeur : joyeux", "Éliminations : 12"], screen=(16, 330))
c.bar("hp", 0.62, unit=hero, lift=260, width=100, height=12, color=(80, 220, 80), text="62%") # suit l'unité
c.text("tag", "Le boss prépare son ultime !", 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) # zone dangereuse au sol
c.circle("aura", hero, 450, color=(80, 200, 255, 220)) # cercle qui suit l'unité
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 n'efface que ce que vous avez dessiné
c.expire("tag", 5) # disparaît tout seul au bout de 5 s
with c.batch(): ... # beaucoup de modifications, une seule écriture en mémoire partagée
c.stats() # drawnFrames augmente = le dessin a bien lieu
Chaque élément est identifié par une key : redessiner avec la même key revient à le mettre à jour.
Cliquable : ajoutez clickable=True à une zone de texte ou à un panneau (la couleur de survol se règle avec hover=) ; un clic dessus envoie un ui.click dans le flux d’événements, avec ev.key égal à cette key, et le jeu ne reçoit pas ce clic. Boutons, cartes de choix, raccourcis clavier et clics au sol prêts à l’emploi : voir Interface et entrées.
Position (une par élément) :
screen=(x, y): pixels à l’écran ; une valeur négative compte à partir du bord droit / bas ;center=Truealigne sur le centre ;frac=(0.5, 0.1): fraction de l’écran ;world=(x, y): coordonnées du monde ;unit=unité: suit l’unité. Pour le texte et les barres placés sur le monde ou sur une unité, le milieu du bord inférieur est aligné sur ce point ;liftles remonte.
Par défaut, les éléments placés sur le monde ou sur une unité évitent le panneau de commande en bas et l’horloge jour/nuit en haut (over_ui=True pour passer par-dessus). Les couleurs s’écrivent (r, g, b), (r, g, b, a), "#RRGGBB" ou "#RRGGBBAA".
| Méthode | Ce qu’elle dessine | Paramètres courants |
|---|---|---|
text(key, texte, ...) | Zone de texte, plusieurs lignes avec \n | color, bg couleur de fond (transparent si omis), border, size, bold, shadow, width (retour à la ligne à cette largeur), radius coins arrondis |
panel(key, titre, [lignes...], ...) | Panneau (fond sombre semi-transparent, bordure dorée) | Comme text |
bar(key, 0..1, ...) | Barre de progression : vie, recharge, incantation | width, height, color, bg, border, text |
image(key, chemin, ...) | Image locale (png / jpg / bmp / gif) | width, height (taille d’origine si omis) |
circle(key, unité ou point, rayon, ...) | Cercle au sol, qui épouse le relief | color couleur du trait, fill remplissage (avec transparence), width épaisseur du trait |
path(key, [points...], ...) | Ligne brisée au sol | color, width, arrow flèche à l’extrémité ; les points peuvent être des coordonnées ou des unités |
HTTP (tout langage)
Serveur de Farsight (écoute uniquement en local) :
POST /api/instances/20/canvas
{"set": [
{"key": "banner", "kind": "text", "text": "Canevas envoyé par 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 éléments actuellement dessinés + nombre de frames dessinées
kind est le nom de la méthode Python, et les noms de paramètres sont les mêmes ; une unité s’indique par son adresse addr dans l’instantané.
Écrire directement dans la mémoire partagée
On peut aussi se passer de Python et de Farsight : envoyez d’abord une fois la commande sémantique canvas_enable (opcode W3P 73) ; le runtime crée alors le bloc de mémoire partagée Local\War3Canvas_<pid> : en-tête de 64 octets + 256 entrées × 112 octets + réserve de 64 KB pour les textes / points. L’écriture suit le seqlock (numéro de séquence impair → écriture des entrées et de la réserve → numéro de séquence pair) ; le runtime lit le bloc une fois par frame, reprend la frame précédente s’il tombe sur une écriture à moitié faite, et renvoie le nombre de frames dessinées, le nombre d’éléments et le compteur d’exceptions. L’implémentation de référence en Python est sdk/python/w3canvas.py ; les structures sont définies dans l’en-tête du protocole, voir Protocole W3P.
Plusieurs programmes qui dessinent en même temps
Mods, Farsight, MCP et la passerelle peuvent dessiner en même temps dans la même partie, alors qu’il n’y a qu’un seul canevas. La règle : chaque programme ne touche qu’à ses propres éléments.
- Avant d’écrire, prendre un verrou nommé, lire les éléments existants, garder ceux des autres, remplacer les siens, puis réécrire le tout ;
- Chaque élément retient qui l’a dessiné (identifiant de processus + numéro dans ce processus) ; si le programme qui l’a dessiné s’est arrêté, l’élément est nettoyé à la prochaine écriture, quel qu’en soit l’auteur, et ses boutons n’interceptent plus les clics ;
- Les numéros d’éléments sont attribués par un compteur partagé, donc sans collision.
Le SDK Python le fait déjà, et clear() n’efface lui aussi que ses propres éléments. Si vous écrivez vous-même directement dans la mémoire partagée, suivez ces règles, sinon vous écraserez ce que les autres ont dessiné. Pour le détail de la structure en mémoire, voir Protocole W3P.
Mesures et précautions
- Mesuré le 2026-09-25 (1920×1080, vitesse ×2) : 0.27 à 0.34 ms par frame pour 9 éléments, environ 63 frames par seconde, 0 exception ; écrire 9 entrées prend 6 ms ; quand le héros se déplace, le cercle, le texte et la barre de vie qui suivent l’unité restent bien calés. La texture n’est redessinée que si le contenu change ; un simple déplacement ne la redessine pas.
- Le dessin a lieu après l’interface du jeu et avant le curseur de la souris : il passe par-dessus les barres de vie, les unités et l’interface du jeu, et le curseur de la souris passe par-dessus lui. Il évite le panneau de commande en bas et l’horloge jour/nuit en haut, mais ne contourne pas les panneaux propres à la carte (classement, compte à rebours en haut à droite) — ne placez pas vos panneaux en haut à droite.
- Hors partie (menu principal, écran de fin de partie), les éléments placés sur des coordonnées du monde ou sur une unité ne sont pas dessinés ; ceux placés à une position de l’écran le sont normalement.
- Un cercle au sol est obtenu en projetant sur le sol chacun des 64 points de sa circonférence : si le terrain a du relief, la forme ondule avec lui — c’est voulu, il est dessiné sur le vrai sol.
- La première ouverture installe le hook et préchauffe les polices, environ 1 seconde ; pendant ce temps, les éléments de texte ne sont pas encore dessinés, mais les cercles et les lignes le sont.
- À la moindre exception pendant le dessin, plus rien n’est dessiné pour le reste de la session (même protection que pour les bulles au-dessus des unités) ;
faultsdansstats()passe alors à 1. - Textes, chemins d’images et points partagent 64 KB au total, avec 256 éléments au maximum ; les chemins d’images doivent être des chemins locaux lisibles par le processus du jeu.
Le panneau d’état du compagnon IA est dessiné avec le canevas : barre de vie, ce qu’il est en train de faire, humeur, éliminations et soins.