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);
                    }
            }
        }
    
    }
  • 相关阅读:
    JID 2.0 RC4 发布,高性能的 Java 序列化库
    FBReaderJ 1.6.3 发布,Android 电子书阅读器
    Arquillian 1.0.3.Final 发布,单元测试框架
    JavaScript 的宏扩展 Sweet.js
    Hypertable 0.9.6.5 发布,分布式数据库
    JRuby 1.7.0 发布,默认使用 Ruby 1.9 模式
    httppp 1.4.0 发布,HTTP响应时间监控
    Redis 2.6.0 正式版发布,高性能K/V服务器
    OfficeFloor 2.5.0 发布,IoC 框架
    XWiki 4.3 首个里程碑发布
  • 原文地址:https://www.cnblogs.com/xiao-v/p/4570564.html
Copyright © 2011-2022 走看看