Greenfoot双人坦克游戏添加bulletCollision方法后触发ActorRemovedFromWorld错误
Greenfoot双人坦克游戏子弹碰撞错误修复方案
问题描述
在Greenfoot开发双人对战坦克游戏时,为Bullet1和Bullet2类的act方法添加bulletCollision方法后,当一方子弹击中另一方玩家,游戏触发greenfoot.ActorRemovedFromWorld错误,错误栈如下:
Caused by: greenfoot.ActorRemovedFromWorld
at greenfoot.World.removeObject(World.java:466)
at Bullet1.checkCollision(Bullet1.java:34)
at Bullet1.act(Bullet1.java:23)
... 4 more ....
问题根源
- 子弹移除后仍执行后续代码:比如Bullet1的
checkCollision方法中已经调用removeObject(this)移除当前子弹,但act方法会继续执行后续的bulletCollision,此时子弹已不在世界中,调用getWorld()等方法会抛出异常。 - 子弹互撞时重复移除:Bullet1和Bullet2同时检测到碰撞并尝试移除对方,导致同一对象被多次调用
removeObject触发错误。
修复方案
1. 终止act方法后续执行
在子弹被移除后立即终止act方法的剩余逻辑,避免无效操作。同时在act开头增加判断,确保只有存在于世界中的子弹才执行逻辑。
2. 优化子弹互撞逻辑
让其中一方子弹负责处理双方的移除操作,避免重复移除同一对象。
修改后的代码示例
Bullet1类
import greenfoot.*; // (World, Actor, GreenfootImage, Greenfoot and MouseInfo) public class Bullet1 extends Actor { private Player1 player1; private GreenfootImage hitImage; private int damage = 5; public Bullet1(Player1 player1) { this.player1 = player1; hitImage = new GreenfootImage("explode1.png"); } public void act() { // 若子弹已被移除,直接终止执行 if (getWorld() == null) return; move(20); // 碰撞玩家后直接返回,不执行后续碰撞检测 if (checkCollision()) return; bulletCollision(); } private boolean checkCollision() { Actor player = getOneIntersectingObject(Player2.class); if (player != null) { ((Player2)player).takeDamage(damage); setImage(hitImage); Greenfoot.playSound("takingDamageSFX.mp3"); Greenfoot.delay(4); getWorld().removeObject(this); return true; } return false; } private void bulletCollision() { Actor bullet2 = getOneIntersectingObject(Bullet2.class); if (bullet2 != null && getWorld() != null) { setImage(hitImage); Greenfoot.delay(4); World world = getWorld(); // 先判断目标是否仍在世界中,避免重复移除 if (world.getObjects(Bullet2.class).contains(bullet2)) { world.removeObject(bullet2); } world.removeObject(this); } } }
Bullet2类
import greenfoot.*; // (World, Actor, GreenfootImage, Greenfoot and MouseInfo) public class Bullet2 extends Actor { private Player2 player2; private int damage = 5; private GreenfootImage hitImage; public Bullet2(Player2 player2) { this.player2 = player2; setRotation(180); hitImage = new GreenfootImage("explode1.png"); } public void act() { if (getWorld() == null) return; move(20); if (checkCollision()) return; bulletCollision(); } private boolean checkCollision() { Actor player = getOneIntersectingObject(Player1.class); if (player != null) { ((Player1)player).takeDamage(damage); setImage(hitImage); Greenfoot.playSound("takingDamageSFX.mp3"); Greenfoot.delay(4); getWorld().removeObject(this); return true; } return false; } private void bulletCollision() { Actor bullet1 = getOneIntersectingObject(Bullet1.class); if (bullet1 != null && getWorld() != null) { setImage(hitImage); Greenfoot.delay(4); // 仅移除自身,由Bullet1负责移除双方,避免重复操作 getWorld().removeObject(this); } } }
核心修改说明
- 在
act方法开头增加if (getWorld() == null) return;,确保子弹被移除后不再执行任何逻辑。 - 将
checkCollision改为返回布尔值,碰撞处理完成后返回true,让act方法直接终止,不再执行后续的bulletCollision。 - 子弹互撞时,仅让Bullet1负责移除双方,Bullet2只处理自身移除,避免重复移除导致的异常。
内容的提问来源于stack exchange,提问作者Justine Apitan
相关产品推荐
相关产品推荐

