如何在1D阵列中"展平"或"索引"3D阵列?

28 .net c# arrays 3d flatten

我试图在我的游戏中将3D阵列压平为1D阵列中的"块"系统.这是一个3D块游戏,基本上我希望块系统几乎与Minecraft的系统相同(但是,这不是Minecraft克隆的任何措施).在我以前的2D游戏中,我使用以下算法访问了扁平化数组:

Tiles[x + y * WIDTH]
Run Code Online (Sandbox Code Playgroud)

然而,这显然不适用于3D,因为它缺少Z轴.我不知道如何在3D空间中实现这种算法.宽度,高度和深度都是常量(宽度和高度一样大).

x + y*WIDTH + Z*DEPTH吗?我的数学非常糟糕,我只是开始进行3D编程,所以我很丢失:|

PS.这样做的原因是我循环并从索引中获取相当多的东西.我知道1D阵列比多维阵列更快(我记得的原因是:P).即使这可能没有必要,我希望尽可能好的表现:)

Gid*_*rth 34

算法大致相同.如果你有一个三维阵列Original[HEIGHT, WIDTH, DEPTH],那么你可以把它变成Flat[HEIGHT * WIDTH * DEPTH]

Flat[x + WIDTH * (y + DEPTH * z)] = Original[x, y, z]
Run Code Online (Sandbox Code Playgroud)

顺便说一下,你应该更喜欢.NET中多维数组的数组数组.性能差异很大

  • 如果HEIGHT对应于Y维度,则它应该是:`Flat [x + WIDTH*(y + HEIGHT*z)] =原始[x,y,z]` (13认同)
  • 你能指点一些来源讨论性能差异吗?此外,您不应仅仅根据绩效做出决定. (3认同)

Sam*_*ien 26

这是一个Java解决方案,它为您提供:

  • 从3D到1D
  • 从1D到3D

下面是我选择遍历3D矩阵的路径的图形说明,单元格按其遍历顺序编号:

2 3D矩阵的示例

转换功能:

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 };
}
Run Code Online (Sandbox Code Playgroud)

  • 此答案中不清楚 xMax 是指“WIDTH”还是“WIDTH-1” (5认同)

小智 24

我认为以上需要一点修正.假设您的高度为10,宽度为90,单维数组将为900.通过上述逻辑,如果您位于阵列9 + 89*89的最后一个元素,显然这大于900.正确的算法是:

Flat[x + HEIGHT* (y + WIDTH* z)] = Original[x, y, z], assuming Original[HEIGHT,WIDTH,DEPTH] 
Run Code Online (Sandbox Code Playgroud)

具有讽刺意味的是,如果您的高度>宽度,您将不会遇到溢出,只需完成疯狂的结果;)

  • 我无法对真实的正确答案进行投票或评论,但马丁认为它是正确的,目前选择的答案是错误的.基本上:data [x] [y] [z] = data [x + y*maxX + z*maxX*maxY] (3认同)

Tom*_*ych 11

x + y*WIDTH + Z*WIDTH*DEPTH.将其可视化为一个矩形实体:首先你遍历x,然后每个y是一个"线" width步长,每个z是一个"平面" WIDTH*DEPTH步骤区域.


Rob*_*mer 6

长话短说

正确答案可以用多种方式编写,但我最喜欢以易于理解和可视化的方式编写。这是确切的答案:

(width * height * z) + (width * y) + x
Run Code Online (Sandbox Code Playgroud)

TS;DR

可视化它:

someNumberToRepresentZ + someNumberToRepresentY + someNumberToRepresentX
Run Code Online (Sandbox Code Playgroud)

someNumberToRepresentZ指示我们位于哪个矩阵 ( depth) 上。要知道我们在哪个矩阵上,我们必须知道每个矩阵有多大。矩阵的二维大小为width * height,很简单。要问的问题是“我所在的矩阵之前有多少个矩阵?” 答案是z

someNumberToRepresentZ = width * height * z
Run Code Online (Sandbox Code Playgroud)

someNumberToRepresentY指示我们位于哪一行 ( height)。要知道我们在哪一行,我们必须知道每行有多大:每行都是 1d,大小为width。要问的问题是“我所在的行之前有多少行?”。答案是y

someNumberToRepresentY = width * y
Run Code Online (Sandbox Code Playgroud)

someNumberToRepresentX指示我们位于哪一列 ( width)。要知道我们在哪一列,我们只需使用x

someNumberToRepresentX = x
Run Code Online (Sandbox Code Playgroud)

我们的可视化然后

someNumberToRepresentZ + someNumberToRepresentY + someNumberToRepresentX
Run Code Online (Sandbox Code Playgroud)

成为

(width * height * z) + (width * y) + x
Run Code Online (Sandbox Code Playgroud)


dle*_*lev 5

你快到了.您需要通过乘ž WIDTH DEPTH:

Tiles[x + y*WIDTH + Z*WIDTH*DEPTH] = elements[x][y][z]; // or elements[x,y,z]
Run Code Online (Sandbox Code Playgroud)


小智 5

上面 Samuel Kerrien 的正向和反向变换几乎是正确的。下面包含一个更简洁的(基于 R 的)转换映射和一个示例(“a %% b”是表示 a 除以 b 的余数的模运算符):

dx=5; dy=6; dz=7  # dimensions
x1=1; y1=2; z1=3  # 3D point example
I = dx*dy*z1+dx*y1+x1; I  # corresponding 2D index
# [1] 101
x= I %% dx; x  # inverse transform recovering the x index
# [1] 1
y = ((I - x)/dx) %% dy; y  # inverse transform recovering the y index
# [1] 2
z= (I-x -dx*y)/(dx*dy); z  # inverse transform recovering the z index
# [1] 3
Run Code Online (Sandbox Code Playgroud)

请注意除法 (/) 和模数 (%%) 运算符。