设置多维数组而不进行数据复制

时间:2017-03-12 03:53:36

标签: c# unity3d multidimensional-array

我很难弄清楚如何正确设置我的阵列。

我有一个基本的图块阵列设置到我的数组grid[,]这很好。

现在我正在尝试为网格之间的边缘制作一个数组,这样我就可以放下墙了。

所以我有这个:walls[,][,]其中每个[,]是一个网格位置,因此每个墙分隔2个网格位置。

这里的最终目标是我想要一个带有两个网格点的墙阵列,如AB,这样我就可以这样做:

Wall wallObject = walls[A.x,A.y][B.x,B.y];

希望这是有道理的。我尝试过这样的事情:

' 现在,因为每1个瓷砖可以有4个墙,我试图像这样设置我的墙阵列但是无法正确地解决语法:

grids = new Tile[x,y];
walls = new Wall[grids.GetLength(0), grids.GetLength(1)][walls.GetLength(0) * 4, walls.GetLength(1) * 4]; // invalid rank specifier ERROR

for(int i = 0; i < x; i++) {
for(int j = 0; j < y; j++) {

   grids[i, j] = new Tile(new Vector3(i, 0, j));
   foreach (Vector3 gridNeighbour in AdjacentTiles(new Vector3(i, 0, j))) //4 directions
   {
      if (!InGrid(gridNeighbour)) continue;    
      walls[i, j][(int)gridNeighbour.x, (int)gridNeighbour.z] = new Wall(grid[i,j],grid[(int)gridNeighbour.x,(int)gridNeighbour.z]);
   }

}}

我在第二行收到错误,不确定正确的写入方式。 我也相当确定我的逻辑是错误的,因为我认为这样的数据设置会为我的墙提供双倍数据,这样我就可以得到wall[gridA][gridB]wall[gridB][gridA]我想避免但我不会#39 ;我知道如何。

2 个答案:

答案 0 :(得分:1)

直接提出问题,基本问题是你并没有真正尝试创建一个4维数组。相反,您正在尝试创建二维数组的二维数组。

如果你想这样做,你需要先分配顶级二维数组,然后用其他二维数组元素填充它:

walls = new Wall[grids.GetLength(0), grids.GetLength(1)][,];

for (int i = 0; i < grids.GetLength(0); i++)
for (int j = 0; j < grids.GetLength(1); j++)
{
    walls[I, j] = new Wall[grids.GetLength(0) * 4, grids.GetLength(1) * 4];
}

或者,您可以创建一个真正的四维数组:

Wall[,,,] walls = new Wall[grids.GetLength(0), grids.GetLength(1),
                           grids.GetLength(0) * 4, grids.GetLength(1) * 4];

尽管如此,这两种方法对我来说都是非常浪费的。这些数组中的绝大多数元素都将被闲置。你只关心每个瓷砖四面墙,那么为什么不每个瓷砖只存储四个?例如:

Wall[,,] walls = new Wall[x, y, 4];

(而不是使用GetLength(),我只是重复使用原始代码中的xy变量来定义网格的尺寸。)

然后编写一个辅助方法,给定两个不同单元格的x / y位置,将返回相关墙的索引。这是解决问题的一种方法:

private static readonly int[,] directions =
{
    { 0, -1 },
    { 1,  0 },
    { 0,  1 },
    {-1,  0 }
};

int GetWallIndex(int x0, int y0, int x1, int y1)
{
    int dx = x0 - x1, dy = y0 -y1;

    for (int i = 0; i < 4; i++)
    {
        if (directions[i, 0] == dx && directions[i, 1] == dy)
        {
            return i;
        }
    }

    return -1;
}

上面的GetWallIndex()方法将返回相关Wall对象的相应索引,如果您传递实际上不相邻的切片的位置,则返回-1。然后,您可以在三维Wall[,,]数组中使用该索引来获取有问题的Wall对象。

这仍然无法复制Wall数据,即墙壁两侧的每个单元一次。恕我直言,这是一个小小的让步,特别是如果Wall对象是引用类型(因此唯一重复的是引用本身)。但是,通过将数据存储在字典中并在查找时对图块坐标进行标准化,可以消除这种低效率。例如:

struct WallAddress
{
    public int X0 { get; }
    public int Y0 { get; }
    public int X1 { get; }
    public int Y1 { get; }

    public WallAddress(int x0, int y0, int x1, int y1)
    {
        // Optional, not shown here:
        // Validate addresses to make sure they represent adjacent tiles

        if (x1 < x0 || (x1 == x0 && y1 < y0))
        {
            int xT = x0, yT = y0;

            x0 = x1;
            x1 = xT;
            y0 = y1;
            y1 = yT;
        }

        X0 = x0;
        Y0 = y0;
        X1 = x1;
        Y1 = y1;
    }
}

Dictionary<WallAddress, Wall> walls = new Dictionary<WallAddress, Wall>();

然后,您只需为每个WallAddress对象创建一对图块的Wall值,然后填写字典。

答案 1 :(得分:1)

与Java不同,您可以执行以下操作:

walls = new Wall[x][y][x2][y2];

C#不会让你这样初始化。有一种方法可以使Wall[,][,]起作用,但是制作Wall[,,,]的4维数组要容易得多。

然而,这甚至都行不通,因为如果你真的想用[reallybignumber]维度数组做这样的事情(我不确定这是最好的方法,但让我们去吧) ,你需要一个Wall[,,,,]数组来存储x1,y1,x2,y2和墙面方向。

虽然这会花费最多的速度(可能?我实际上并不知道C#中多维数组的性能影响),如果你只是去,你会节省很多内存(和理智)像Peter Duniho的回答一样的字典和结构。