Java原生Pac-Man游戏中间墙体精准碰撞检测问题求助
解决Pac-Man精准碰撞检测问题的方案
原代码的核心问题
- 仅检测目标位置对应的单个tile,忽略了角色碰撞盒可能覆盖多个tile的情况,导致部分墙体未被识别,出现轻微穿墙。
- 边界计算逻辑冗余且不准确,未基于角色实际碰撞范围做判断。
- 移动时直接跳步到速度叠加后的位置,未处理“不可移动时精准停在墙前”的逻辑。
修正后的碰撞检测方案
1. 基于碰撞盒的canMove函数
角色是有体积的,需检测碰撞盒覆盖的所有tile是否均可通行。以下是修正后的函数:
// 31行,28列的地图 public static boolean canMove(int centerX, int centerY, String direction) { int tileSize = 16; // 设置碰撞盒半宽高:比tile半尺寸小2,避免卡墙且贴合原版手感 int collisionHalf = 6; // 计算碰撞盒的四个边界 int left = centerX - collisionHalf; int right = centerX + collisionHalf; int top = centerY - collisionHalf; int bottom = centerY + collisionHalf; // 先判断碰撞盒是否超出地图整体边界 if (left < 0 || right >= tileSize * 28 || top < 0 || bottom >= tileSize * 31) { return false; } // 获取碰撞盒覆盖的所有tile的行列范围 int startRow = top / tileSize; int endRow = bottom / tileSize; int startCol = left / tileSize; int endCol = right / tileSize; // 遍历所有覆盖的tile,只要有一个不可通行就返回false for (int row = startRow; row <= endRow; row++) { for (int col = startCol; col <= endCol; col++) { // 防止行列越界 if (row < 0 || row >= 31 || col < 0 || col >= 28) { return false; } // 仅1、3、4为可通行tile if (map[row][col] != 1 && map[row][col] != 3 && map[row][col] != 4) { return false; } } } return true; }
2. 精准停墙的移动逻辑
不能直接禁止移动,而是当检测到不可移动时,将角色定位到墙体边缘:
int speed = 4; int tileSize = 16; int collisionHalf = 6; int currentX = // 角色当前X坐标 int currentY = // 角色当前Y坐标 switch(direction) { case "LEFT": int newXLeft = currentX - speed; if (canMove(newXLeft, currentY, direction)) { currentX = newXLeft; } else { // 计算左侧墙体的右侧边缘,将角色贴墙放置 int currentCol = currentX / tileSize; currentX = currentCol * tileSize + (tileSize - collisionHalf); } break; case "RIGHT": int newXRight = currentX + speed; if (canMove(newXRight, currentY, direction)) { currentX = newXRight; } else { int currentCol = currentX / tileSize; currentX = (currentCol + 1) * tileSize - collisionHalf; } break; case "UP": int newYUp = currentY - speed; if (canMove(currentX, newYUp, direction)) { currentY = newYUp; } else { int currentRow = currentY / tileSize; currentY = currentRow * tileSize + (tileSize - collisionHalf); } break; case "DOWN": int newYDown = currentY + speed; if (canMove(currentX, newYDown, direction)) { currentY = newYDown; } else { int currentRow = currentY / tileSize; currentY = (currentRow + 1) * tileSize - collisionHalf; } break; }
关键逻辑说明
- 碰撞盒覆盖所有可能接触的tile,彻底避免漏检墙体。
- 移动时优先尝试完整速度位移,不可行时计算墙体边缘坐标,让角色精准停在墙前,消除穿墙现象。
- 碰撞盒尺寸留有余量,避免角色被墙体卡住,同时贴合原版Pac-Man的移动手感。
内容的提问来源于stack exchange,提问作者user22495401
相关产品推荐
相关产品推荐

