【问题标题】:directing a mass of enemies at once一次指挥大量敌人
【发布时间】:2012-03-19 21:01:34
【问题描述】:

我正在开发一个简单的 2d 游戏,其中许多敌人不断产生并在 python + pygame 中追逐一个或多个玩家。我遇到的一个问题,许多编写过此类游戏的人都遇到过一个问题,那就是敌人会很快收敛。我已经为这个问题做了一个临时的解决方案,一个函数可以将任意两个距离太近的敌人随机分开。这很好用,但它是关于每帧运行的 O(n^2) 算法,并且在高敌人处程序开始减慢。

当我的程序使用这个函数运行时,敌人似乎形成了我昵称为“团块”的圆形物体。丛似乎通常是黄道的,但实际上可能更复杂(不对称),因为随着玩家的移动,敌人会被拉向不同的方向。我确实喜欢这个团块的行为方式,但是我想知道是否有更有效的方法来计算它。目前,集群中的每个敌人(通常 > 100 个)都会首先向玩家的方向移动,然后被推开。如果有一种方法可以计算团块创建的图形,以及它的移动方式,它将节省大量计算。

我不确定如何解决这个问题。或许可以计算出图形边界的移动位置,然后将其展开以确保该区域保持不变。

还有我目前用来移动敌人的两个功能:

def moveEnemy(enemy, player, speed):
    a = player.left-enemy.left
    b = player.top-enemy.top
    r = speed/math.hypot(a,b)
    return enemy.move(r*a, r*b)

def clump(enemys):
    for p in range(len(enemys)):
        for q in range(len(enemys)-p-1):
            a = enemys[p]
            b = enemys[p+q+1]
            if abs(a.left-b.left)+abs(a.top-b.top)<CLUMP:
                xChange = (random.random()-.5)*CLUMP
                yChange = ((CLUMP/2)**2-xChange**2)**.5
                enemys[p] = enemys[p].move(int(xChange+.5), int(yChange + .5))
                enemys[p+q+1] = enemys[p+q+1].move(-int(xChange+.5),-int(yChange+.5))
    return enemys

编辑:一些有关丛集外观的屏幕截图: http://imageshack.us/photo/my-images/651/elip.png/ http://imageshack.us/photo/my-images/832/newfni.png/

http://imageshack.us/photo/my-images/836/gamewk.png/

这个团块似乎主要是一个刚刚被拉伸的圆形物体(像一个日食,但可能会向多个方向拉伸),但是由于矩形敌人,它目前具有直边。

【问题讨论】:

  • 范围的代码怎么样?那是在做距离检查吗?对于大量单元而言,这可能非常昂贵。
  • 另外,不要每帧都这样做,而是每 X 帧都这样做。我以类似的方式解决了同样的问题,但是我允许一些重叠。它让大群蜂群看起来更危险!
  • 根据您在此处获得的答案质量,您可能还想尝试在 gamedev.stackexchange.com 上提问。
  • 你能提供一些图片吗?
  • 这是关于...僵尸吗? :)

标签: python algorithm pygame


【解决方案1】:

有几种方法可以解决这个问题,具体取决于您的游戏。以下是提高性能的一些想法:

  1. 允许一些重叠。
  2. 减少在固定帧数后进行的距离检查。
  3. 改进您的距离检查公式。如果您使用标准距离公式,则可以通过多种方式进行优化。一方面,摆脱平方根。精度无关紧要,只有相对距离。
  4. 每个单位都可以跟踪附近单位的列表。仅在该列表中的单位之间执行计算。每隔一段时间,通过检查所有单位来更新该列表。
  5. 根据您的游戏设置方式,您可以将字段划分为多个区域,例如象限或单元格。单元仅针对该单元中的其他单元进行测试。

编辑:当单位接近他们的目标时,它可能无法正常运行。我建议他们实际上寻找随机附近的目标,而不是让他们从远处瞄准确切的目标。就像偏离他们的真实目标一样。

我相信还有很多其他方法可以改进这一点,毕竟它是开放式的。我还应该指出Boidsflocking,这可能很有趣。

【讨论】:

  • 感谢您的回复,以回答您的建议: 1. 已经允许一些重叠,因为当敌人相距 5 个单位时,它们实际上是重叠的,因为它们是 24 x 24 方格。 2. 一个不错的选择,但移动的距离必须更大才能抵消这一点,但敌人似乎在四处跳跃。 3.取点我会取出平方根。 4. 似乎是一个不错的选择。 5. 我可能会尝试一下,但我想我只需要 4 或 5 个中的一个。我真正想要的(如果可能的话)是一种一次计算整个“团块”的方法。
  • @user1125600 我可以想出一些理论算法来一次计算整个团块。这类似于最大化容器中的对象数量。但我认为这对于实时游戏来说不是一个好主意。
【解决方案2】:

您可以将丛定义为一个单独的对象,该物体具有固定数量的空间“插槽”,用于丛中的每个敌方单位。每个槽都有一组相对于丛中心的坐标,并且可以是空的,也可以是对一个单元的引用。

一个试图加入集群的新单位会移动到最里面的空闲槽位,一旦它到达那里,它就会“保持编队”,它的位置总是它所占据的槽位的位置。团块的半径比单个单位大得多,会调整位置以避免重叠其他团块或未尝试加入团块的松散单位等。

不过,在某些时候,您需要处理集群中各个单元的交互,所以我不确定这是否值得。我认为 Austin Henley 提出的将场划分为单元/区域并仅针对附近单元中的单元进行测试的建议是最实用的方法。

【讨论】:

    【解决方案3】:

    我想你正在寻找flocking

    【讨论】:

      【解决方案4】:

      植绒/转向行为运动的最佳介绍:http://www.red3d.com/cwr/steer/。见附件red3d paper。以及相关的OpenSteer

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-03-21
        • 1970-01-01
        • 2011-10-01
        • 1970-01-01
        相关资源
        最近更新 更多