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

Java顶视角2D游戏碰撞检测Bug求助:速度翻倍、数组越界

8方向顶视角2D游戏碰撞检测Bug修复方案

问题汇总

  • 玩家向下移动时速度翻倍,直接超出5x5测试地图边界,随后游戏卡顿、玩家无法移动
  • 控制台抛出数组越界异常:

    Exception in thread "Thread-0" java.lang.ArrayIndexOutOfBoundsException: Index 5 of 5 out of bounds for length 5
    at lu.embellishedduck.liminalmurmurs.engine.CollisionDetection.checkTileCollision(CollisionDetection.java:134)

  • 单一方向碰撞墙体后,尝试斜向移动会被推入墙体约4像素并卡住

核心Bug根源分析

1. 重复移动导致速度翻倍(Player类)

在Player.update()方法的主移动分支中,向下移动被执行了两次位移操作:

if (keyHandler.isDownPressed()) {
    setDirection("down");
    worldY += getMovementSpeed(); // 第一次位移
}

之后在无碰撞校验通过的switch分支中,又执行了第二次位移:

case "down" :
    worldY += getMovementSpeed(); // 第二次位移
    break;

双重位移直接导致向下速度翻倍,玩家瞬间冲出地图边界,触发数组越界。

2. 无边界校验引发数组越界(CollisionDetection类)

碰撞检测时未对计算出的行列索引做合法性校验,当玩家超出地图后,entityBottomRow会等于5(5x5地图有效行索引为0-4),直接访问mapTileNum[entityLeftCol][5]触发数组越界,进而导致游戏逻辑卡顿。

3. 斜向碰撞检测覆盖不全

斜向移动的碰撞检测仅检查单个角落的Tile,未覆盖移动路径上的所有可能碰撞点,导致碰撞处理不精准,出现被推入墙体的情况。

修复方案

1. 修复重复移动问题

修改Player.update()方法中向下移动的代码,移除多余的位移操作:

// 原代码
if (keyHandler.isDownPressed()) {
    setDirection("down");
    worldY += getMovementSpeed(); // 删除此行
}

2. 添加碰撞检测边界校验

在CollisionDetection.checkTileCollision()方法中,所有访问mapTileNum数组的操作前,添加索引合法性校验。以向下移动分支为例:

case "down" :
    entityBottomRow = (entityBottomWorldY + entity.getMovementSpeed()) / gamePanel.getTILE_SIZE();
    
    // 添加边界校验:超出地图范围直接标记碰撞
    int mapColCount = gamePanel.getTileManager().getMapTileNum().length;
    int mapRowCount = gamePanel.getTileManager().getMapTileNum()[0].length;
    if (entityBottomRow >= mapRowCount || entityBottomRow < 0 ||
        entityLeftCol >= mapColCount || entityLeftCol < 0 ||
        entityRightCol >= mapColCount || entityRightCol < 0) {
        entity.setCollisionOn(true);
        break;
    }

    tileNum1 = gamePanel.getTileManager().getMapTileNum()[entityLeftCol][entityBottomRow];
    tileNum2 = gamePanel.getTileManager().getMapTileNum()[entityRightCol][entityBottomRow];

    if (gamePanel.getTileManager().getTiles()[tileNum1].isCollision() || 
        gamePanel.getTileManager().getTiles()[tileNum2].isCollision()) {
        entity.setCollisionOn(true);
    }
    break;

其他方向(up、left、right及所有斜向)需添加类似的边界校验逻辑。

3. 优化斜向碰撞检测覆盖范围

以up-left方向为例,修改碰撞检测逻辑,覆盖移动路径上的多个Tile:

case "up-left" :
    int predictedTopRow = (entityTopWorldY - entity.getMovementSpeed()) / gamePanel.getTILE_SIZE();
    int predictedLeftCol = (entityLeftWorldX - entity.getMovementSpeed()) / gamePanel.getTILE_SIZE();
    
    // 边界校验
    int mapColCount = gamePanel.getTileManager().getMapTileNum().length;
    int mapRowCount = gamePanel.getTileManager().getMapTileNum()[0].length;
    if (predictedTopRow < 0 || predictedLeftCol < 0 ||
        predictedLeftCol >= mapColCount || predictedTopRow >= mapRowCount) {
        entity.setCollisionOn(true);
        break;
    }

    // 检查左上角、左列当前行、上列当前列的Tile
    int tileNum1 = gamePanel.getTileManager().getMapTileNum()[predictedLeftCol][predictedTopRow];
    int tileNum2 = gamePanel.getTileManager().getMapTileNum()[predictedLeftCol][entityTopRow];
    int tileNum3 = gamePanel.getTileManager().getMapTileNum()[entityLeftCol][predictedTopRow];

    if (gamePanel.getTileManager().getTiles()[tileNum1].isCollision() ||
        gamePanel.getTileManager().getTiles()[tileNum2].isCollision() ||
        gamePanel.getTileManager().getTiles()[tileNum3].isCollision()) {
        entity.setCollisionOn(true);
    }
    break;

其他斜向方向(up-right、down-left、down-right)需按照此逻辑扩展碰撞检测覆盖范围。

验证步骤

  1. 运行游戏,测试向下移动,确认速度恢复正常,不会超出地图边界
  2. 测试所有8个方向的移动,包括碰撞墙体后的斜向移动,确认不再出现卡顿或被推入墙体的情况
  3. 查看控制台,确认数组越界异常不再抛出

内容的提问来源于stack exchange,提问作者Will Blanchard

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 06:00:56