zoukankan      html  css  js  c++  java
  • 多线程之碰撞小球

    弹球游戏是一款模拟多线程运行的游戏,利用继承Thread实现多线程。

    效果图:小球之间会相互碰撞并交换速度在弹开。按钮能实现随机添加、移除小球并暂停小球移动。

    具体实现:

    1、创建界面(包含主函数)。

    public class BallFrame extends JFrame {
    public static void main(String[] args) { BallFrame bf = new BallFrame(); bf.initUI(); } public void initUI(){ //设置界面属性,包括按钮背景,添加监听 } }
    //创建一个链表存储小球
           private ArrayList<Ball> list = new ArrayList<Ball>();

    2、创建小球类,继承Thread类。这个类包含以下内容。

    public class Ball extends Thread { 
    //需要设置的属性有:
    private int x, y;// 小球圆心坐标
        private Graphics2D g;
        Random rand = new Random();
        private ArrayList<Ball> list;//存贮每个小球
        int r = 12;//小球半径
        int green,red,blue;//小球的颜色 }

    (1)、重写构造方法,主要用来传递参数,包括画笔,面板等。

    (2)、画一个小球的方法。

    public void drawNew(Graphics2D g) {
            // 绘制新的小球
            for (int i = r; i > 0; i--) {
    //设置颜色使小球看起来具有立体感。
    if(green<235)green=G + 8*(r-i) ; if(red<235)red=R + 8*(r-i) ; if(blue<235)blue=B + 8*(r-i) ; g.setColor(new Color(green,red,blue)); g.fillOval(x - r / 2 - i / 2, y - r / 2 - i / 2, i * 2, i * 2); } }

    (3)、小球的移动方法。

    public void move() {
            x += xspeed;
            y = y+yspeed;
        }

    (4)、擦除小球的方法,画出新的小球之前要把上一个小球擦出,不然画不出小球的动态效果。

    public void draw(Graphics2D g) {
    
            // 擦除上一次绘制的小球
            g.setColor(Color.black);
            g.fillOval(x - r - 1, y - r - 1, r * 2 + 2, r * 2 + 2);
        }

    (5)、判断小球碰撞的方法,判断这个小球是否与链表内其他的小球存在碰撞,同时也判断是否与边界发生碰撞。

    public void collide() {
            int index=list.indexOf(this);
                    for (int i =index; i < list.size(); i++) {
                Ball ball = list.get(i);
                // 判断是否发生碰撞
                if (ball != this) {
                    // 计算两个小球的距离
                    int d = (int) Math.sqrt((this.x - ball.x) * (this.x - ball.x)
                            + (this.y - ball.y) * (this.y - ball.y));
                    if (d < (this.r + ball.r+2)) {
                        int m = this.xspeed;
                        this.xspeed = ball.xspeed;
                        ball.xspeed = m;
                        m = this.yspeed;
                        this.yspeed = ball.yspeed;
                        ball.yspeed = m;
                    }
                }
            }
    //判断是否与边界发生碰撞
    if (x + r > centerPanel.getWidth() || x < r) xspeed = -xspeed; if (y + r > centerPanel.getHeight() || y < r) yspeed = -yspeed; }

    (6)、线程运行的方法。

        public void run() {
            while (true) {
                this.draw(g);
                this.move();
                this.collide();
                this.drawNew(g);
                try {
    //每40ms循环一次模拟小球的动态效果 Thread.sleep(
    40); } catch (InterruptedException e) { e.printStackTrace(); } } }

    3、事件的处理(添加、删除、暂停),主要通过鼠标实现。

    (1)、添加小球。在随机位置产生一个小球,初始速度也随机。

    if (e.getActionCommand().equals("添加")) {
    //随机设置小球的初始位置
    int x = rand.nextInt(centerPanel.getWidth() - 24) + 12; int y = rand.nextInt(centerPanel.getHeight() - 24) + 12; // 创建小球对象 Ball ball = new Ball(list, x, y, centerPanel, this); ball.start();//启动线程 list.add(ball);//将小球存入链表 System.out.println(list.size()); flag = true; }

    (2)、删除小球,随机删除界面中一个小球。

     if (e.getActionCommand().equals("移除")) {
                // 随机移除小球
                if (list.size() > 0) {
                    int index = rand.nextInt(list.size());
                    Ball ball = list.remove(index);
                    ball.draw(g);//清除被移除的小球
                    ball.stop();
                    System.out.println(ball);
                } else
                    System.out.println("没有可移除的小球!");
            } 

    (3)、暂停小球。

    Thread中有可以让线程等待的方法,但是时间不具有灵活性,这里考虑用sleep方法来实现。

    在run()方法中插入sleep,手动改变sleep的条件。

    public void run() {
            while (true) {
                this.draw(g);
                this.move();
                this.collide();
                this.drawNew(g);
                try {
                    Thread.sleep(40);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
    
    //以下是插入的代码
                while(flag){  //flag就是控制暂停的条件
                    try {
                        Thread.sleep(1);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }

    //监听中的方法
    if (e.getActionCommand().equals("暂停")) {
                if (flag == false) {
                    flag = true;
                } else if (flag == true) {
                    flag = false;
                }    
                for (int i = 0; i < list.size(); i++) {
                        Ball ball = list.get(i);
                        ball.setFlag(flag);
                    }
            }

    完整代码:

    import java.awt.BorderLayout;
    import java.awt.Color;
    
    import javax.swing.JButton;
    import javax.swing.JFrame;
    import javax.swing.JPanel;
    
    public class BallFrame extends JFrame {
    
        private static final long serialVersionUID = 1L;
    
        public static void main(String[] args) {
            //线程
            BallFrame bf = new BallFrame();
            bf.initUI();
        }
        
        public void initUI(){
            this.setTitle("弹球");
            this.setSize(400, 500);
            this.setDefaultCloseOperation(3);
            this.setLocationRelativeTo(null);
            this.setResizable(false);
            
            /***********北边************/
            JPanel northPanel = new JPanel();
            northPanel.setBackground(Color.black);
            JButton butAdd = new JButton("添加");
            JButton butRemove = new JButton("移除");
            JButton butPause = new JButton("暂停");
            
            northPanel.add(butAdd);
            northPanel.add(butRemove);
            northPanel.add(butPause);
            this.add(northPanel,BorderLayout.NORTH);
            
            
            /***********中间************/
            JPanel centerPanel = new JPanel();
            centerPanel.setBackground(Color.black);
            this.add(centerPanel,BorderLayout.CENTER);
            this.setVisible(true);
    
            //事件处理类
            BallListener bl = new BallListener(centerPanel);
            //给事件源添加动作监听方法,指定事件处理类的对象bl
            butAdd.addActionListener(bl);
            butRemove.addActionListener(bl);
            butPause.addActionListener(bl);
        }
    
    }
    import java.awt.Color;
    import java.awt.Graphics2D;
    import java.awt.RenderingHints;
    import java.util.ArrayList;
    import java.util.Random;
    
    import javax.swing.JPanel;
    
    /**
     * 小球类
     */
    public class Ball extends Thread {
    
        private int x, y;// 小球圆心坐标
        private Graphics2D g;
        Random rand = new Random();
        private JPanel centerPanel;
        private ArrayList<Ball> list;
        int r = 12;
        int green,red,blue;
        int G = rand.nextInt(155);
        int R = rand.nextInt(155);
        int B = rand.nextInt(155);
        int xspeed =  3;
        int yspeed =  3;
        BallListener bl;
    
        public Ball(ArrayList<Ball> list, int x, int y, JPanel centerPanel,
                BallListener bl) {
            this.x = x;
            this.y = y;
            this.list = list;
            this.centerPanel = centerPanel;
            this.g = (Graphics2D) centerPanel.getGraphics();
            this.bl = bl;
            // 设置取表画笔的锯齿状
            g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                    RenderingHints.VALUE_ANTIALIAS_ON);
        }
    
        private boolean flag = true;
    
        public void setFlag(boolean flag) {
            this.flag = flag;
        }
    
        public boolean getFlag() {
            return flag;
        }
    
        public void draw(Graphics2D g) {
    
            // 擦除上一次绘制的小球
            g.setColor(Color.black);
            g.fillOval(x - r - 1, y - r - 1, r * 2 + 2, r * 2 + 2);
        }
    
        public void drawNew(Graphics2D g) {
            // 绘制新的小球
            for (int i = r; i > 0; i--) {
                if(green<235)green=G +  8*(r-i) ;
                if(red<235)red=R +  8*(r-i) ;
                if(blue<235)blue=B +  8*(r-i) ;
                g.setColor(new Color(green,red,blue));
                g.fillOval(x - r / 2 - i / 2, y - r / 2 - i / 2, i * 2, i * 2);
            }
        }
    
        public void move() {
            x += xspeed;
            y = (int)(y+yspeed);
        }
    
        public void collide() {
            int index=list.indexOf(this);
                    for (int i =index; i < list.size(); i++) {
                Ball ball = list.get(i);
                // 判断是否发生碰撞
                if (ball != this) {
                    // 计算两个小球的距离
                    int d = (int) Math.sqrt((this.x - ball.x) * (this.x - ball.x)
                            + (this.y - ball.y) * (this.y - ball.y));
                    if (d < (this.r + ball.r+2)) {
                        int m = this.xspeed;
                        this.xspeed = ball.xspeed;
                        ball.xspeed = m;
                        m = this.yspeed;
                        this.yspeed = ball.yspeed;
                        ball.yspeed = m;
                    }
                }
            }
                    if (x + r > centerPanel.getWidth() || x < r)
                        xspeed = -xspeed;
                    if (y + r > centerPanel.getHeight() || y < r)
                        yspeed = -yspeed;
        }
    
        public void run() {
            while (true) {
                this.draw(g);
                this.move();
                this.collide();
                this.drawNew(g);
                try {
                    Thread.sleep(40);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                while(flag^true){
                    try {
                        Thread.sleep(1);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
    package study0528ball;
    
    import java.awt.Graphics2D;
    import java.awt.RenderingHints;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.util.ArrayList;
    import java.util.Random;
    
    import javax.swing.JPanel;
    
    public class BallListener implements ActionListener {
    
        private JPanel centerPanel;
        private Graphics2D g;
        private ArrayList<Ball> list = new ArrayList<Ball>();
        private boolean flag;
        private Random rand = new Random();
    
        public boolean isFlag() {
            return flag;
    
        }
    
        public BallListener(JPanel centerPanel) {
            this.centerPanel = centerPanel;
            g = (Graphics2D) centerPanel.getGraphics();// 强制转型
            // 设置取表画笔的锯齿状
            g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                    RenderingHints.VALUE_ANTIALIAS_ON);
        }
    
        @SuppressWarnings("deprecation")
        @Override
        public void actionPerformed(ActionEvent e) {
            if (e.getActionCommand().equals("添加")) {
                int x = rand.nextInt(centerPanel.getWidth() - 24) + 12;
                int y = rand.nextInt(centerPanel.getHeight() - 24) + 12;
                // 创建小球对象
                Ball ball = new Ball(list, x, y, centerPanel, this);
                ball.start();
                list.add(ball);
                System.out.println(list.size());
                flag = true;
            }
    
            else if (e.getActionCommand().equals("移除")) {
                // 随机溢出小球
                if (list.size() > 0) {
                    int index = rand.nextInt(list.size());
                    Ball ball = list.remove(index);
                    ball.draw(g);
                    ball.stop();
                    System.out.println(ball);
                } else
                    System.out.println("没有可移除的小球!");
            } else if (e.getActionCommand().equals("暂停")) {
                if (flag == false) {
                    flag = true;
                } else if (flag == true) {
                    flag = false;
                }    
                for (int i = 0; i < list.size(); i++) {
                        Ball ball = list.get(i);
                        ball.setFlag(flag);
                    }
            }
        }
    
    }
  • 相关阅读:
    VBA基础四:数据库链接(WPS2019)
    VBA基础三:循环(DO...LOOP,)
    随机多人红包
    概率抽奖
    七步轻松实现大数据库表的数据转储
    SQL Server中的行列倒置技巧
    把对应表的字段跨表赋值
    sql内日期格式化输出
    事务的用法
    女孩,你为什么不沉住气奋斗
  • 原文地址:https://www.cnblogs.com/xiao-v/p/4570564.html
Copyright © 2011-2022 走看看