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
相关产品推荐
相关产品推荐

