【问题标题】:Implementation of array with negative indices负索引数组的实现
【发布时间】:2012-08-06 23:00:23
【问题描述】:

我正在制作一款游戏,其世界向各个方向无限延伸。这意味着您可以在位置X:50、Y:50 或X:-50、Y:-50。但是......我真的不能用普通的 C# 列表来做到这一点......

我提出的所有想法似乎都太复杂/效率低下...

【问题讨论】:

  • 通常用取模运算符实现
  • 想详细说明一下吗?
  • 别在意我上面的评论,我在想别的东西。请参阅下面的答案。
  • 计算机无法存储无限数组,这是错误的代码编写模式。

标签: c# arrays


【解决方案1】:

实现无限网格的最简单方法是使用带有字典的稀疏矩阵,其中 x,y 对作为键,您要存储的数据作为值。如果您的网格是稀疏的,这将快速、易于实现且内存友好。

另一种方法是链接网格(类似于链表,但具有指向 4 个方向的指针),或基于图块的方法来减少链接网格的开销(图块是 NxN 数组的链接网格)。瓦片的实现相当复杂,但对于非常密集的网格来说,它是内存和性能之间的良好折衷。

但我个人最喜欢的方法是使用奇偶变换。所以奇数指数是正数,而偶数指数是负数。要从虚拟索引转换为物理索引,您可以使用公式p = abs(v * 2) - (v > 0 ? 1 : 0) 并将物理索引转换为虚拟索引,您可以使用v = (p % 2 == 1 ? +1 : -1) * ((2*p + 3) / 4)。这种关系的出现是因为自然数和整数(0 <-> 0), (1 <-> 1), (2 <-> -1), (3 <-> 2), (4 <-> -2), (5 <-> 3), (6 <-> -3), ... 之间存在一对一的关系(双射)。这种方法快速、简单且优雅,但当您的网格非常稀疏且项目离中心线非常远时,这种方法在内存方面不是很好。

【讨论】:

  • 我认为奇偶方法适用于我正在做的事情。谢谢:)
【解决方案2】:

除非你有一个 TON(是的,一个 TON 的比特......)的单元格,你可以使用字典。将它与 System.Drawing.Point 结合起来作为键,你会得到一件好事:

Dictionary<Point,YourGridObject> myMap = new Dictionary<Point,YourGridObject>();

编辑:除了字典之外,每个单元格都可以引用它的相邻单元格,这样你可以使用字典直接去“某处”,然后用相邻的单元格导航。我用这种方式在一个十六进制网格中实现了一个 A* 寻路算法。

编辑 2: 例如,如果你想访问一个特定的坐标,你可以简单地

var myTile = myMap[new Point(25, -25)];

那么,你想得到East的磁贴,你可以

var eastTile = myTile.East;

您的网格对象也可以实现偏移方法,这样您就可以得到“West 2, North 5”的平铺

var otherTile = myTile.Offset(-2, 5);

【讨论】:

  • 所以假设我想找到25,-25... 位置的内容,我会使用.Where(...) 函数吗?
  • 与其添加对相邻单元格的引用,不如存储对 Point 对象的引用可能更容易,您可以通过添加/减去 Point 的坐标来找到邻居。根据您程序的结构,这些非规范化可能非常有用或不必要地复杂化。
  • @TheAdamGaskins 我在回答中添加了一些元素,但这只是建议。我不知道你想用你的磁贴做什么,但实现它的最佳方式实际上取决于你将如何使用它。
  • @LieRyan 在某些情况下引用相邻单元格而不是存储坐标可能会更快,而不是查询字典。这真的取决于他有多少瓷砖。不利的一面是我认为如果序列化/反序列化。在我的场景中,您必须在反序列化后重新创建所有关联。
【解决方案3】:

使用下面的两个 List 进行两个不同方向的扩展怎么样?

【讨论】:

    【解决方案4】:

    我不确定这是否比您想要处理的更复杂,但您是否考虑过使用极坐标而不是笛卡尔坐标?该坐标系中没有负数。我知道一开始覆盖很困难,但一旦你把头绕过去,它就变成了第二天性。

    【讨论】:

      【解决方案5】:

      您可以使用 Dictionary,它具有数组的所有功能,但显然带有负索引。

      【讨论】:

        【解决方案6】:

        计算机无法存储无限数组。 您的数组必须有一个边界,请提醒您在数组初始化期间在代码中的某处声明了特定大小。 也许你在某个地方调整它的大小,但仍然留下一个从 0.. 到.. 最大的数字范围。

        所以你应该做的是,编写一个函数,允许在这样的地图中进行相对定位。因此,您将当前的地图 [x,y] 存储为位置。 并且您可以通过具有相对于您当前位置添加/减去的功能来上升。 这也使您的代码更易于理解。

        如果您处理的不是游戏地图而是数字范围,可以说是向量 你可以创建一个包含 n 个点的列表,或者一个二维字典。

        我在这里发布它,因为您的问题可能会导致人们编写错误的代码。

        在地图周围有边界的情况下(典型的游戏场景和图像处理)也可以为其他人添加。 您的数据来自 [-1..width+1] 的位置,只需将其标注为 [0,width+2] 然后循环遍历它,从 'for (int x = 1; x

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2014-01-21
          • 2011-04-29
          • 2020-02-03
          • 2013-03-21
          • 1970-01-01
          • 1970-01-01
          • 2018-04-27
          • 2019-06-02
          相关资源
          最近更新 更多