使用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); } } }
问题分析及修复方案
核心问题点
- 碰撞检测精度不足:原代码用缩小的子弹矩形做碰撞,容易出现擦碰误触发或漏触发的情况,导致效果不稳定。
- 冷却逻辑与销毁逻辑耦合:
DestroyTiles中同时处理方块销毁和冷却层生成,可能干扰方块销毁的执行时机。 - 碰撞遍历顺序问题:原遍历逻辑找到第一个碰撞方块就终止,若子弹同时覆盖多个方块,可能选中错误的目标方块。
修复代码
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
相关产品推荐
相关产品推荐

