BeeGrid — Documentazione Tecnica
Griglia logica a celle: ostacoli, coordinate e algoritmi di posizionamento
📁 Panoramica
BeeGrid è la griglia logica di BeeEngine: divide lo spazio di gioco in celle quadrate e tiene uno stato per ogni cella (vuoto, ostacolo, tipo di tile, costo di pathfinding, e così via). Non è una tilemap grafica: non carica texture e non sa come si disegna una cella. Tiene solo i numeri.
La classe è intenzionalmente piccola. Il costruttore alloca la matrice, setCell / getCell la leggono e la scrivono con controlli di bound, e draw delega il rendering a una funzione che passi tu. Se ti serve una mappa visiva con sprite, quella è BeeTilemap. Qui stai lavorando sulla geometria dello spazio.
📁 Ordine degli assi: colonna, poi riga
Questo è il punto dove è più facile sbagliare. La matrice interna è data[riga][colonna], ma i metodi pubblici accettano prima la colonna e poi la riga: setCell(c, r, val) e getCell(c, r). È la convenzione canvas (x, y): la colonna cresce verso destra, la riga verso il basso.
Se inverti gli argomenti, su una griglia non quadrata (per esempio 20×12) non prendi un errore: scrivi in una cella sbagliata e il gioco “funziona” in modo storto. Controlla sempre l’ordine prima di incolpare il pathfinding.
📁 Bound sicuri su setCell e getCell
Entrambe le funzioni controllano che la riga esista (this.data[r]) e che la colonna stia in [0, cols). Fuori dai bordi setCell non fa nulla e getCell ritorna null — non 0. Zero è una cella valida (vuota di default); null significa “questa coordinata non esiste”.
Non usare getCell come se tornasse sempre un numero. Se stai facendo pathfinding o collisioni, distingue i due casi, altrimenti tratti una cella fuori mappa come ostacolo o come spazio libero a seconda di come interpreti null.
📁 Disegno: tu passi la funzione, BeeGrid scorre le celle
draw(ctx, drawFunction) non dipinge da sola. Scorre tutte le celle e per ognuna chiama drawFunction(ctx, x, y, valore), dove x e y sono già in pixel: c * cellSize e r * cellSize. Il valore è quello salvato in data[r][c].
Due conseguenze pratiche. La prima: se la griglia è 40×30 stai facendo 1.200 callback ogni frame. Per una griglia di debug va bene; per un livello grande conviene disegnare solo le celle visibili (culling) fuori da questa classe, oppure non chiamare draw ogni frame. La seconda: drawFunction deve esistere. Se passi undefined, il ciclo parte e va in errore alla prima cella.
📁 Da pixel a cella (e ritorno)
BeeGrid non ha un metodo worldToCell. La conversione la fai tu con la divisione intera:
Il contrario è quello che fa già draw: x = c * cellSize, y = r * cellSize. L’origine della griglia è in alto a sinistra dello spazio mondo, allineata a (0, 0). Se la mappa è spostata (camera, offset di livello), devi sottrarre quell’offset prima di convertire, altrimenti le celle “camminano” rispetto agli sprite.
📁 Esempio pratico
📁 Perché è scritto così — note per chi integra
Zero è il default, non “mancante”. Ogni cella nasce a 0. Se 0 per te è “camminabile”, va bene. Se 0 per te è “non inizializzata”, non hai modo di distinguerla da una cella vuota voluta: scegli un altro sentinella (per esempio -1) e usalo tu.
Nessuna copia difensiva di data. griglia.data è l’array vivo. Puoi leggerlo per un algoritmo A*, ma se lo rimpiazzi o gli cambi la forma, setCell e draw smettono di essere coerenti con cols / rows.
Non ridimensiona a caldo. Cambiare cols o rows dopo il costruttore non rialloca la matrice. Per una mappa nuova crea un altro BeeGrid.
Non è BeeTilemap. Qui non ci sono tileset, culling, layer o collisioni automatiche. È un contenitore 2D + un loop di disegno. Tienila così: se ci metti dentro il rendering delle texture, duplichi BeeTilemap e perdi la chiarezza.
📁 Riepilogo API
| Membro | Ritorna | Scopo |
|---|---|---|
constructor(cols, rows, cellSize) |
BeeGrid |
Alloca una matrice rows × cols riempita di 0. |
cols / rows / cellSize |
number |
Dimensioni della griglia e lato in pixel di una cella. |
data |
number[][] |
Matrice viva data[r][c]. Non è una copia. |
setCell(c, r, val) |
void |
Scrive il valore se la cella esiste. Fuori bound: no-op. |
getCell(c, r) |
any | null |
Legge la cella. Fuori bound ritorna null, non 0. |
draw(ctx, drawFunction) |
void |
Per ogni cella chiama drawFunction(ctx, x, y, val) in pixel. |
