1

我正在使用 Python 制作一个简单的进化模拟器。

有一个名为 的列表engine.All,其中存储了单位/动物和食物。我遍历它,如果我遇到一只动物,我会再次遍历它,看看它是否与任何食物块发生碰撞。

如果是这样,那么我会增加他的能量,将食物标记为已吃,并将其添加到toRemove列表中,稍后我会使用该列表从engine.All.

这是代码,但删除了所有多余的东西:

def remove(l, who): #This should remove all the elements contained in who from the list l
    offset = 0

    for i in who:
        l.pop(i + offset)
        offset -= 1

    return l


for ob in engine.All:
    if ob.skip:
        continue;

    if ob.drawable:
       ob.draw()

    if isinstance(ob, Flatlander): #If it is an animal
        #Do speed stuff
        ob.energy -= decay #Lower its energy

        for i in range(len(engine.All)): #Iterate through the list again
            if collides(ob.pos, ob.r, engine.All[i].pos, engine.All[i].r) and isinstance(engine.All[i], Food) and ob.energy + engine.All[i].r < ob.r**2*3.14 and not engine.All[i].skip: #If it collides with a food piece, the food piece isn't about to be deleted and it can take the energy in (their maximum is defined by their radiuses)
                ob.energy += engine.All[i].r #Increase the his energy
                toRemove.append(i) #Add the food piece to the toRemove list
                engine.All[i].skip = True #Flag it as skipped

        if ob.energy < 0 and not ob.skip: #If its energy is 0 and if it isn't already about to be deleted
            toRemove.append(engine.All.index(ob)) #Add it to the toRemove list
            ob.skip = True #Flag it as skipped


engine.All = remove(engine.All, toRemove) 

我几乎可以肯定这不起作用,并且有更好的方法来做到这一点。我如此确定的原因是,有时,我看到屏幕上的东西只是“闪烁”——突然消失又出现。此外,似乎有“幽灵”动物(在代码中称为 Flatlanders),我得出结论是因为有时食物会永久消失。

请推荐一种更有效的方法。

4

3 回答 3

4

将其作为生成器函数执行并产生您想要的结果会更容易,而不是弹出您不想要的元素。

def valid_engines():
    for ob in engine.All:
        if should_use_engine(ob):
            yield ob

engines_to_use = valid_engines()

should_use_engine() 当然会替换为您上面的逻辑,以确定是否包含引擎。

于 2012-05-10T22:14:30.530 回答
1

如果该skip属性只为那些需要删除的对象设置,只需使用它:

import math
import itertools

for ob in engine.All:
    if isinstance(ob, Flatlander):
        ob.energy -= decay

for pair in itertools.combinations(engine.All, 2):
    fooditems = [x for x in pair if isinstance(x, Food) and not x.skip]
    animals = [x for x in pair if isinstance(x, Flatlander) and not x.skip]
    if not (fooditems and animals):
        continue
    animal = animals[0]
    food = fooditems[0]
    if collides(animal.pos, animal.r, food.pos, food.r):
        # This seems an odd calculation to me but I think it follows your code.
        if animal.energy + food.r < animal.r ** 2 * math.pi:
            # eating is feasible; the animal always eats the food if it can
            food.skip = True
            animal.energy += food.r # Not the area?

for ob in engine.All:
    if isinstance(ob, Flatlander) and ob.energy < 0:
        ob.skip = True # dead

# Remove dead things
engine.All = [ob for ob in engine.All if not ob.skip]

# Draw everything (no dead things remain)
for ob in engine.All:
    if ob.drawable:
      ob.draw()

一般来说,我可能更愿意将食品和平地人放在单独的列表中。

有几种技术可以更有效地进行碰撞检测(例如将世界划分为正方形,并仅检查相同或周围正方形中的那些动物)但是如果您只有少数(比如少于几百个)动物/食物这将不需要。

于 2012-05-10T22:30:31.520 回答
0

我不熟悉进化游戏,但我想你有某种 2D 地图(mb 3D)和一些移动并吃掉它们碰撞的第一个食物的动物?或者它是一种生活游戏?这基本上是一样的:p

如果是这样,我会在正方形中添加一个内容字段。当动物移动到一个方格时,您检查相邻的方格,如果存在食物,您只需将该方格的内容字段设置为 Null。这是对存储 2D 游戏中每个元素的位置的常见优化,可以根据需要进行调整。

您可以使用计时器字段添加已删除项目的列表,以告知每个项目应何时重新生成。此列表将按重新生成时间排序,以便您可以轻松检测是否需要重新插入项目。

于 2012-05-10T22:13:53.930 回答