Java案例——小球的弹性碰撞

学习使用AWT时编写的一个模拟弹性碰撞的程序。

package Package1;

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

public class BallsTest {
    //创建窗口对象
    public Frame frame = new Frame("这是一个窗口容器Frame");
    //设置桌面(画布)宽度和高度
    public int TABLE_WIDTH = 500;
    public int TABLE_HEIGHT = 300;
    //设置球拍的宽度和高度
    public final int RACKET_WIDTH = 80;
    public final int RACKET_HEIGHT = 20;
    //定义变量,记录球拍的坐标
    public int racketX = 120;
    public final int racketY = 280;
    //设置小球颜色
    public Color[] Allcolor = {Color.BLUE, Color.GREEN, Color.CYAN, Color.BLACK, Color.MAGENTA};
    //是否结束游戏
    volatile boolean flag = false;

    //小球个数
    public volatile int num = 2;
    //设置重力加速度
    public int gravity = 1;
    //设置刷新周期
    public int delay = 30;

    private class Ball {
        //设置小球的半径
        public volatile int ballRadius;
        //定义变量,记录小球的坐标
        public volatile double ballX;
        public volatile double ballY;
        //定义变量,记录小球在x和y方向上分别移动的速度
        public volatile double speedX;
        public volatile double speedY;
        //设置小球颜色
        public Color color;
        Random random = new Random();

        //初始化时随机生成坐标速度等信息
        public Ball() {
            int SPEEDMAX = 20;
            int R_MIN = 20;
            int R_MAX = 25;

            this.ballRadius = random.nextInt(R_MAX - R_MIN) + R_MIN;
            this.ballX = random.nextInt(TABLE_WIDTH - 2 * this.ballRadius);
            this.ballY = random.nextInt(TABLE_HEIGHT / 2);
            this.speedX = random.nextInt(SPEEDMAX * 2) - SPEEDMAX + 5;
            this.speedY = 0;
            this.color = Allcolor[random.nextInt(Allcolor.length)];

        }

        public Ball(int ballX, int ballY, int speedX, int speedY, int ballRadius) {
            this.ballX = ballX;
            this.ballY = ballY;
            this.speedX = speedX;
            this.speedY = speedY;
            this.ballRadius = ballRadius;
        }

        public int getBallRadius() {
            return ballRadius;
        }

        public void setBallRadius(int BallRadius) {
            this.ballRadius = BallRadius;
        }

        public double getBallX() {
            return ballX;
        }

        public void setBallX(int ballX) {
            this.ballX = ballX;
        }

        public double getBallY() {
            return ballY;
        }

        public void setBallY(int ballY) {
            this.ballY = ballY;
        }

        public double getSpeedX() {
            return speedX;
        }

        public void setSpeedX(int speedX) {
            this.speedX = speedX;
        }

        public double getSpeedY() {
            return speedY;
        }

        public void setSpeedY(int speedY) {
            this.speedY = speedY;
        }
    }

    ArrayList<Ball> balls = new ArrayList<Ball>(); //创建一些小球

    //给小球组设置运动线程,并检测碰撞来修改它们的速度
    private class BallMovement implements Runnable {
        //每个线程负责跟踪一个小球
        private int ballId; //跟踪的小球索引

        public BallMovement(int ballId) {
            this.ballId = ballId;
        }

        private boolean isTouched(int ballId, int ballIdOther) {
            //碰撞检测
            Ball ball0 = balls.get(ballId);
            Ball ball1 = balls.get(ballIdOther);
            //获取本小球和其它小球的半径和速度、位置
            int ball0Radius = ball0.getBallRadius();
            double ball0X = ball0.getBallX();
            double ball0Y = ball0.getBallY();
            double x0 = ball0X + ball0Radius;
            double y0 = ball0Y + ball0Radius;

            int ball1Radius = ball1.getBallRadius();
            double ball1X = ball1.getBallX();
            double ball1Y = ball1.getBallY();
            double x1 = ball1X + ball1Radius;
            double y1 = ball1Y + ball1Radius;

            //根据是否发生碰撞改变各自小球类的内部变量值
            double deltaX = x1 - x0;
            double deltaY = y1 - y0;
            double distance = Math.sqrt((Math.pow(deltaX, 2) + Math.pow(deltaY, 2)));
            //如果发生碰撞
            boolean b = false;
            double d = ball0Radius + ball1Radius;
            if (distance <= d) {
//                double d = ball0.ballRadius + ball1.getBallRadius();
//                double x0 = ball0.ballX + ball0.ballRadius;
//                double y0 = ball0.ballY + ball0.ballRadius;
//                double x1 = ball1.ballX + ball1.ballRadius;
//                double y1 = ball1.ballY + ball1.ballRadius;
//                double deltaX = x1 - x0;
//                double deltaY = y1 - y0;
                //---------------------------------
//                double theta = Math.atan(deltaY/deltaX);
//                //修正一下两个小球的位置
//                theta = Math.abs(Math.atan(deltaY/deltaX));
//                double dx = d*Math.cos(theta);
//                double dy = d*Math.sin(theta);
//                if(deltaY >= 0 && deltaX >= 0) {
//                    ball0.ballX = x1 - dx -  ball0.ballRadius;
//                    ball0.ballY = y1 - dy -  ball0.ballRadius;
//                }
//                if(deltaY < 0 && deltaX >= 0) {
//                    ball0.ballX = x1 - dx -  ball0.ballRadius;
//                    ball0.ballY = y1 + dy -  ball0.ballRadius;
//                }
//                if(deltaY >= 0 && deltaX < 0) {
//                    ball0.ballX = x1 + dx -  ball0.ballRadius;
//                    ball0.ballY = y1 - dy -  ball0.ballRadius;
//                }
//                if(deltaY < 0 && deltaX < 0) {
//                    ball0.ballX = x1 + dx -  ball0.ballRadius;
//                    ball0.ballY = y1 + dy -  ball0.ballRadius;
//                }
                b = true;
            }
            return b;
        }

        @Override
        public void run() {
            double v0X;
            double v0Y;
            double l0;
            double victor01X;
            double victor01Y;
            double theta0;
            double vicTheta0;
            double vTheta0;
            double v1X;
            double v1Y;
            double l1;
            double victor10X;
            double victor10Y;
            double theta1;
            double vicTheta1;
            double vTheta1;

            double vicLength;
            double tempTheta1;
            double tempTheta2;

            while (!flag) {
                try {
                    Thread.sleep(delay); //设置刷新时间
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                //更新该小球下一时间点的位置
                balls.get(ballId).speedY += gravity;
                balls.get(ballId).ballX += balls.get(ballId).speedX;
                balls.get(ballId).ballY += balls.get(ballId).speedY;
                if (balls.get(ballId).ballX < 0) {
                    balls.get(ballId).ballX = 0;
                    balls.get(ballId).speedX = -balls.get(ballId).speedX; //反向运动
                } else if (balls.get(ballId).ballX > (TABLE_WIDTH - balls.get(ballId).ballRadius * 2)) {
                    balls.get(ballId).ballX = (TABLE_WIDTH - balls.get(ballId).ballRadius * 2);
                    balls.get(ballId).speedX = -balls.get(ballId).speedX; //反向运动
                }
                if (balls.get(ballId).ballY < 0) {
                    balls.get(ballId).ballY = 0;
                    balls.get(ballId).speedY = -balls.get(ballId).speedY; //反向运动
                } else if (balls.get(ballId).ballY > (TABLE_HEIGHT - balls.get(ballId).ballRadius * 2)) {
                    balls.get(ballId).ballY = (TABLE_HEIGHT - balls.get(ballId).ballRadius * 2);
                    balls.get(ballId).speedY = -balls.get(ballId).speedY; //反向运动
                }
                //更新该小球的速度属性
                for (int j = 0; j < balls.size(); j++) {
                    if (j > ballId && isTouched(ballId, j)) { //与所有其它小球进行碰撞检测
                        Ball ball0 = balls.get(ballId);
                        Ball ball1 = balls.get(j);

                        victor01X = ball1.getBallX() + ball1.getBallRadius() -
                                (ball0.getBallX() + ball0.getBallRadius());
                        victor01Y = ball1.getBallY() + ball1.getBallRadius() -
                                (ball0.getBallY() + ball0.getBallRadius());
                        vicTheta0 = Math.atan(victor01Y / victor01X);
                        vicLength = Math.sqrt(Math.pow(victor01X, 2) + Math.pow(victor01Y, 2));

                        v0X = (double) ball0.getSpeedX();
                        v0Y = (double) ball0.getSpeedY();
                        l0 = Math.sqrt(Math.pow(v0X, 2) + Math.pow(v0Y, 2));
                        vTheta0 = Math.atan(v0Y / v0X);
                        theta0 = Math.acos((v0X * victor01X + v0Y * victor01Y) / (l0 * vicLength));
                        if (vTheta0 > vicTheta0) {
                            tempTheta1 = vicTheta0 + Math.PI - theta0;
                        } else {
                            tempTheta1 = vicTheta0 - Math.PI + theta0;
                        }

                        victor10X = -victor01X;
                        victor10Y = -victor01Y;
                        vicTheta1 = Math.atan(victor10Y / victor10X);
                        v1X = (double) ball1.getSpeedX();
                        v1Y = (double) ball1.getSpeedY();
                        l1 = Math.sqrt(Math.pow(v1X, 2) + Math.pow(v1Y, 2));
                        vTheta1 = Math.atan(v1Y / v1X);
                        theta1 = Math.acos((v1X * victor10X + v1Y * victor10Y) / (l1 * vicLength));
                        if (vTheta1 > vicTheta1) {
                            tempTheta2 = vicTheta1 + Math.PI - theta1;
                        } else {
                            tempTheta2 = vicTheta1 - Math.PI + theta1;
                        }

                        ball0.speedX = (l1 * Math.cos(tempTheta2));
                        ball0.speedY = (l1 * Math.sin(tempTheta2));
                        ball1.speedX = (l0 * Math.cos(tempTheta1));
                        ball1.speedY = (l0 * Math.sin(tempTheta1));
                    }
                }
            }
        }
    }

    //自定义一个类继承Canvas充当画布
    private class MyCanvas extends Canvas {
        public MyCanvas(int TABLE_WIDTH, int TABLE_HEIGHT) {
            this.setPreferredSize(new Dimension(TABLE_WIDTH, TABLE_HEIGHT));
        }

        @Override
        public void paint(Graphics g) {
            //在这里绘制内容
            if (flag) {
                //游戏结束
                g.setColor(Color.BLUE);
                g.setFont(new Font("Times", Font.BOLD, 30));
                g.drawString("游戏结束!", 80, 200);
            } else {
                //游戏中
                //绘制小球
                for (int i = 0; i < balls.size(); i++) {
                    g.setColor(balls.get(i).color);
                    g.fillOval((int) balls.get(i).ballX, (int) balls.get(i).ballY,
                            balls.get(i).getBallRadius() * 2, balls.get(i).getBallRadius() * 2);
                }
                //绘制球拍
                g.setColor(Color.PINK);
                g.fillRect(racketX, racketY, RACKET_WIDTH, RACKET_HEIGHT);
            }
        }
    }

    //创建绘画区域(桌面)
    MyCanvas myCanvas = new MyCanvas(TABLE_WIDTH, TABLE_HEIGHT);
    Timer timer = new Timer(delay, new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent e) {
            myCanvas.repaint();
        }
    });

    //组装视图以及游戏逻辑的控制
    public void init() {
        //添加一系列小球
        balls = new ArrayList<Ball>();
        for (int i = 0; i < num; i++) {
            balls.add(new Ball());
        }
        //给球拍添加监听器以便控制球拍
        MouseMotionListener mouseMotionListener = new MouseMotionAdapter() {
            @Override
            public void mouseMoved(MouseEvent e) {
                //获取当前鼠标位置
                int mouseX = e.getX();
                if (mouseX < (RACKET_WIDTH / 2)) {
                    //设置球拍的位置
                    racketX = 0;
                } else if (mouseX > (TABLE_WIDTH - RACKET_WIDTH / 2)) {
                    racketX = TABLE_WIDTH - RACKET_WIDTH;
                } else {
                    racketX = mouseX - (RACKET_WIDTH / 2);
                }
            }
        };
        //给frame和myCanvas注册监听器
        myCanvas.addMouseMotionListener(mouseMotionListener);
        frame.addMouseMotionListener(mouseMotionListener);
        frame.add(myCanvas);

        //通过pack()方法设置最佳大小
        frame.pack();
        //设置Frame可见
        frame.setVisible(true);
        frame.setLocation(500, 200);

        //加入线程
        timer.start();
        for (int i = 0; i < balls.size(); i++) {
            new Thread(new BallMovement(i)).start();
        }
    }

    public static void main(String[] args) {
        new BallsTest().init();
    }
}

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值