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

Java Pong游戏AI对手行为异常问题求助

Java Pong游戏AI对手异常修复方案

问题概述

开发Java Pong游戏时,AI对手存在行为异常:快速上下移动、频繁瞬移、卡顿后突然瞬移,无法平滑跟随球的位置移动。

核心问题分析

  1. Opponent类move方法逻辑错误:存在笔误导致AI直接瞬移到顶部,且跟随逻辑冗余;
  2. 球位置更新顺序错误:AI移动时使用的是上一帧的球位置,导致跟随延迟;
  3. 无限重绘导致渲染异常:Board类paint方法中调用repaint(),引发无限重绘循环;
  4. Timer逻辑冗余:GamePlay中Timer的动作监听存在重复的球移动判断,且AI移动触发时机混乱;
  5. Ball类构造方法参数错误:误将ballHeight赋值给ballWidth,导致球的尺寸异常。

具体修复步骤

1. 修复Opponent类move方法

修正笔误,简化跟随逻辑,确保AI以自身中心为目标平滑跟随球:

public class Opponent {
    public int opponentXpos;
    public int opponentYpos;
    public int opponentWidth;
    public int opponentHeight;
    public int ballPos;
    Rectangle opponent;

    public Opponent(int opponentXpos, int opponentYpos, int opponentWidth, int opponentHeight) {
        this.opponentXpos = opponentXpos;
        this.opponentYpos = opponentYpos;
        this.opponentWidth = opponentWidth;
        this.opponentHeight = opponentHeight; // 修复参数赋值错误
        opponent = new Rectangle(opponentXpos, opponentYpos, opponentWidth, opponentHeight);
    }

    public void move() {
        // 限制AI在游戏区域内
        if (opponent.y >= 570) {
            opponent.y = 570;
        }
        if (opponent.y <= 50) {
            opponent.y = 50;
        }

        // 以AI paddle中心为目标,平滑跟随球的Y轴位置
        int targetY = ballPos - opponent.height / 2;
        if (opponent.y < targetY) {
            opponent.y += 1;
        } else if (opponent.y > targetY) {
            opponent.y -= 1;
        }
    }

    public void getBallPos(int ball) {
        this.ballPos = ball;
    }
}

2. 调整GamePlay中AI逻辑顺序

先更新球位置给AI,再执行AI移动,确保使用最新的球位置,同时简化Timer逻辑:

public class GamePlay extends JPanel implements KeyListener {
    public int playerScore = 0;
    public int opponentScore = 0;
    boolean over = false;
    Rectangle a;

    Opponent opponent = new Opponent(835, 300, 15, 80);
    Ball ball = new Ball(400, 350, 20, 20);

    public GamePlay(int x, int y, int z, int c) {
        this.a = new Rectangle(x, y, z, c);
        timer.start();
    }

    // 重命名并简化碰撞检测方法
    public void checkCollision() {
        if (ball.ball.intersects(opponent.opponent)) {
            ball.right = false;
        }

        if (ball.ball.x >= 862) {
            playerScore++;
            resetBall();
        }

        if (ball.ball.x <= 4) {
            opponentScore++;
            resetBall();
        }
    }

    // 重置球的位置和方向
    private void resetBall() {
        ball.ball.x = 400;
        ball.ball.y = 350;
        ball.up = ball.random.nextBoolean();
        ball.right = ball.random.nextBoolean();
    }

    Timer timer = new Timer(16, new ActionListener() { // 调整为16ms约60帧,提升稳定性
        @Override
        public void actionPerformed(ActionEvent e) {
            // 先同步最新球位置给AI
            opponent.getBallPos(ball.ball.y);
            // 执行AI移动
            opponent.move();
            // 执行球移动
            ball.move();
            // 检测碰撞
            checkCollision();

            if (playerScore == 5 || opponentScore == 5) {
                over = true;
                timer.stop();
            }
            // 触发重绘
            repaint();
        }
    });

    @Override
    public void keyPressed(KeyEvent e) {
        if (e.getKeyCode() == KeyEvent.VK_SPACE && over) {
            timer.start();
            opponentScore = 0;
            playerScore = 0;
            opponent.opponent.x = 835;
            opponent.opponent.y = 300;
            over = false;
            resetBall();
        }
    }

    @Override
    public void keyReleased(KeyEvent arg0) {}

    @Override
    public void keyTyped(KeyEvent arg0) {}
}

3. 修复Board类的无限重绘问题

移除paint方法中的repaint()调用,改用Timer触发重绘,同时调用父类paint方法清除画布:

import java.awt.*;
import javax.swing.*;

public class Board extends JPanel {
    GamePlay play = new GamePlay(0, 0, 900, 900);

    public Board() {
        addKeyListener(play);
        setFocusable(true);
    }

    @Override
    public void paint(Graphics g) {
        super.paint(g); // 清除上一帧绘制内容,避免残留
        Graphics2D g2 = (Graphics2D) g;
        g2.setColor(Color.black);
        g2.fill(play.a);
        g.setColor(Color.WHITE);
        board(g);
        g2.setColor(Color.white);
        g2.fill(play.opponent.opponent);
        g2.fill(play.ball.ball);

        if (play.playerScore == 5) {
            g.setColor(Color.WHITE);
            g.setFont(new Font("Arial", Font.BOLD, 20));
            g.drawString("You win!", 300, 300);
            g.drawString("press space bar to restart.", 300, 350);
        }
        if (play.opponentScore == 5) {
            g.setColor(Color.WHITE);
            g.setFont(new Font("Arial", Font.BOLD, 20));
            g.drawString("You lose!", 300, 300);
            g.drawString("press space bar to restart.", 300, 350);
        }
    }

    public void board(Graphics g) {
        Graphics2D g2d = (Graphics2D) g;
        Stroke stroke1 = new BasicStroke(4f);
        g2d.setColor(Color.white);
        g2d.setStroke(stroke1);
        g2d.drawRect(20, 50, 850, 600);
        g2d.setColor(Color.white);
        float[] dashingPattern2 = {10f, 4f};
        Stroke stroke2 = new BasicStroke(4f, BasicStroke.CAP_BUTT,
                BasicStroke.JOIN_MITER, 1.0f, dashingPattern2, 0.0f);
        g2d.setStroke(stroke2);
        g2d.drawLine(435, 50, 435, 650);
        g.setFont(new Font("arial", Font.PLAIN, 30));
        g.drawString(""+play.playerScore, 20, 35);
        g.drawString(""+play.opponentScore, 855, 35);
    }
}

4. 修复Ball类构造方法参数错误

修正ballHeight的赋值错误,确保球的尺寸正确:

import java.awt.*;
import java.util.Random;
import javax.swing.*;

public class Ball extends JPanel{
    public int ballXpos;
    public int ballYpos;
    public int ballWidth;
    public int ballHeight;
    boolean right = false;
    boolean up = true;
    Random random = new Random();

    Rectangle ball;

    public Ball(int ballXpos, int ballYpos, int ballWidth, int ballHeight){
        this.ballXpos = ballXpos;
        this.ballYpos = ballYpos;
        this.ballWidth = ballWidth;
        this.ballHeight = ballHeight; // 修复赋值错误
        up = random.nextBoolean();
        right = random.nextBoolean();
        ball = new Rectangle(ballXpos, ballYpos, ballWidth, ballHeight);
    } 

    public void move(){
        if(right == false){
            ball.x = ball.x - 1;
        }
        
        if(right == true){
            ball.x = ball.x + 1;
        }
        if(up == true){
            ball.y = ball.y - 1;
        }

        if(up == false){
            ball.y = ball.y + 1;
        }

        if(ball.x >= 863){
            resetBallPosition();
        }

        if(ball.x <= 3){
            resetBallPosition();
        }

        if(ball.y <= 38){
            up = false;
        }

        if(ball.y >= 630){
            up = true;
        }
    }

    private void resetBallPosition() {
        ball.x = 400;
        ball.y = 350;
        up = random.nextBoolean();
        right = random.nextBoolean();
    }
}

额外优化建议

  • 可给AI添加动态速度调整逻辑,比如球离AI越远,移动步长越大,提升AI真实感;
  • 统一使用Timer控制游戏帧率,避免过高帧率导致的性能消耗;
  • 为玩家添加 paddle 控制逻辑,完善游戏完整性。

内容的提问来源于stack exchange,提问作者Jon doe

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 08:53:08