it-swarm.it

Come "appiattire" o "indicizzare" l'array 3D nell'array 1D?

Sto cercando di appiattire l'array 3D in un array 1D per il sistema "chunk" nel mio gioco. È un gioco a blocchi 3D e in pratica voglio che il sistema a blocchi sia quasi identico al sistema di Minecraft (tuttavia, non si tratta di un clone di Minecraft di alcuna misura). Nei miei precedenti giochi 2D ho accesso all'array appiattito con il seguente algoritmo:

Tiles[x + y * WIDTH]

Tuttavia, questo ovviamente non funziona con il 3D poiché manca l'asse Z. Non ho idea di come implementare questo tipo di algoritmo nello spazio 3D. Larghezza, altezza e profondità sono tutte costanti (e la larghezza è grande quanto l'altezza).

È solo x + y*WIDTH + Z*DEPTH? Sono piuttosto cattivo con la matematica e sto solo iniziando la programmazione 3D, quindi sono piuttosto perso: |

PS. Il motivo è che sto effettuando un ciclo e ricevendo cose da indice piuttosto da molto. So che gli array 1D sono più veloci degli array multidimensionali (per ragioni che non ricordo: P). Anche se questo potrebbe non essere necessario, voglio le migliori prestazioni possibili :)

19
user925777

L'algoritmo è per lo più lo stesso. Se si dispone di un array 3D Original[HEIGHT, WIDTH, DEPTH], è possibile trasformarlo in Flat[HEIGHT * WIDTH * DEPTH] by

Flat[x + WIDTH * (y + DEPTH * z)] = Original[x, y, z]

Per inciso, dovresti preferire le matrici di array su array multidimensionali in .NET. Le differenze di prestazioni sono significative

28

Ecco una soluzione in Java che offre entrambi:

  • da 3D a 1D
  • dalla 1D alla 3D

Di seguito è riportata un'illustrazione grafica del percorso che ho scelto per attraversare la matrice 3D, le celle sono numerate nel loro ordine di attraversamento:

 2 Examples of 3D matrices

Funzioni di conversione:

public int to1D( int x, int y, int z ) {
    return (z * xMax * yMax) + (y * xMax) + x;
}

public int[] to3D( int idx ) {
    final int z = idx / (xMax * yMax);
    idx -= (z * xMax * yMax);
    final int y = idx / xMax;
    final int x = idx % xMax;
    return new int[]{ x, y, z };
}
23
Samuel Kerrien

Penso che quanto sopra abbia bisogno di una piccola correzione. Diciamo che hai un'ALTEZZA di 10, e una LARGHEZZA di 90, l'array monodimensionale sarà 900. Con la logica sopra, se sei all'ultimo elemento dell'array 9 + 89 * 89, ovviamente questo è maggiore di 900. L'algoritmo corretto è:

Flat[x + HEIGHT* (y + WIDTH* z)] = Original[x, y, z], assuming Original[HEIGHT,WIDTH,DEPTH] 

Ironia della sorte se si raggiunge HEIGHT> WIDTH, non si verificherà un overflow, ma solo i risultati di bonkers;)

18
Martin

x + y*WIDTH + Z*WIDTH*DEPTH. Visualizzalo come un solido rettangolare: per prima cosa attraversi x, quindi ogni y è una "linea" width passi lunghi, e ogni z è un "piano" WIDTH*DEPTH passaggi nell'area.

11
Tom Zych

Ci sei quasi. È necessario moltiplicare Z per WIDTH e DEPTH:

Tiles[x + y*WIDTH + Z*WIDTH*DEPTH] = elements[x][y][z]; // or elements[x,y,z]
5
dlev

L'Algoritmo corretto è:

Flat[ x * height * depth + y * depth + z ] = elements[x][y][z] 
where [WIDTH][HEIGHT][DEPTH]
1
Beta-Logics

TL; DR

La risposta corretta può essere scritta in vari modi, ma mi piace di più quando può essere scritta in un modo che è molto facile da capire e visualizzare. Ecco la risposta esatta:

(width * height * z) + (width * y) + x

TS; DR

Visualizzalo:

someNumberToRepresentZ + someNumberToRepresentY + someNumberToRepresentX

someNumberToRepresentZindica quale matrice è attiva (depthname__). Per sapere su quale matrice ci troviamo, dobbiamo sapere quanto è grande ogni matrice. Una matrice è 2d dimensionata come width * height, semplice. La domanda da porsi è " quante matrici sono prima della matrice su cui sono attivo?" La risposta è zname__:

someNumberToRepresentZ = width * height * z

someNumberToRepresentYindica su quale riga si trova (heightname__). Per sapere su quale riga ci troviamo, dobbiamo sapere quanto è grande ogni riga: Ogni riga è 1d, dimensionata come widthname__. La domanda da porsi è " quante righe sono prima della riga in cui mi trovo?". La risposta è yname__:

someNumberToRepresentY = width * y

someNumberToRepresentXindica quale colonna è attiva (widthname__). Per sapere in quale colonna ci troviamo, usiamo semplicemente xname__:

someNumberToRepresentX = x

La nostra visualizzazione di

someNumberToRepresentZ + someNumberToRepresentY + someNumberToRepresentX

Diventa

(width * height * z) + (width * y) + x
1
Robert Plummer

Per capire meglio la descrizione dell'array 3D nell'array 1D sarebbe (suppongo che la profondità nella migliore risposta sia la dimensione Y)

IndexArray = x + y * InSizeX + z * InSizeX * InSizeY;

IndexArray = x + InSizeX * (y + z * InSizeY);
1
Evalds Urtans