You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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 ....

问题根源

  1. 子弹移除后仍执行后续代码:比如Bullet1的checkCollision方法中已经调用removeObject(this)移除当前子弹,但act方法会继续执行后续的bulletCollision,此时子弹已不在世界中,调用getWorld()等方法会抛出异常。
  2. 子弹互撞时重复移除: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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 19:29:58