La migliore tecnica per disegnare piastrelle isometriche


8

Sto pensando di creare un semplice gioco isometrico con HTML5 Canvas e mi chiedo quale sia il modo più veloce per eseguire il rendering delle tessere.

Poiché le piastrelle sono a forma di diamante, ma drawImage disegna rettangoli, devo lasciare fuori gli angoli (le parti nere di seguito):

piastrella diamantata campione

Penso che mi lasci con tre opzioni:

  1. Usa oggetti immagine con canali alfa (.png). Temo che questo potrebbe uccidere le prestazioni.
  2. Usa un tracciato di ritaglio. Se il renderer è ottimizzato, questo potrebbe essere piuttosto veloce.
  3. Piastrelle quadrate Prerender, in questo modo:

piastrelle quadrate prerenderizzate

Avrei il quadrato nero come una vera tessera in memoria, e disegnerei una tessera simile per il campo verde, e tutti i campi accanto ad esso, o sopra e sotto. I campi diagonali (blu) sarebbero costituiti dagli angoli delle piastrelle rettangolari. Ciò eviterebbe il clipping o i canali alfa, ma dovrei eseguire il prerender di tutte le possibili combinazioni di riquadri e sembra eccessivo.

Qual è il modo migliore o più veloce per fare tessere isometriche? Cosa usano altri giochi, come FarmVille?


1
Penso che la "migliore tecnica" sia un po 'caricata e dipenderà dai requisiti del gioco, dalla tecnologia utilizzata e dallo sviluppatore che crea il gioco.
MichaelHouse

1
Che problema stai effettivamente riscontrando? Sembra che tu abbia fornito tre risposte alla tua domanda all'interno del testo della domanda?
Trevor Powell,

1
Questo non ha abbastanza voti: BEST BEST BESSSSSSST! Argh?
Jimmy,

1
Immagino che dovresti seguire i consigli che trovi qui: meta.gamedev.stackexchange.com/a/638/7191
MichaelHouse

1
Quindi non sai che questo è in realtà un problema di prestazioni? Stai solo cercando di ottimizzare il codice prima che sia scritto? In tal caso, -1 e votazione per chiudere.
Trevor Powell,

Risposte:


11

L'uso della trasparenza (canale alfa) è la strada da percorrere, consiglio.

Ciò significa che quando si desidera un oggetto verticale sulla piastrella in questo modo:

piastrella con albero

Quindi puoi farlo facilmente se il tuo renderer disegna l'algoritmo di piastrelle in primo piano, cioè i pittori.

CREDITO IMMAGINE: Tileset di Reiner.


9

Mentre il metodo descritto da SWS e MarkR è anche quello che preferisco, vorrei presentare un approccio alternativo.

Un'opzione di hacking per la creazione di un look isometrico con il minimo sforzo è di utilizzare effettivamente le tessere ortogonali e utilizzare context.transform per impostare una matrice di proiezione che renda la mappa isometrica (o una combinazione di context.rotate e context.scale quando non si " so come funzionano le matrici di proiezione).

Vedi le specifiche per i metodi di trasformazione della tela per i dettagli.

Immagine della piastrella:

immagine della piastrella di base

Codice disegno:

    for (var x = 0; x < 5; x++) {
        for (var y = 0; y < 5; y++) {
            ctx.drawImage(img, x * img.width, y * img.height);
        }
    }

Risultato prima dell'applicazione matrice:

senza matrice di trasformazione applicata

Stesso codice con la stessa immagine della piastrella dopo aver applicato questa matrice di trasformazione:

    ctx.transform(  1,   0.5,
                   -1,   0.5,
                  160,   0    );

con matrice di trasformazione

Con la griglia tratteggiata rimossa dall'immagine della piastrella e modificato l'offset della piastrella nel codice di disegno in img.width - 1e img.height - 1per eliminare gli spazi vuoti causati dalla trasformazione. All'improvviso la tessera sembra metà brutta:

con matrice e alcune modifiche

Lo svantaggio principale di questo metodo è che quando si progettano le piastrelle in un editor grafico, non saranno realmente ciò che vedi. Incontrerai anche problemi quando vuoi disegnare oggetti che non sono sul pavimento ma in posizione verticale. Per questi puoi disattivare la matrice di trasformazione prima di disegnarli, ma dovrai calcolare tu stesso la posizione. Puoi usare queste formule per questo:

var xScreen = xWorld * 1   + yWorld * -1  + 160;
var yScreen = xWorld * 0.5 + yWorld * 0.5 + 0;  

(nota come i numeri dalla matrice di trasformazione riappaiono in queste formule: qui stai facendo la moltiplicazione della matrice).

Quindi perché dovrei farlo?

Questo metodo è utile quando:

  1. non hai esperienza con la progettazione di tessere isometriche, ma ne hai di ortogonali
  2. non voglio dedicare molto tempo allo sviluppo di un motore grafico isometrico, che è un po 'più difficile di un motore ortogonale.

Un'altra caratteristica interessante è che quando sai come aggirare il calcolo della matrice, puoi modificare la matrice di proiezione tra i fotogrammi per ingrandire, inclinare e ruotare la mappa in tempo reale per alcuni effetti 3D fasulli (prova a farlo con tessere isometriche) .

Ma quando sai come gestire le piastrelle isometriche, sia dal punto di vista artistico che tecnico, e non hai bisogno di trucchi dalla prospettiva falsa, ti suggerisco piuttosto di scegliere piastrelle a forma di diamante con trasparenza.


È certamente possibile farlo. In questo modo puoi avere tessere "piatte" o "dall'alto verso il basso". Tuttavia, significa che qualsiasi elemento "3d" nelle tessere non può essere fatto facilmente. Preferisco fare questa trasformazione in anticipo.
Mark R

+1 se non solo per la spiegazione degli esperti! Molto bene.
Luceos,

@MarkR: ho ampliato molto la mia risposta dopo aver fatto il tuo commento, potresti voler dare un'occhiata se è ancora valido.
Philipp

1
Grazie per il resoconto dettagliato! È una tecnica molto interessante, non ci avevo pensato prima. Tuttavia, poiché sto iniziando da zero (e sono ugualmente cattivo nel disegnare piastrelle isometriche e quadrate ;-)), andrò per vere piastrelle isometriche. Inoltre, questo non sembra essere molto veloce. Ho fatto un piccolo punto di riferimento e mescolare le tessere senza una matrice di trasformazione in posizioni di pixel interi è circa 3 volte più veloce rispetto alla trasformazione sul mio PC. Potrei comunque usarlo per alcuni effetti speciali.
jdm,

Qualche modo per aggiungere un po 'di livello z a questa mappa?
Tarion,

3
  1. Stai utilizzando context.drawImage per copiare i dati dei pixel da una sorgente (Immagine o tela fuori schermo) a un'altra (tela fuori schermo o su schermo), che gestisce alfa con garbo e pronto all'uso. La tela è accelerata dall'hardware, quindi i test ti permetteranno di determinare se c'è una differenza evidente nelle velocità di rendering rispetto ai pixel alfa o opachi.

  2. Il ritaglio richiede di spingere / far apparire lo stato del contesto quando si definisce un tracciato di ritaglio una volta per riquadro, che potrebbe essere un'operazione costosa considerando il superamento isometrico.

  3. Le tessere prerenderizzate, come dici tu, richiederebbero un numero immenso di tessere "connettore" da disegnare, che possono o meno essere fattibili. (Sono più incline a "forse non").

Una quarta soluzione sarebbe quella di adottare un "blocco" pre-renderizzato (PRC) di tessere, generato una volta per tele fuori schermo, e quindi coprire lo schermo con i PRC una volta per fotogramma. Ci sarebbe ancora un sovraccarico, ma costruire una volta il PRC e renderlo con un offset determinato dalla posizione del personaggio del giocatore (o visualizzare la telecamera) rispetto al PRC dovrebbe essere un'operazione relativamente semplice. Ciò consentirebbe di combinare il rendering con l'opzione n. 1, che è la migliore opzione IMO se le prestazioni non fossero considerate (poiché è più semplice da implementare).


3

Un piccolo canale alfa non fa molto male, ma se vuoi evitarlo considera l'uso di tessere da due quarti, questo ti dà anche un po 'di spazio per fare belle transizioni di tessere senza fare una pletora di immagini diverse, questo è probabilmente il più grande vantaggio:

Modello rettangolare sottotegola

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.