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

Java随机弹跳球程序仅显示单个球的问题排查求助

问题根源及修复方案

1. 致命错误:误用静态变量存储球的属性

你把Ball类里的x、y、vx、vy、r、c都定义成了static,静态变量属于类本身,所有Ball实例会共享同一套值。这意味着你创建的100个球其实共用同一个位置、速度和颜色,最终看起来就只有一个球。必须去掉这些属性的static修饰符,让每个球拥有独立的属性。

2. 绘制逻辑错误

  • 每个球的draw()方法里调用StdDraw.clear(),会导致画一个球就清空一次画布,最后只能看到最后一个被绘制的球。应该把清空画布的操作放到主循环最开头,每次刷新帧只清空一次。
  • draw()里先画圆再设置画笔颜色,顺序完全反了,应该先设置颜色再绘制圆形,否则球会用默认颜色渲染。
  • 主循环里每次画一个球就调用StdDraw.show()和StdDraw.pause(),这会让每个球单独刷新,导致画面闪烁且无法同时显示所有球。正确做法是先完成所有球的绘制、移动、边界检测,再统一刷新画布并暂停。

3. 其他细节错误

  • 初始化球的do-while循环中,第二个循环判断的是Math.abs(x),应该改为Math.abs(y),否则y坐标的合法性判断完全错误。
  • 边界检测里用的是静态的r,应该替换为每个球自己的半径balls[i].getR()。
  • 初始化时r的第一次赋值在循环内,第一次循环时r还未初始化(默认值为0),会导致do-while条件判断异常,应该把r的生成放到对应的do-while循环前面。

修正后的完整代码

import java.util.Random;
import java.awt.Color;
import edu.princeton.cs.introcs.StdDraw;

public class Ball {
    // 去掉static,每个球拥有独立属性
    private double x;
    private double y;
    private double vx;
    private double vy;
    private double r;
    private Color c;
    
    private static int number;
    private static Ball[] balls;
    private static Color[] ballColors;
    
    public Ball(double x, double y, double vx, double vy, double r, Color c) {
        this.x = x;
        this.y = y;
        this.vx = vx;
        this.vy = vy;
        this.r = r;
        this.c= c;
    }
    
    public void test() {
        System.out.println("vx: "+vx+" ve vy: "+vy);
    }
    
    public static void setImage() {
        StdDraw.setCanvasSize(500, 500);
        StdDraw.setXscale(-1.0, 1.0);
        StdDraw.setYscale(-1.0, 1.0);
        StdDraw.enableDoubleBuffering();
    }
    
    public void move() {
        x = x + vx;
        y = y + vy;
    }
    
    public void draw() {
        // 先设置颜色再绘制圆形
        StdDraw.setPenColor(c);
        StdDraw.filledCircle(x, y, r);  
    }
    
    // 去掉getX、getVx的static修饰符,对应实例属性
    public double getX() {
        return x;
    }
    
    public double getY() {
        return y;
    }
    
    public double getVy() {
        return vy;
    }
    
    public double getVx() {
        return vx;
    }
    
    public double getR() {
        return r;
    }
    
    public void setX(double newX) {
        x = newX;
    }
    
    public void setY(double newY) {
        y = newY;
    }
    
    public void setVx(double newVx) {
        vx = newVx;
    }
    
    public void setVy(double newVy) {
        vy = newVy;
    }
    
    public void setR(double newR) {
        r = newR;
    }

    public static void main(String[] args) {
        Ball.setImage();
        
        number = 100;
        balls = new Ball[number];
        ballColors = new Color[] {StdDraw.GREEN, StdDraw.RED, StdDraw.BLUE};
        
        Random random = new Random();
        for (int i = 0; i < number; i++) {
            // 先生成半径,再判断坐标合法性
            double ballR = random.nextDouble() * 0.08 + 0.02; 
            double ballX;
            do {
                ballX = random.nextDouble() * 2 - 1;
            } while (Math.abs(ballX) > (1 - ballR));
            
            double ballY;
            do {
                ballY = random.nextDouble() * 2 - 1;
            } while (Math.abs(ballY) > (1 - ballR)); // 修正为判断y坐标
            
            double ballVx = random.nextDouble() * 0.04 - 0.02;
            double ballVy = random.nextDouble() * 0.04 - 0.02;
            Color ballC = ballColors[(random.nextInt(3))];
            balls[i] = new Ball(ballX, ballY, ballVx, ballVy, ballR, ballC);
        }
       
        while(true) {
            // 每次帧刷新先清空画布
            StdDraw.clear(StdDraw.BOOK_LIGHT_BLUE);
            
            for (int i = 0; i < number; i++) {
                balls[i].draw();
                balls[i].move();

                // 用当前球自己的半径做边界检测
                if(Math.abs(balls[i].getX() + balls[i].getVx()) > (1.0 - balls[i].getR())) {
                    balls[i].setVx(-balls[i].getVx());
                }
                
                if(Math.abs(balls[i].getY() + balls[i].getVy()) > (1.0 - balls[i].getR())) {
                    balls[i].setVy(-balls[i].getVy());
                }
            }
            
            // 所有球处理完后统一刷新画布并暂停
            StdDraw.show();
            StdDraw.pause(20);
        }
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 15:34:52