具有快速删除/迭代/插入的集合,可回收Android / Java程序中的对象?

时间:2010-01-28 05:59:50

标签: java android collections

我正在为Android编写游戏。例如,游戏可能涉及子弹,敌人,宝石等,这些都需要:

  • 在游戏过程中在游戏世界中创建和销毁,例如子弹是火,然后在撞到墙壁时消失。

  • 按顺序访问了很多例如所有按顺序更新,然后全部按顺序绘制。

根据我迄今为止在Android工作中所知道的,为了保持帧速率,我需要考虑以下因素:

  • 当你不需要时,不要分配对象,因为垃圾收集器会启动并破坏你的帧速率。

  • 首选例如局部变量访问访问对象字段和调用函数。

对于上面提到的PC游戏中的游戏对象,我通常只是喜欢使用像Vector或LinkedList这样的东西。但是,这些不会回收对象,并且使用Iterator会创建一个新对象,并在迭代时涉及多个函数调用。

什么是合适的收藏品?

我目前发现效果很好的是创建例如100个子弹的标准阵列,其中所有100个子弹都是预先创建的。然后,当所有活动子弹出现在阵列的开头时,我会计算有多少子弹是活动的。每当我迭代一系列子弹并且我需要销毁一个子弹时,我只需将当前项目符号索引与最后一个活动项目符号索引交换,然后减少活动项目符号数。这改变了子弹顺序,但没关系。

这很有效:

优点:回收对象,很少/没有函数调用 缺点:未实现为集合类时容易出错(尤其是删除)

有人能提出更好的选择吗?我见过很多用于管理对象池的类,但我不确定哪些适合我。

感谢。

2 个答案:

答案 0 :(得分:7)

我在80年代后期编程游戏,最近在Java用于移动设备。我可以告诉你,如果你使用LinkedList或Vector来存储与物体相对应的Java对象,那么你将会杀死你的帧速率。这不是手机游戏的编程效率。通过考虑“每一点都很重要”来编程高效的移动游戏。这是优化占主导地位的领域之一。

过度简化,但想象一下你的游戏目前只有四颗子弹“活着”(它不是真的“在屏幕上”,你的“活跃世界”可以并且通常应该比你的屏幕稍微大一些,它会让你很多处理更容易)。

(20,30,3)(10,50,2)(30,40,-3)(50,50,5)

因此,子弹1位于坐标空间中的像素(20,30)处,并以3的速度(无论3的速度,只是一个示例)向右移动(过度简化,只是为了解释) ,子弹2在(10,50)以2的速度向右移动,子弹3在(30,40),以3的速度向左移动(减去这里意味着左),最后一颗子弹在(50,50,5)以5的速度向右移动。

在当前的手机游戏中,这在内存中的表现如何?

像这样,在int []中:

int [] = {4,20,30,3,10,50,2,30,40,-3,50,50,5,...,...,...};

前4个告诉我们这个“数据结构有4个元素。而且你知道每个元素都由3个值组成(在我们过于简单的例子中)。

现在想象一下子弹2撞墙并消失,会发生什么?

此:

int [] = {3,20,30,3,50,50,5,30,40,-3,50,50,5,...,...,...};

我们将第一个int的减少简化为3,表示我们的游戏世界中只剩下3个子弹,我们只是将(50,50,5)移动到位置'2',替换(10, 50,2)(50,50,5)。那是因为我们的子弹的顺序没有重要性(它们都具有相同的效果)并且“将所有int []元素移动到左侧”将是非常低效的。

请注意,我们甚至懒得“清除”'第4个子弹':旧的(50,50,5)仍然在那里,但我们知道我们只有3个元素,所以我们不要不在乎。

所以在内存中看起来像这样:

int [] = {3,20,30,3,50,50,5,30,40,-3,50,50,5,...,...,...};

你只关心这个:

int [] = {3,20,30,3,50,50,5,30,40,-3,...,...,...,...,...,。 ..};

这是在大多数当前手机游戏中的表现:在主循环中为“子弹处理”创建零对象。您可以使用基元数组自己管理这些简单的数据结构。

int []会在你的关卡游戏开始时初始化为游戏/关卡中可能发生的最大子弹数。

你的“可重复使用的子弹池”。

如果您开始考虑将Java对象视为子弹并且使用您在每个帧上修改的LinkedList或Vector,那么您将永远不会获得可接受的性能:您将成为每秒50次生成无数不必要的物体,并经常触发GC。

现在我当然不是说OO编程在移动游戏中没有它的位置:我只是说,如果你的想法就物体而言像子弹一样微不足道,那么你永远不会接受性能

我的“子弹移除”技术涉及一个减量(子弹数量)和3个副本。你不能打败那个;)

它适用于很多事情:子弹,粒子效果,敌人,物品,奖金,等等:)

在游戏循环中可能经常删除/重新创建的微不足道的东西可能不应该使用对象建模,当然也不应该放在Vector和LinkedList中。

答案 1 :(得分:2)

我认为您正在寻找/谈论Object Pool

来自维基百科:

  

对象池是一种软件设计模式。对象池是一组初始化对象,可以随时使用,而不是按需分配和销毁。在初始化类实例的成本高,类的实例化率高的情况下,对象池可以提供显着的性能提升任何时候使用的实例数量都很低

看起来你已经开始设计一个对象池了,所以它可能是一个很好的选择。