2010-06-12 65 views
7

在Java(Swing)中,假设我有一个2D游戏,在屏幕上有各种类型的实体,例如玩家,坏人,通电等。玩家在屏幕上移动,为了高效地检查玩家附近的东西,我想我会希望根据他们的位置索引访问角色附近的东西。Java中游戏实体位置的高效映射

例如,如果玩家 'P' 走上元素 'E' 在下面的例子中...

| | | | | | 
| | | |P| | 
| | |E| | | 
| | | | | | 

...会做这样的事情:

if(player.getPosition().x == entity.getPosition().x && 
       entity.getPosition.y == thing.getPosition().y) 
{ 
    //do something 
} 

而且这很好,但这意味着这些实体持有他们的立场,因此,如果我在屏幕上有很多实体,我将不得不遍历所有可能的实体,并根据玩家位置检查每个实体的位置。这看起来效率很低,特别是如果你开始获得大量的实体。

所以,我怀疑我会需要某种地图像

Map<Point, Entity> map = new HashMap<Point, Entity>(); 

还有存储我点的信息,这样我就可以在固定时间内访问这些实体。这种方法唯一的问题是,如果我想要将实体移动到屏幕上的不同点,我必须搜索HashMap的值,以查找要移动的实体(效率低,因为我不知道它的值点位置提前),然后一旦我发现它从HashMap中删除它,并重新插入它与新的位置信息。

对于我应该在这里使用什么类型的数据结构/存储格式的任何建议或建议,以便根据实体的位置以及基于实体的位置有效地访问实体?

回答

4

空间分区可能会有效。

您可以执行固定的分割,例如统一网格或加权网格,除非您的地图上有热点,而事情异常聚集。对于每个占用的分区,创建它包含的所有实体的容器。

插入是恒定的时间。删除实际上是无限小数 n(您的实体总数)假设 n非常大,并且您已经有效地设置了分区。 Proximity looksups与删除共享相同的运行时。尽管如此,技术上O仍然很小( n)。如果分区变得异常拥挤,这将变得明显。

为了得到内X单位实体的所有实体的名单,你必须首先得到由集中在你的实体2 X宽阔的广场广场跨越所有分区的列表。如果你使用网格分区,这是相当微不足道的。接下来,您循环遍历这些分区中的所有实体,并返回距离为x或更少的实体。

更复杂的分区方法是动态分区树中的空间,确保没有分区可以包含超过给定数量的实体。如果分区变满,则沿空间平均值划分它,并创建两个两个空间分区,以便每个分区保存原始分区实体的一半。这使得插入和查找具有对数运行时间,因为您无法再在常量时间内发现所需的分区,但在给定分区限制群体的情况下,清除会变成恒定时间。

+0

感谢您的提示,我会研究更多的空间分区。 – 2010-06-12 06:30:38

+0

我键入了两个游戏板实现,用于保存随机添加到1920x1080区域的1,000,000个实体。使用一个1080x1920的容器阵列,我有0.004毫秒插入,0.003毫秒的删除和0.004毫秒要求在3×3区域的所有容器的清单。使用动态二进制空间分区,对于与3x3区域相交的分区,我有0.007 ms的插入,0.003 ms的删除和0.007 ms的查询。对于非均匀分布的实体,BSP上的性能和内存使用情况应该更好。 – Gunslinger47 2010-06-12 21:22:16

0

低效的,因为我不知道提前
我是正确的点位,该实体对象没有在它的位置信息?我会建议添加它。或者,否则,您可以拥有当前实体位置的地图Map<EntityIdType, Point>并首先获取位置。没有什么花哨。

+0

要么你刚刚重申了手头的问题,要么你完全不了解这个问题,因为这里没有提供解决方案。根据原始文章中提出的两种方法,对象要么包含位置信息,要么不包含位置信息。同样,地图取决于采取了哪种方法。无论哪种方式,寻找中间立场的原始问题都不存在于你的答案中。 – 2010-06-12 06:29:50

3

如果在EntityPoint之间存在一对一映射,并且您希望能够在两个方向上映射,那么bimap是最自然的数据结构。

番石榴有一个BiMap<K,V>实现,它支持BiMap<V,K> inverse()视图操作。这只是一个观点,所以它并不昂贵。

或者,您可以管理自己的Map<Entity,Point>Map<Point,Entity>,但那会重新发明轮子。