Android游戏开发:使用哪种数据结构?

时间:2011-08-11 02:25:02

标签: java android data-structures

我正在为Android制作游戏。我有点想让游戏保密,所以我不能透露太多关于它的事情,所以请耐心等待。基本上它是实时运行的(所以我将实现一个线程来更新对象的坐标),它的风格有点像Duck Hunt;你必须击中在屏幕上移动的物体。但是,游戏一直在略微滞后(在三星Galaxy S上运行,这是高端设备之一)所以我相信我需要使用更好的数据结构。

基本上我将这些对象存储在双向链表而不是数组中,因为我希望屏幕上的最大对象数是动态的。换句话说,我有一个对头部和尾部对象的引用,所有游戏对象都像典型的链表那样连接起来。这提出了以下问题:

  1. 搜索对象是否与给定坐标相交(通过触摸屏幕)需要O(n)时间(最差情况)因为我必须从头到尾遍历并检查每个对象的命中框。
  2. 两个对象之间的碰撞检查花费O(n ^ 2)时间(同样,最糟糕的情况),因为对于每个对象,我必须检查其hitbox是否与链表中所有其他对象的hitbox相交。
  3. 我选择链表的另一个原因是因为我基本上有两个链表:一个用于活动对象(即屏幕上的对象),另一个用于非活动对象。因此,假设游戏屏幕上最多有8个对象,如果活动链表有5个对象,则非活动列表将有3个对象。使用两个链表使得每当一个对象变为非活动状态时,我只需将它附加到非活动链表而不是解除引用并等待垃圾收集器回收内存。此外,如果我需要一个新对象,我可以简单地从非活动链表中取一个对象,并在活动链表中使用它,而不必分配更多内存来创建一个新对象。

    我考虑过使用多维数组。该方法涉及将屏幕划分为对象可以躺在其中的“单元格”。例如,在480x800屏幕上,如果对象的高度和宽度都是80像素,我会将屏幕划分为6x10网格,或者在Java代码的上下文中,我会制作GameObject [6] [10]。我可以简单地将对象的坐标(在屏幕上)除以80以获得其索引(在网格上),这也可以提供O(1)插入。这也可以通过坐标O(1)进行搜索,因为我可以使用触摸坐标来检查相应的索引。

    碰撞检查可能仍需要O(n ^ 2)时间,因为我仍然需要遍历网格中的每个单元格(尽管这样我只需要与我正在检查的单元格相邻的最多8个单元格进行比较目前)。

    然而,网格理念带来了自己的问题:

    1. 如果屏幕的分辨率不是480x800,该怎么办?如果网格不能均匀分为6x10怎么办?这可能会使程序更容易出错。
    2. 在内存方面使用的游戏对象网格是否昂贵?考虑到我正在为移动设备开发,我需要考虑到这一点。
    3. 所以最终的问题是:我应该使用链表,多维数组还是其他我没有考虑过的东西?

      下面是我如何实现碰撞的想法:

      private void checkForAllCollisions() {
       GameObject obj1 = mHead;
      
       while (obj1 != null) {
              GameObject obj2 = obj1.getNext();
                  while (obj2 != null) {
                      //getHitBox() returns a Rect object that encompasses the object
                      Rect.intersects(obj1.getHitBox(), obj2.getHitBox());
                      //Some collision logic
                  }
                  obj1 = obj1.getNext();
              }
      }
      

2 个答案:

答案 0 :(得分:2)

更好的碰撞检测性能的常见数据结构是quadtrees(2维)和octrees(3维)。

如果您想坚持使用列表 - 是否有理由使用LinkedList而不是ArrayList?我希望您当前正在使用内置链接列表实现...


三星Galaxy S拥有512 MB的RAM - 不用担心单个数据结构占用太多内存(还)。在此数据结构开始吸收大量RAM之前,您必须拥有相对较多的相对较重的对象。即使您有1000个GameObject个实例,并且数据结构中的每个实例(包括在所述数据结构中存储实例的相关权重)都是10,000个字节(这非常令人振奋),那仍然只有9.5兆字节的内存

答案 1 :(得分:1)

所以我绝对认为我们需要先考虑一些事情。

1。)LL vs. Array

你说你使用了LL而不是数组,因为LL给你的动态属性。但是,我想说你可以通过在填充之后将其大小加倍来使用足够动态的数组,这将为你提供插入amortized的O(1)运行时(假设数组是不保持/未分类)。但是,由于必须适当地复制数据,因此有时会出现一个插入O(n)的情况。所以,对于像这样的现场游戏,我相信LL是一个不错的选择。

2。)你根据游戏对象考虑记忆。

这在很大程度上取决于每个GameObject的结构,你没有提供足够详细的信息。如果每个GameObject只包含几个整数或原始类型,那么你可以负担得起内存。如果每个GameObject的内存成本非常高并且你使用的是非常大的网格,那么它肯定会耗费大量内存,但它将取决于每个GameObject的内存使用量以及网格的大小。

3.)如果分辨率不同于480x800,请不要担心。如果您使用的是6x10网格,请考虑使用密度倍增器:

float scale = getContext().getResources().getDisplayMetrics().density;

然后将getWidth()和getHeight()乘以此比例以获得正在使用您的应用的设备的确切宽度和高度。然后,您可以将这些数字除以6和10.但是,请注意某些设备上的某些网格可能看起来很难看,即使它们以这种方式正确缩放也是如此。

4。)碰撞处理

你提到过你正在进行碰撞处理。虽然我不能说在你的情况下处理这个问题的最佳方法是什么(我仍然对你根据你的问题实际做到这一点感到困惑),请记住这些替代方案:

a。)Linear Probing b。)Separate Chaining c。)Double Hashing

这些都是公认的哈希冲突处理策略,但可以在你的游戏中实现(再次,你会知道更多关于你保留一些信息的信息)。但是,我会说如果你使用网格,你可能想要沿线性探测做一些事情或者一起创建2个哈希表(如果合适的话,但这似乎会带走你想要的网格布局)实现,所以,再次,你的自由裁量权)。另请注意,您可以使用某种树(如四叉树)来更快地进行碰撞检测。如果您不了解四叉树,请查看它们here。想到一个的好方法是将正方形图片划分为叶子上的单独像素,并将平均颜色存储在pruning的父节点处。只是一种帮助你有意义地思考四叉树的方法。

希望有所帮助。同样,也许我因为你问题的模糊性而误解了某些东西,所以让我知道。我很乐意提供帮助。