Java实现俄罗斯方块:JLabel方块碰撞检测与停止移动问题
解决俄罗斯方块方块碰撞停止问题
别用颜色检测来判断碰撞,这种方式既不可靠又容易出bug——JLabel的渲染延迟、边框像素干扰都会让检测结果出错。直接通过坐标+已落地方块的位置记录来做碰撞检测才是正确的思路,具体实现步骤如下:
1. 维护落地方块的位置记录
创建一个二维数组(比如boolean[][] occupiedGrid),用来标记游戏区域内每个网格单元是否已经被落地的方块占据。假设每个方块尺寸固定为40x40,游戏区域是10列20行的网格,数组可定义为boolean[10][20]。
每当有方块停止下落时,就把该方块(包括piece和piece2)占据的网格位置在数组中标记为true。
2. 修改定时器的碰撞检测逻辑
在原有底部边界检测的基础上,加入“下一个位置是否存在障碍物”的判断:
- 计算当前下落方块(piece和piece2)下落一格后的y坐标
- 将像素坐标转换为网格坐标,检查对应
occupiedGrid位置是否为true,或是否超出游戏区域底部 - 若满足任一条件,立即停止定时器并执行后续逻辑
修改后的示例代码
// 类级别变量:网格记录、方块尺寸、游戏区域底部边界 private boolean[][] occupiedGrid = new boolean[10][20]; private static final int BLOCK_SIZE = 40; private static final int GAME_AREA_BOTTOM = 825; Runnable timer = new Runnable() { public void run() { boolean shouldStop = false; // 检测piece的碰撞 int nextPieceY = piece.getY() + BLOCK_SIZE; int pieceGridRow = nextPieceY / BLOCK_SIZE; int pieceGridCol = (piece.getX() - 40) / BLOCK_SIZE; // 40为游戏区域左侧x偏移,需根据实际调整 if (nextPieceY + piece.getHeight() >= GAME_AREA_BOTTOM || (pieceGridRow < 20 && occupiedGrid[pieceGridCol][pieceGridRow])) { shouldStop = true; } // 检测piece2的碰撞(若存在) if (!shouldStop && piece2 != null) { int nextPiece2Y = piece2.getY() + BLOCK_SIZE; int piece2GridRow = nextPiece2Y / BLOCK_SIZE; int piece2GridCol = (piece2.getX() - 40) / BLOCK_SIZE; if (nextPiece2Y + piece2.getHeight() >= GAME_AREA_BOTTOM || (piece2GridRow < 20 && occupiedGrid[piece2GridCol][piece2GridRow])) { shouldStop = true; } } if (shouldStop) { executor.shutdown(); // 将当前方块标记到网格中 markBlockToGrid(piece); if (piece2 != null) markBlockToGrid(piece2); block(); time(); } else { // 正常下落一格 piece.setLocation(piece.getX(), piece.getY() + BLOCK_SIZE); if (piece2 != null) { piece2.setLocation(piece2.getX(), piece2.getY() + BLOCK_SIZE); } } } }; // 辅助方法:将方块位置标记到网格 private void markBlockToGrid(JLabel block) { int gridCol = (block.getX() - 40) / BLOCK_SIZE; int gridRow = block.getY() / BLOCK_SIZE; // 若方块是多格组成的形状,需遍历所有占据的网格单元 if (gridCol >= 0 && gridCol < 10 && gridRow >= 0 && gridRow < 20) { occupiedGrid[gridCol][gridRow] = true; } } // 启动定时器 executor.scheduleAtFixedRate(timer, 2, 1, TimeUnit.SECONDS);
关键说明
- 放弃颜色检测:颜色检测依赖像素采样,极易因JLabel布局偏移、渲染抗锯齿等问题误判,坐标+网格记录的方式逻辑清晰且稳定。
- 网格坐标转换:需根据你的游戏界面布局,调整像素坐标到网格坐标的偏移量(比如示例中的左侧x偏移40)。
- 多格形状适配:如果方块由多个JLabel组成(如I型、L型),需要遍历所有组成方块的位置,逐个检查下一个位置是否存在碰撞。
内容的提问来源于stack exchange,提问作者MildArachnophobe
相关产品推荐
相关产品推荐

