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

基于ACM Graphics(Java)的吃豆人碰撞检测异常问题排查

帮你搞定吃豆人碰撞问题~

嘿,我看了你写的两段代码,问题的核心其实都是碰撞检测的时机和碰撞后的处理逻辑不对,导致吃豆人要么穿砖块,要么卡里面。我来给你拆解下问题,再给你修正方案:

第一个版本的问题

你先让吃豆人完成移动,再检测碰撞,这时候吃豆人已经钻进砖块里了,再调用pac.move(0,0)根本没用——因为这个方法只是让它不移动,但已经穿进去的位置不会变。而且你的碰撞方向判断逻辑也没起到实际作用,就算判断对了方向,也没有把吃豆人移回砖块外面。

先贴下你原来的代码方便对照:

private void gameLoop() { 
    boolean done = false; 
    while (!done) { 
        if(pacmanState == "right") { 
            pac.move(20, 0); 
            pause(100); 
        } 
        if(pacmanState == "left") { 
            pac.move(-20, 0); 
            pause(100); 
        } 
        if(pacmanState == "down") { 
            pac.move(0, 20); 
            pause(100); 
        } 
        if(pacmanState == "up") { 
            pac.move(0, -20); 
            pause(100); 
        } 
        if(pac.getBounds().intersects(b2.getBounds())) { 
            if(pac.getY() <= b2.getY() - (b2.getHeight()/2)) { //Hit was from below the brick 
                pac.move(0, 0); 
            } 
            if(pac.getY() >= b2.getY()+ (b2.getHeight()/2)) { //Hit was from above the brick 
                pac.move(0, 0); 
            } 
            if(pac.getX() < b2.getX()) { //Hit was on left 
                pac.move(0, 0); 
            } 
            if(pac.getX() > b2.getX()){ //Hit was on right 
                pac.move(0, 0); 
            } 
        } 
    }
}

第二个switch版本的问题

你把移动和碰撞检测放switch里了,但逻辑还是乱的:先移动,然后如果碰撞了要么原地不动,要么又移动一次,这会导致吃豆人卡在砖块中间——因为移动后已经穿进去了,没有回退到碰撞前的位置,自然移不开。

你的switch代码片段:

switch (pacmanState) { 
    case "left": 
        pac.move(-20, 0); 
        pause(100); 
        if (pac.getBounds().intersects(b2.getBounds())) { 
            if (pac.getX() > b2.getX()) { 
                pac.move(0, 0); 
            } else { 
                pac.move(-20, 0); 
                pause(100); 
            } 
        } 
        break; 
}

修正方案:先记录位置,碰撞就回退

最直接有效的方法是:先保存吃豆人移动前的位置,尝试移动后检测碰撞,如果碰撞了就把它移回移动前的位置。这样既不会穿砖块,也不会卡里面。

修改后的代码示例:

private void gameLoop() {
    boolean done = false;
    while (!done) {
        // 第一步:记录移动前的坐标
        int prevX = pac.getX();
        int prevY = pac.getY();
        
        // 第二步:根据方向执行移动
        switch(pacmanState) {
            case "right":
                pac.move(20, 0);
                break;
            case "left":
                pac.move(-20, 0);
                break;
            case "down":
                pac.move(0, 20);
                break;
            case "up":
                pac.move(0, -20);
                break;
            default:
                // 没有方向时不移动
                break;
        }
        pause(100);
        
        // 第三步:检测碰撞,碰撞就回退到之前的位置
        if(pac.getBounds().intersects(b2.getBounds())) {
            pac.setLocation(prevX, prevY);
        }
    }
}

如果你需要更精确的方向碰撞(比如只回退X或Y轴,而不是整个位置),可以再优化:比如判断碰撞时X轴重叠还是Y轴重叠,只回退对应的轴。比如如果是左右方向碰撞,就只回退X坐标,Y坐标保持不变,这样体验更自然。

举个方向优化的例子:

if(pac.getBounds().intersects(b2.getBounds())) {
    // 计算X和Y方向的重叠量
    int overlapX = Math.min(pac.getX() + pac.getWidth(), b2.getX() + b2.getWidth()) - Math.max(pac.getX(), b2.getX());
    int overlapY = Math.min(pac.getY() + pac.getHeight(), b2.getY() + b2.getHeight()) - Math.max(pac.getY(), b2.getY());
    
    // 重叠量小的方向是碰撞的主要方向,只回退这个方向
    if(overlapX < overlapY) {
        // 左右方向碰撞,回退X坐标
        if(pac.getX() < b2.getX()) {
            pac.setLocation(b2.getX() - pac.getWidth(), pac.getY());
        } else {
            pac.setLocation(b2.getX() + b2.getWidth(), pac.getY());
        }
    } else {
        // 上下方向碰撞,回退Y坐标
        if(pac.getY() < b2.getY()) {
            pac.setLocation(pac.getX(), b2.getY() - pac.getHeight());
        } else {
            pac.setLocation(pac.getX(), b2.getY() + b2.getHeight());
        }
    }
}

这样处理后,吃豆人就会刚好停在砖块的边缘,不会穿进去也不会卡住啦~

内容的提问来源于stack exchange,提问作者zver.oxuyan.ushaq.2

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 09:49:50