Java 2D横版平台游戏跳跃撞墙上下瞬移bug如何修复
碰撞bug根因
- 地面碰撞缺少下落状态校验:当前只要瓦片处于角色下方行、左右列匹配就直接把角色Y坐标拉到瓦片顶部,哪怕角色正处于向上跳跃的状态也会触发,这是跳跃碰墙瞬移的核心原因
- 碰撞检测顺序错误:先处理垂直方向(地面/头顶)碰撞,再处理水平侧面碰撞,跳跃碰墙时X轴位置还没修正,就先触发了垂直方向的错误判定
- 行列参数计算位置错误:row、rowBelow等行列值放在瓦片遍历循环内部计算,每次修改X/Y坐标后,后续瓦片检测用的是修改后的坐标,导致判定逻辑混乱
- 侧面碰撞判定条件过窄:原判定绑定了角色行和瓦片行相等的逻辑,跳跃过程中角色跨两行时无法触发侧面碰撞,导致穿墙后被垂直瞬移
修复代码
你可以直接替换原有collisionCheck方法的代码:
public void collisionCheck(){ // 行列坐标提前计算,仅使用修正前的原始坐标计算,避免循环内修改坐标导致判定混乱 int row = y / Game.TILE_SIZE; int rowBelow = y / Game.TILE_SIZE + 1; int columnLeft = x / Game.TILE_SIZE; int columnRight = (x + width) / Game.TILE_SIZE; for (ArrayList<Integer> tile: Game.tileCoordinates){ // 先处理水平侧面碰撞 // 判定角色和瓦片在Y轴有重叠即可检测侧面碰撞,不需要绑定行相等 if (y + height > tile.get(1) && y < tile.get(1) + Game.TILE_SIZE) { // 碰撞左侧 if (x + width >= tile.get(0) && x < tile.get(0)) { x = tile.get(0) - width; } // 碰撞右侧 if (x < tile.get(0) + Game.TILE_SIZE && x + width > tile.get(0) + Game.TILE_SIZE) { x = tile.get(0) + Game.TILE_SIZE; } } // 处理头顶碰块(Y轴向上碰撞) if (tile.get(1) / Game.TILE_SIZE == row && (tile.get(0) / Game.TILE_SIZE == columnLeft || tile.get(0) / Game.TILE_SIZE == columnRight)){ if (jumping && velocity < 0) { // 仅向上跳跃时触发头顶碰撞 y = tile.get(1) + Game.TILE_SIZE; velocity = 0; jumping = false; falling = true; // 头顶碰块后直接转为下落状态 Game.spacePressed = false; } } // 处理地面碰撞(Y轴向下碰撞) if (tile.get(1) / Game.TILE_SIZE == rowBelow){ if ((tile.get(0) / Game.TILE_SIZE == columnLeft || tile.get(0) / Game.TILE_SIZE == columnRight) && velocity > 0) { // 仅下落状态触发地面碰撞 y = tile.get(1) - height; velocity = 0; if (jumping) { jumping = false; Game.spacePressed = false; dustAfterShowed = false; xAfterJump = x; yAfterJump = y; } if (falling){ falling = false; } } } } }
注:上述代码默认游戏坐标系Y轴向下为正,向上跳跃时velocity为负值,和常规2D游戏坐标系逻辑一致,如果你的项目velocity正负定义相反,调整对应判定的大于/小于符号即可。
额外优化建议
如果后续还想优化碰撞性能,可以提前过滤掉和角色行列不相邻的瓦片,不需要遍历所有瓦片做判定,能大幅降低循环计算量。
内容的提问来源于stack exchange,提问作者Bjorn
相关产品推荐
相关产品推荐

