我正在编写捕食者/猎物模拟,其中物体可以出生或被杀死。当被杀死时,它们会从arraylist中删除,当它们出生时会被添加。列表中的每个对象都可以杀死另一个对象或复制。我浏览列表,模拟每个物体的运动以及与周围环境的相互作用,包括决定复制或杀死另一个物体(如果它关闭)。
循环中断的正常情况,就好像当前正在进行的索引发生删除或生成一样。 什么是更好的解决方案?用计数器和条件表示大小> 0或其他一些方式?
答案 0 :(得分:5)
您可以等到迭代完成后添加/删除项目:
entities_to_add = new Array;
entities_to_remove = new Array;
function tick():
for each entity in world:
//general entity behavior goes here
if entity.wants_to_reproduce:
entities_to_add.append(entity.make_baby())
if entity.wants_to_die:
entities_to_remove.append(entity)
function cleanup():
for each entity in entities_to_remove:
world.remove(entity)
for each entity in entities_to_add:
world.add(entity)
entities_to_remove.clear()
entities_to_add.clear()
function main():
while(True):
tick()
cleanup()
这有一个缺点,即死亡的实体看起来会一直存在,直到滴答结束。这可能是坏的,例如,如果捕食者杀死猎物,并且第二捕食者也在同一滴答中杀死该猎物。如果这是不可取的,你可以让掠夺者在攻击之前检查entities_to_remove数组,以确保它们的猎物仍然存活。
答案 1 :(得分:1)
在模拟中通常有两个世界副本 - 一个用于时间 t 的状态,一个用于时间 t +Δt的状态。
如果您没有两个副本,并在处理状态转换时尝试生成实体,那么列表中的第一个实体将看到与上一个不同的世界。
例如,如果更多的猎物出生而不是在蜱虫中砍伐,那么恰好位于列表末尾的掠食者将具有一个优势,这个优势不是被模拟的世界的一部分,而是你实施的人工制品。如果你已经添加了“红猫”和“蓝猫”,那么蓝猫会做得更好,没有任何真正的区别。
如果你确实有两个副本,那么你必须解决一个以上捕食者砍伐同一个猎物的问题,但你的原始问题将不存在。
答案 2 :(得分:0)
ArrayList<Object> predators = new ArrayList<Object>();
ArrayList<Object> preys = new ArrayList<Object>();
for (Object predator : predators) {
Object[] entities = preys.toArray();
for (Object entity : entities) {
if (entity.shouldReprodue()) {
world.add(entity.baby());
}
if (entity.shouldDie()) {
world.remove(entity);
}
}
}
我认为每个捕食者都应该制作当前世界ArrayList的新副本。