2013-01-23 8 views
8

Ho problemi con le pareti isometriche.Disegno pareti isometriche

Sto disegnando le piastrelle del pavimento isometriche utilizzando il metodo di rendering dal retro al fronte e funziona perfettamente. Tengo anche le mie piastrelle del pavimento allineate correttamente in una bella griglia. Il codice (e questo sembra essere piuttosto standard per il disegno piano isometrico) è la seguente:

for(int x = 0; x < 6; x++){ 
    for(int y = 3; y >=0 ; y--){ 

     int xCo = (y+x)*(tileWidth/2); 
     int yCo = (x-y)*(tileHeight/2); 
     tile.draw(g, xCo, yCo); 
    }    
} 

Questo rende un bel po 'di piano:

multiple floor tiles

La griglia è costruito da questa tessera :

A single tile

Purtroppo, quando uso la stessa logica per le pareti, tutto va righ t all'inferno.

for(int x = 0; x < 6; x++){ 
    for(int y = 3; y >= 0 ; y--){ 

     int xCo = (y+x)*(wallWidth()/2); 
     int yCo = (x-y)*(wallHeight()/2); 
     walls.draw(g, xCo, yCo);  
} 
} 

sto usando questo come il mio rivestimento parete:

Single wall tile

(si tratta di un segnaposto di Google la ricerca di immagini, ma dovrebbe funzionare lo stesso)

Questa è la risultato che ottengo:

Multiple wall tiles

L'ordine di rendering per le mie pareti è chiaramente corretto, le pareti più vicine rendono sopra pareti più lontane, che è quello che voglio, ma il posizionamento è anche dolorosamente scorretto, e non so esattamente come dovrei correggere quel corto usando i valori dei pixel.

Per riferimento, ho eseguito una prova utilizzando pixel val di codice hard, poiché ho trovato che dall'angolo destro di una parete all'angolo destro della parete successiva, la modifica era esattamente (200, -100) pixel. Quando ho fatto il mio conto ciclo di rendering per quella

int xCo = (x+y)*200; 
int yCo = (y-x)*-100; 

ha funzionato bene, ma che non è una soluzione praticabile in quanto non consente alcuna versatilità.

Quindi, sto cercando suggerimenti su come allineare le mie pareti isometriche. Che cosa sto facendo di sbagliato?

Grazie!

+0

Grazie per aver reso visibili le mie foto. Ho postato anche su gamedev.stackexchange e sono estremamente restrittivi su link e immagini, quindi non ho provato qui. –

+0

Ho notato un motivo con le pareti: il bordo orizzontale superiore anteriore della prima parete è collineare con il bordo orizzontale inferiore anteriore della terza parete. Inoltre, il bordo verticale anteriore destro della prima parete è collineare con il bordo verticale posteriore sinistro della terza parete. Lo stesso vale per la seconda e quarta parete. Quindi sono un po 'in fila. Solo non nel modo che vuoi. – Kevin

+0

Haha sì, è vero.In questo mi consolerò, ma non sono sicuro di cosa farne a parte "il mio metodo è solo a metà sbagliato" –

risposta

2

Non si può semplicemente utilizzare lo stesso codice di disegno per pareti come per pavimenti perché le pareti e pavimenti non sono sullo stesso piano: pavimenti sono piatte (orizzontale) mentre le pareti sono verticali. Quindi devi disegnarli in modo leggermente diverso.

vostre coordinate X e Y, nel caso piano significano qualcosa come "destra/sinistra" e "avanti/indietro" in termini di posizionamento delle piastrelle. Per i mattoni, sinistra e destra hanno ancora senso, ma vogliamo sostituire avanti/indietro con su e giù per riflettere la direzione verticale. Quindi la nostra "y" ha un nuovo significato.

Ora, in matematica, l'asse y di solito rivolta verso l'alto, mentre in grafica 2D per computer è rivolta verso il basso. Puoi scegliere: il codice sottostante presuppone che punti verso l'alto in modo che y = 0 significhi "al livello del pavimento".

Quindi iniziamo a pensare all'ordine. Il mattone di esempio che hai pubblicato è per un muro che sarebbe l'estremità sinistra (in alto) di un piano. A causa delle parti nere del mattone (la profondità del muro), dobbiamo assicurarci di disegnare i mattoni che sono più a destra prima in modo che la profondità nera sul lato sinistro sia coperta da mattoni più vicini. Lo stesso argomento vale per il nero sulla parte superiore del muro, dobbiamo prima disegnare i mattoni inferiori.

Se ci atteniamo alle direzioni x e y come discusso prima (x va da sinistra a destra, y va dal basso verso l'alto), questo significa che dobbiamo eseguire entrambi i nostri punti di forenza in direzioni negative:

for (int y = 3; y >= 0; y--) { 
     for (int x = 5; x >= 0; x--) { 
      ... 
     } 
    } 

la questione principale è ora quanto abbiamo per compensare il disegno di ogni mattone rispetto agli altri mattoni. Facciamo una sola direzione alla volta, iniziando dalla direzione x.

Immaginiamo solo due mattoni uno accanto all'altro:

two bricks horizontally

La sinistra dei due ha la parte di profondità nera visibile ma il diritto non si dovrebbe vedere.Quindi non possiamo semplicemente compensare l'immagine giusta per l'intera larghezza del PNG. In effetti, supponendo che i mattoni si allineino con le piastrelle del pavimento, la larghezza della parte anteriore effettiva del muro dovrebbe essere uguale alla metà della larghezza di una piastrella.

int xCo = x * tileWidth/2; 

La profondità muro nero a sinistra non dovrebbe essere ignorato, perché probabilmente vogliamo per compensare ogni mattone un po 'a sinistra in modo che la coordinata x del angolo anteriore delle linee parete al passo con i piastrelle del pavimento, non la coordinata x dell'angolo posteriore.

Ora, la coordinata y di ogni mattone è un po 'più complicata perché non dipende solo dalla riga del mattone, dipende anche dalla coordinata x: più a destra più in alto dovremmo disegnare. Ma ignoriamo direzione x per un attimo e cercare di disegnare semplicemente una colonna di mattoni:

two bricks vertically

Nuovamente, il delta tra le coordinate y dei due mattoni non è l'altezza del PNG . A differenza del caso di sinistra/destra in cui abbiamo ipotizzato che i mattoni si allineano con le tessere che ci hanno permesso di usare tileWidth come delta-x, i mattoni possono avere altezze arbitrarie. Ma possiamo ancora calcolare l'effettiva altezza del mattone dall'altezza dell'immagine perché sappiamo che la profondità sul lato sinistro e la profondità sulla parte superiore devono essere allineate.

Se osserviamo il piccolo triangolo trasparente nell'angolo in alto a destra del PNG di mattoni, notiamo che il rapporto tra larghezza e altezza deve essere uguale al rapporto tra larghezza e altezza di una piastrella. Che ci permette di calcolare una YOffset dal xoffset calcolato sopra, e di utilizzare quella di dedurre l'altezza effettiva del mattone:

int yoffset = xoffset * tileHeight/tileWidth; 
int wallHeight = wallHeight() - tileHeight/2 - yoffset; 

Si noti che questo funziona solo sotto l'ipotesi che non c'è spazio vuoto al confine il PNG e potrebbe ancora fallire a causa di errori di arrotondamento. Quindi potresti aggiungere uno Math.ceil() (o semplicemente + 1) qui se necessario.

Quindi per le colonne semplici, siamo a posto ora: possiamo semplicemente moltiplicare la nostra variabile con il precedente wallHeight. Ma come notato prima, la posizione x di un mattone influenza anche la coordinata del pixel y. Se guardiamo di nuovo la prima immagine con i due mattoni uno accanto all'altro, quanto abbiamo dovuto spostare il mattone destro per allineare il mattone sinistro? Bene, questo è in realtà facile, perché è lo stesso delle piastrelle del pavimento: metà dell'altezza di una piastrella!

Quindi siamo a posto. Se mettiamo tutto insieme, si finisce con un po 'di codice come questo:

int xoffset = wallWidth() - tileWidth/2; 
int yoffset = xoffset * tileHeight/tileWidth; 
int wallHeight = wallHeight() - tileHeight/2 - yoffset; 

for (int y = 3; y >= 0; y--) { 
    for (int x = 5; x >= 0; x--) { 

     int xCo = x * tileWidth/2; 
     int yCo = y * wallHeight - x * tileHeight/2; 

     walls.draw(g, xCo - xoffset, yCo - yoffset); 
    } 
} 

(sto supponendo che wallWidth() e wallHeight() restituiscono la larghezza e l'altezza del mattone PNG.)

Si noti che le tre costanti prima dei cicli for possono essere spostate fuori dal codice di disegno effettivo - dipendono solo dalle proprietà dell'immagine e da altre costanti e non devono essere ricalcolate ogni volta che si disegna il muro.

+0

Quindi, prima di tutto voglio ringraziarvi per una risposta incredibilmente accurata. Sei una specie di mago. Ma io sono di spessore, e ho ancora bisogno di aiuto La prima cosa è la prima, non capisco cosa sta succedendo qui: "In realtà, supponendo che i mattoni si allineano con le piastrelle del pavimento, la larghezza del reale la parte anteriore del muro dovrebbe essere uguale alla metà della larghezza di una piastrella. " Se sono allineati, la loro larghezza non dovrebbe essere la stessa? Inoltre, potresti spiegare come ottenere la coordinata y del muro se li voglio allineati invece che accatastati? La tua prima immagine dei due muri fianco a fianco è ciò che sto andando. –

+0

Inoltre, ho w dovrei gestire le coordinate x se i muri non sono allineati con le piastrelle del pavimento? Come posso gestire i muri in modo indipendente, in pratica. –

+1

Nessun problema: se non hai bisogno che i muri siano impilati, sostituisci semplicemente il ciclo esterno con 'int y = 0'. A parte questo, hai provato il codice e vedi se fa qualcosa di simile a quello che vuoi? Potrebbe essere più facile copiarlo e incollarlo, quindi iniziare a giocarci. --- Per quanto riguarda la tua domanda con le larghezze: il problema qui è che a volte uso la larghezza della parola per riferirsi alla larghezza di un muro o di una tessera, e talvolta alla larghezza dell'immagine. A causa della vista isometrica queste due larghezze sono diverse. Nella frase citata, mi riferisco alle larghezze dell'immagine. – Thomas

0

Se si guarda la piastrella del pavimento che ha la forma di un diamante, spostandola di mezza larghezza e di larghezza pari a metà, i due bordi si allineano.
La tessera del muro non è un diamante, quindi spostando la metà larghezza e l'altra metà della lunghezza i bordi che si desidera abbinare non si allineano.

Dato u = distanza per muoversi attraverso e v = distanza a muoversi su e A l'angolo isometrica

v = u*tan(A)

u in questo caso è la larghezza della faccia anteriore dell'immagine.

se faccia (il bit texture) dell'immagine muro corrisponda alla lunghezza del bordo della piastrella questo dà

int offset = ?;// this is the width of the black stripe on the image. 

for(int x = 0; x < 6; x++){ 
    for(int y = 3; y >=0 ; y--){ 

     int xCo = ((y+x+1)*(tileWidth/2))-offset; 
     int yCo = (x-y)*(tileHeight/2); 
     wall.draw(g, xCo, yCo); 
    }    
} 
+0

Posso lavorare con questo. Sono al telefono, quindi lo proverò più tardi, ma grazie! Voglio assicurarmi di avere chiari termini qui: Quando dici "se la faccia dell'immagine corrisponde alla lunghezza del bordo della piastrella" a cosa ti riferisci esattamente? Ci sono troppi significati possibili per me per essere sicuri (la larghezza dell'immagine che è rettangolare, la lunghezza effettiva della tessera che è difficile da scoprire e fastidiosa perché non è quadrata, ecc.). Grazie ancora! –

+1

Intendevo la trama sull'immagine del muro, a differenza della parte nera della profondità. Per il bordo della tessera pavimento intendo la linea tra due punti adiacenti sul diamante, non i lati del rettangolo che contiene l'immagine. – BevynQ

+0

quindi ho solo bisogno di rendere l'offset una frazione consistente della larghezza dell'immagine, in modo che possa accettare più immagini fatte con le stesse specifiche, giusto? –

0

In un regno isometrica, ci sono tre assi si può posizionare in - Z per un massimo e giù, X e Y per le tue 'diagonali'.

Innanzitutto, immaginiamo la rappresentazione di pixel di un'unità 1 di 1 unità di 1 unità isometrico cubo, con tutte le parti rappresentate altrettanto lunga:

sarebbe un pixel di altezza sull'asse Z. Anche gli altri suoi bordi sarebbero di lunghezza pari a A, ma ruotati di 60 gradi, quindi sarebbe peccato (30) * A pixel alti e cos (30) * A pixel lunghi nelle direzioni X e Y - ovvero 0.5 * A e sqrt (3)/2 * A.

Così, per posizionare un oggetto cubo dimensioni isometrica in X, Y e Z dobbiamo tradurre la sua sullo schermo x ed y dal seguente:

y += Z*A 
x += X*A/2 - Y*A/2 
y += (X+Y)*A*sqrt(3)/2 

Finché le ipotesi ho fatto tenere questa dovrebbe lavoro.

EDIT: A proposito, A dovrà essere codificato duro se l'immagine ha profondità e quindi non è possibile estrarre automaticamente A dalle dimensioni dell'immagine.