多线程之碰撞小球

弹球游戏是一款模拟多线程运行的游戏,利用继承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);
                }
        }
    }

}
时间: 2024-10-13 21:21:16

多线程之碰撞小球的相关文章

Java多线程-两个小球

1 import java.applet.*; 2 import java.awt.*; 3 import javax.swing.*; 4 5 public class MyBall { 6 public static void main(String[] args) { 7 JFrame w = new JFrame(); 8 w.setSize(300, 400); 9 MyPanel mp = new MyPanel(); 10 w.add(mp); 11 Thread b1 = new

jq手写碰撞小球

1 jQuery.fn.bump = function() { 2 var ele = $(this); 3 var eleW = ele.width(); 4 var eleH = ele.height(); 5 //运动的高度和宽度范围 6 var W = $(window).width()-eleW; 7 var H = $(window).height()-eleH; 8 window.onresize = function () { 9 W = $(window).width()-el

日更第4期-2015-1-19-openFrameworks系列第三讲-面向对象的小球们

昨天的教程里,实在有太多想讲的东西了,所以反而什么都没有讲.一个很大的原因就是——我妄想让所有 水平的读者都能读懂.这其实是绝对不可能的.因为,每个人知识面不同,已经掌握的技能也不同,那么所 适应的学习轨迹其实也该不同. 以我个人来说,我其实是一个谨慎型的人,在学习的过程中一般不会冒进,这意味着我的基础知识会更加 扎实,但是进步的速度就会偏慢.我在这里写博客,其实就是一种学习方式,但无疑,这种学习方式其实很 效率低下(而且还没有人看).可是,对于我就是一个很好的补充......感觉有点跑题了,其

Java多线程的应用总结

多线程的好处 :  在java中通常每一个任务称为一个线程,但是多线程实现一个程序同时执行多个任务. 直接了当的说多线程可以把任务分块执行,分块后可以同时进行而不用等待. 如下载文件, 浏览网站时加载图片,通过多线程就可以实现多文件下载,一下做好几个工作,这样效率更高, Java多线程实现方式主要有三种:继承Thread类.实现Runnable接口.使用ExecutorService.Callable.Future实现有返回结果的多线程.其中前两种方式线程执行完后都没有返回值,只有最后一种是带返

基于Seajs的可控台球碰撞游戏

前言 不记得哪个黑色星期五,贪吃鱼基本完工的时候,产品突然增加需求,要求金币扔出去后不消失,互相可碰撞,其最终结果还要由服务器控制(没错,至今做的所有游戏都有幕后黑手,=W=). 对于碰撞以前只写过一个球到处碰墙壁的,小球之间的碰撞倒是没有接触,想到他们碰撞过程中的角度变化.速度分配,就不敢往下想了,于是马上想到box2d这个牛逼哄哄的引擎. 但是,使用物理引擎虽然高效.逼真,但所有碰撞都是不可控,包括最终的落点.所以引擎不能解决这次遇到的需求. 不能用引擎,咱自己写也不怕,反正当年物理和高数都

JAVA 多线程制作大球吃小球 一、实现球的自动生成及运动 生产消费模型

/*文章中用到的代码只是一部分,需要源码的可通过邮箱联系我 [email protected]*/ 前几天用多线程实现了创建小球并移动,想到大鱼吃小鱼,便突发奇想要写一个大球吃小球.首先第一步自然是先把界面弄好啦 1 public class BallUI extends JPanel { 2 3 private ArrayList<Ball> li = new ArrayList<Ball>(); 4 5 public static void main(String[] args

小球碰撞墙壁----干掉误差

之前一直在沿用之前听课学来的"千篇一律"的小球碰撞墙壁或者地板的计算方法. 忽然发现,小球碰撞的时候,其实小球有一部分是进入了墙的里面,在小球速度并不快的情况下,或许不明显,但是当小球速度变的更快,小球半径也更大的时候,就没法看了 效果如下 代码如下(所有代码都只在chrome或者safari下能用,因为requestAnimationFrame方法我并没有写兼容): <!doctype html> <html> <head> <meta ch

(NO.00004)iOS实现打砖块游戏(九):游戏中小球与反弹棒的碰撞

大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请告诉我,如果觉得不错请多多支持点赞.谢谢! hopy ;) 前一篇博文介绍了物理对象中小球与砖块的碰撞处理,在这一篇中我们再来看一下小球与反弹棒碰撞发生的那点事 ;) 小球与反弹棒开始碰撞 同样我们在碰撞中也要调整小球的力矩,所以也要分开处理,首先是碰撞开始时的处理: -(BOOL)ccPhysicsCollisionBegin:(CCPhysicsCollisionPair *)pair ball:(CCNode *)

【web前端学习部落22群】分享 碰撞的小球开源小案例

对于课程中的疑问,大家可以加 web前端学习部落22群 120342833和其他老师还有众多的小伙伴们进行沟通交流哦,群里还有不少技术大拿.行业大牛 可以一起探讨问题,我们也会安排专业的技术老师为大家答疑解惑呢! <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>碰撞的小球</title> <style type="text/cs