Jak "spłaszczyć " lub" indeks " tablicę 3D w tablicy 1D?

Próbuję spłaszczyć tablicę 3D do tablicy 1D dla systemu "chunk" w mojej grze. Jest to gra 3D-block i w zasadzie chcę, aby system chunk był prawie identyczny z systemem Minecraft (jednak nie jest to klon Minecraft w żadnym stopniu). W moich poprzednich grach 2D uzyskałem dostęp do spłaszczonej tablicy z następującym algorytmem:

Tiles[x + y * WIDTH]

To oczywiście nie działa z 3D, ponieważ brakuje w nim osi Z. Nie mam pojęcia jak zaimplementować tego typu algorytm w przestrzeni 3D. Szerokość, wysokość i głębokość są stałymi (a szerokość jest tak samo duża jak wysokość).

Czy to tylko x + y*WIDTH + Z*DEPTH ? Jestem dość kiepski z matematyką i dopiero zaczynam programowanie 3D, więc jestem dość zagubiony : /

PS. Powodem tego jest to, że często zapętlam i otrzymuję rzeczy według indeksu. Wiem, że tablice 1D są szybsze niż tablice wielowymiarowe (z powodów, których nie pamiętam :P). Mimo, że to może nie być konieczne, chcę jak najlepszego wykonania:)

Author: Tom Zych, 2011-09-10

8 answers

Algorytm jest w większości taki sam. Jeśli masz tablicę 3D Original[HEIGHT, WIDTH, DEPTH], możesz przekształcić ją w Flat[HEIGHT * WIDTH * DEPTH] przez

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

Na marginesie powinieneś preferować tablice tablic zamiast wielowymiarowych tablic w .NET. różnice w wydajności są znaczące

 29
Author: Gideon Engelberth,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-09-09 21:46:49

Oto rozwiązanie w Javie, które daje Ci oba:

  • od 3D do 1D
  • od 1D do 3D

Poniżej znajduje się graficzna ilustracja ścieżki, którą wybrałem do przemierzania macierzy 3D, komórki są ponumerowane w kolejności ich przemierzania:

2 Przykłady matryc 3D

Funkcje konwersji:

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 };
}
 21
Author: Samuel Kerrien,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-12-18 20:08:43

Myślę, że powyższe wymaga małej korekty. Powiedzmy, że masz wysokość 10, a szerokość 90, tablica jednowymiarowa będzie 900. Według powyższej logiki, jeśli jesteś na ostatnim elemencie tablicy 9 + 89*89, oczywiście jest to ponad 900. Prawidłowy algorytm to:

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

Jak na ironię jeśli masz wysokość > szerokość nie doświadczysz przepełnienia, po prostu wypełnij bonkers wyniki;)

 18
Author: Martin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-05-17 13:41:44

x + y*WIDTH + Z*WIDTH*DEPTH. Wizualizuj go jako prostokątną bryłę: najpierw przemierzasz wzdłuż x, Następnie każdy y jest "linią" width, a każdy z jest "płaszczyzną" WIDTH*DEPTH w obszarze.

 12
Author: Tom Zych,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-09-09 21:46:30

Już prawie jesteś. Musisz pomnożyć Z przez WIDTH oraz DEPTH:

Tiles[x + y*WIDTH + Z*WIDTH*DEPTH] = elements[x][y][z]; // or elements[x,y,z]
 6
Author: dlev,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-09-09 21:46:02

Aby lepiej zrozumieć opis tablicy 3D w tablicy 1D byłoby (myślę, że głębokość w najlepszej odpowiedzi oznacza rozmiar Y)

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

IndexArray = x + InSizeX * (y + z * InSizeY);
 1
Author: Evalds Urtans,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-02-07 15:45:12

Prawidłowy algorytm to:

Flat[ x * height * depth + y * depth + z ] = elements[x][y][z] 
where [WIDTH][HEIGHT][DEPTH]
 1
Author: Beta-Logics,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-03-13 10:20:23

TL;DR

Poprawną odpowiedź można napisać na różne sposoby, ale najbardziej lubię, gdy można ją napisać w sposób bardzo łatwy do zrozumienia i wizualizacji. Oto dokładna odpowiedź:

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

TS; DR

Visualize it:

someNumberToRepresentZ + someNumberToRepresentY + someNumberToRepresentX

someNumberToRepresentZ wskazuje, na której macierzy jesteśmy (depth). Aby wiedzieć, na której macierzy jesteśmy, musimy wiedzieć, jak duża jest każda macierz. Macierz ma rozmiar 2d width * height, prosty. Pytanie brzmi: "ile macierzy jest przed matrix, na którym jestem?"Odpowiedź brzmi z:

someNumberToRepresentZ = width * height * z

someNumberToRepresentY wskazuje, w którym wierszu jesteśmy (height). Aby wiedzieć, w którym rzędzie jesteśmy, musimy wiedzieć, jak duży jest każdy wiersz: każdy wiersz to 1D, wielkości width. Pytanie brzmi: "ile wierszy jest przed rzędem, w którym jestem?". Odpowiedź brzmi y:

someNumberToRepresentY = width * y

someNumberToRepresentX wskazuje, na której kolumnie jesteśmy (width). Aby dowiedzieć się, na której kolumnie jesteśmy, wystarczy użyć x:

someNumberToRepresentX = x

Nasza wizualizacja wtedy z

someNumberToRepresentZ + someNumberToRepresentY + someNumberToRepresentX

Staje się

(width * height * z) + (width * y) + x
 0
Author: Robert Plummer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-07-09 19:02:01