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

使用JFrame开发Java 2D游戏时的碰撞检测异常问题

Java 2D游戏方块销毁逻辑Bug修复求助

我正在开发一款Java 2D游戏,玩家需射击方块(tiles)。当前代码存在Bug:子弹会破坏附近方块,但效果不稳定且不符合预期。

期望效果:子弹击中方块时,摧毁该方块及其上下左右相邻方块。

问题代码(Player.java精简版)

public class Player{
    public int pointX;
    public int pointY;
    public int velocityX;
    public int defaultVelX = 15;
    public int cooldown = 2;
    public boolean shooting = false;
    public Tile hitTile = null;
    YeahGame yg;
    Shot shot;
    TileManager tm;

    public Player(int x, int y, YeahGame yg) {
        this.pointX = x;
        this.pointY = y;
        this.yg = yg;
        tm = yg.tm;
    }
    public void shoot() {
        if (!shooting) {
            shot = new Shot(pointX, pointY, yg);
            shooting = true;
        }
    }
    public void Hit(int offsetX, int offsetY, int level) {
        Tile tl = tm.GetTile(hitTile.x + offsetX, hitTile.y + offsetY);
        if (tl != null && tl.isActive) {
            if (level >= tl.level) {
                tl.isActive = false;
            } else {
                tl.level -= level;
            }
        }
    }
    public void DestroyTiles() {
        Hit(0,0,1);
        Hit(1,0,1);
        Hit(0,1,1);
        Hit(-1,0,1);
        Hit(0,-1,1);
        if (cooldown > 0) {
            cooldown--;
        } else if (cooldown == 0) {
            tm.NewLayer();
            cooldown = 2;
        }
    }
    public boolean bulletCollision() {
        boolean is = false;
        if (shooting) {
            for (ArrayList<Tile> sampleRow : tm.rows) {
                for (Tile tile : sampleRow) {
                    if (tile.isActive) {
                        Rectangle shotRect = new Rectangle(shot.pointX+yg.tileSize/4, shot.pointY+yg.tileSize/4, yg.tileSize/2, yg.tileSize/2);
                        Rectangle tileRect = new Rectangle(tile.x * yg.tileSize, tile.y * yg.tileSize, yg.tileSize, yg.tileSize);

                        if (tileRect.intersects(shotRect)) {
                            is = true;
                            hitTile = tile;
                            break;
                        }
                    }
                }
                if (is) {
                    break;
                }
            }
        }
        return is;
    }
    public void update() {
        if (shooting) {
            shot.update();
            if (bulletCollision()) {
                DestroyTiles();
                shooting = false;
                shot = null;
            }
            else if (shot.pointY < 0) {
                shooting = false;
                shot = null;
            }
        }
    }
    public void draw(Graphics g) {
        g.setColor(Color.red);
        g.fillRect(pointX, pointY, yg.tileSize, yg.tileSize);
        if (shooting) {
            shot.draw(g);
        }
    }
}

问题分析及修复方案

核心问题点

  1. 碰撞检测精度不足:原代码用缩小的子弹矩形做碰撞,容易出现擦碰误触发或漏触发的情况,导致效果不稳定。
  2. 冷却逻辑与销毁逻辑耦合:DestroyTiles中同时处理方块销毁和冷却层生成,可能干扰方块销毁的执行时机。
  3. 碰撞遍历顺序问题:原遍历逻辑找到第一个碰撞方块就终止,若子弹同时覆盖多个方块,可能选中错误的目标方块。

修复代码

1. 优化碰撞检测(改用子弹中心点检测)
public boolean bulletCollision() {
    boolean is = false;
    if (shooting) {
        // 计算子弹中心点坐标
        int shotCenterX = shot.pointX + yg.tileSize / 2;
        int shotCenterY = shot.pointY + yg.tileSize / 2;
        for (ArrayList<Tile> sampleRow : tm.rows) {
            for (Tile tile : sampleRow) {
                if (tile.isActive) {
                    int tilePixelX = tile.x * yg.tileSize;
                    int tilePixelY = tile.y * yg.tileSize;
                    // 检测中心点是否在方块范围内,精度更高
                    if (shotCenterX >= tilePixelX 
                        && shotCenterX < tilePixelX + yg.tileSize 
                        && shotCenterY >= tilePixelY 
                        && shotCenterY < tilePixelY + yg.tileSize) {
                        is = true;
                        hitTile = tile;
                        break;
                    }
                }
            }
            if (is) {
                break;
            }
        }
    }
    return is;
}
2. 分离冷却逻辑与销毁逻辑
public void DestroyTiles() {
    // 仅处理方块销毁逻辑
    Hit(0, 0, 1);
    Hit(1, 0, 1);
    Hit(0, 1, 1);
    Hit(-1, 0, 1);
    Hit(0, -1, 1);
}

public void update() {
    // 独立处理冷却与新层生成
    if (cooldown > 0) {
        cooldown--;
    } else if (cooldown == 0) {
        tm.NewLayer();
        cooldown = 2;
    }

    if (shooting) {
        shot.update();
        if (bulletCollision()) {
            DestroyTiles();
            shooting = false;
            shot = null;
        } else if (shot.pointY < 0) {
            shooting = false;
            shot = null;
        }
    }
}
3. 额外验证点
  • 确认TileManager.GetTile方法能正确处理边界坐标(超出网格范围时返回null),避免空指针或数组越界。
  • 检查Shot类的update方法,确保子弹移动速度不会过快导致碰撞检测跳过方块(可添加分步检测或调整速度)。

内容的提问来源于stack exchange,提问作者Emil Coder

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 19:30:06