BeeEngine logo BeeEngine JAVASCRIPT 2D ENGINE

Layer di disegno in JavaScript: y-sort e UI su Canvas

Documentazione – BeeEngine
v2.9.6

BeeLayer — Documentazione Tecnica

Pipeline di disegno: background, world, ysort, ui

📁 Panoramica

BeeLayer mette in ordine chi va disegnato, e in quale pass. Vive in src/graphics/BeeLayer.js. BeeEngine ne crea una: gioco.layers = new BeeLayer(). Il loop la chiama due volte: drawWorld sotto la camera, drawScreen dopo ctx.restore.

I quattro pass di default, in ordine:

Nome order Spazio Sort
background 0 mondo stabile
world 10 mondo stabile
ysort 20 mondo piedi, dal basso
ui 100 schermo stabile

Senza drawLayer l’entità sta su world. BeeText nasce già con drawLayer = 'ui'. Un layer aggiunto da te si infila in base a order: a parità vince chi è stato aggiunto prima.

BEE_LAYER di BeeRigidBody è un’altra cosa: bitmask della fisica (DEFAULT, PLAYER, WORLD, TRIGGER, PROJECTILE, GHOST). I pass di disegno sono le stringhe BEE_DRAW.

import { BeeEngine, BEE_DRAW } from ‘beeengine’; const gioco = new BeeEngine(‘testCanvas’, 800, 600); hero.drawLayer = BEE_DRAW.YSORT; gioco.layers.add(‘fx’, { space: ‘world’, sort: ‘stable’, order: 25 });

📁 Raccolta

collect legge currentScene.entities e poi engine.entities. L’ordine dentro la lista non sposta un figlio davanti al padre. La stessa entità nelle due liste entra una volta.

  1. 1. radiciSolo chi non ha parent. Da lì scende su children.
  2. 2. orfaniChi è in lista e non è ancora stato visto. Parte dal più alto antenato ancora in lista.
  3. 3. bucketRadice, oppure drawLayer diverso da quello ereditato. Poi la y-sort, se il pass è y.

Un figlio senza drawLayer, o con lo stesso del padre, resta fuori dal bucket. Lo disegna drawEntity mentre dipinge il padre, nello stesso pass. Un figlio con un drawLayer diverso entra nel suo pass: drawEntity sul padre lo salta, così non esce due volte.

La chiave y-sort è sortY se è un numero finito (anche 0). Altrimenti i piedi: il box di getEntityDrawBounds, se c’è, senno worldY + height (o y + height). A parità di chiave resta l’ordine di raccolta.

drawWorld raccoglie e disegna solo i pass world. drawScreen riusa quella raccolta e disegna solo i pass screen. Chiamata da sola, drawScreen raccoglie lei. ctx assente: il flush esce, i bucket restano.

📁 Nel frame

Sotto ctx.save e la camera: scenes.drawWorld (lo sfondo che metti tu sulla scena), poi layers.drawWorld, poi il callback render, poi l’overlay mondo di Ladybug. Dopo restore: layers.drawScreen, scenes.drawUI (scene.draw), ui.draw, i controlli touch, l’overlay di Ladybug.

drawEntity applica alpha se è sotto 1, e salta entity.draw quando il box ha larghezza e altezza e sta fuori vista (camera in mondo, canvas in schermo). I figli li visita lo stesso. Un box senza size viene disegnato. active === false non c’entra: ferma l’update, non il draw.

📁 Dove è facile sbagliare

Il cappello sta col corpo. Se padre e figlio hanno lo stesso drawLayer (o il figlio non lo ha), il figlio non ha una chiave y-sort sua. Esce dentro il draw del padre, in ordine di children. Per farlo mescolare con gli altri, il suo drawLayer deve essere un pass diverso, per esempio 'ysort' su un padre che resta su 'world'.

Padre invisibile o destroyed. Il sottoalbero non si disegna, anche se il figlio è in lista e ha drawLayer: 'ui'. Vale anche se il padre destroyed non è lui stesso in lista.

Padre fuori dalle liste. I figli che ci sono vengono disegnati come radici. Il padre no. I children di un prefab nascono con addToScene: false: li raggiunge la visita dal padre, se il padre è in scena.

Nome layer sconosciuto. Il nodo cade nel bucket world, se quel pass esiste. I figli ereditano però la stringa che hai scritto, non world. space: 'Screen' e sort: 'Y' non lanciano: diventano mondo e stabile. I valori letti sono 'screen', e 'y' oppure 'ysort'.

Dopo add il pass è fissato. get torna una copia. Per cambiare order, visible o sort fai remove e add. new BeeLayer({ defaults: false }) non installa i quattro pass: senza un layer world il fallback non ha dove andare.

📁 Esempio: corpo, cappello, etichetta

hero.drawLayer = BEE_DRAW.YSORT; const hat = new BeeEntity(4, –8, 12, 12); hero.addChild(hat); const label = new BeeText(‘HP’, 8, 8); hero.addChild(label);

hat non ha drawLayer: esce nel pass ysort del padre, insieme a lui. label è un BeeText, quindi 'ui': va nel pass schermo, dopo il restore. Il loop fa già drawWorld e drawScreen. renderEntities è solo la metà mondo.

📁 Riepilogo API

Non estende BeeEntity. BEE_DRAW, BEE_SPACE e BEE_LAYER_DEFAULTS escono dal barrel. I default di add sono spazio mondo, sort stabile, visibile, order 0.

Membro Ritorna Scopo
new BeeLayer({ defaults? }) BeeLayer defaults: false salta i quattro pass. Altrimenti li installa.
add(name, spec?) this Nome vuoto o già presente: lancia. spec: space, sort, order, visible.
remove(name) this Nome assente: nessun effetto.
has(name) / get(name) / list() boolean / copia / array get di un nome assente è null. list segue order.
size number Quanti pass, non quante entità.
items(name) array Entità dell’ultimo collect, già ordinate se il pass è y-sort. Nome assente: [].
collect(engine) this Svuota i bucket e li riempie. engine assente: liste vuote.
drawWorld(ctx, engine) this Raccoglie sempre, poi i pass mondo. Chiama engine.drawEntity, senno entity.draw.
drawScreen(ctx, engine) this Raccoglie solo se serve, poi i pass schermo. A fine chiamata la raccolta è da rifare al frame dopo.