我时常想象人生就是一颗颗不同颜色的球,我们在特定的空间里面做自由的运动,偶尔会与另一颗美丽或者平凡的小球碰撞在一起,然后我们仍走向截然不同的道路。
生命如此,每个人都是独立的个体。也许有一天吧,你遇到了比你强大,比你包容的另一个生命,他或者她会告诉你,来我的怀里吧;于是乎你毅然决然的放弃了所有,奋不顾身的投入了他的怀抱,两颗不同的心,不同的生命也能融为一体。
于是我们终于知道,生命可以是坚硬的碰撞,也可以是温柔的拥抱。在碰撞与拥抱之间,整个宇宙中的生命得以延续,文明才能得到继续。
在这里作为java初步学习的小结,下面是我所做的小球碰撞以及包容(吞噬)的多线程程序。
以下:
我们用一个黑色的界面来代表整个宇宙,在其中放入五颜六色的形状不一的小球(代表生命),这些球在遇到界面的边界时会发生反弹,在遇到其他球时则会发生吞噬或者碰撞的随机过程。
将小球定义为Ball类,每次在黑色界面上的鼠标点击都会在点击处生成一个颜色随机,大小随机(有上限),速度随机(大小和方向随机,但x,y方向的速度不会同时为0)。将所有小球存放在Arraylist中,然后利用多线程对Arraylist进行操作。其中主要实现的是小球的碰撞以及吞噬的 功能。此外还引入暂停,继续,停止等功能。
下面是小球类
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.util.Random;
/*
* 这里定义的小球类
* 属性有坐标x,y;大小size;速度xspeed,yspeed;颜色color。全部定义为private型
* 各属性都有他们的setters和getters
* 方法有move方法来控制其移动
*
*/
public class Ball {
private int x,y,size;
private int xspeed;
private int yspeed;
private Color color;
public int getXspeed() {
return xspeed;
}
public void setXspeed(int xspeed) {
this.xspeed = xspeed;
}
public int getYspeed() {
return yspeed;
}
public void setYspeed(int yspeed) {
this.yspeed = yspeed;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
public int getSize() {
return size;
}
public void setSize(int size) {
this.size = size;
}
public Color getColor() {
return color;
}
public void setColor(Color color) {
this.color = color;
}
//move是小球的移动方法。
public void move(BallGame BG,Graphics2D g2d){
//判断是否碰撞到左右边界,如果碰撞到则x方向的速度取反
if(x<=0||(x+this.size)>=BG.getWidth()){
int tempspeed=-this.xspeed;
this.xspeed =tempspeed;
}
//判断是否碰撞到上下边界,如果碰撞到则y方向的速度取反
if(y<=20||((y+this.size)>=BG.getHeight())){
int tempspeed =-this.yspeed;
this.yspeed =tempspeed;
}
/*
* 下面是小球的移动过程:将小球之间所在位置用界面背景色填充,
* 在新的位置上画出小球
*/
//用界面背景色填充小球位置
g2d.setColor(BG.getBackground());
g2d.fillOval(x, y, this.size+5, this.size+5);
//改变小球的x和y方向上的小球都会移动xpeed和yspeed的距离,然后得到新的位置坐标
this.x +=this.xspeed;
this.y +=this.yspeed;
//再用小球颜色在新的坐标上画出小球
g2d.setColor(this.color);
g2d.fillOval(x, y, this.size, this.size);
}
下面是整个界面的实现以及主线程的实现
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.RenderingHints;
import java.util.ArrayList;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class BallGame extends JFrame {
private Image img;
private ArrayList list =new ArrayList();
public static void main(String []Args){
BallGame BG= new BallGame();
BG.unitUI();
}
//这里是黑色的界面
public void unitUI(){
this.setTitle("老九的小球游戏");
this.setSize(1200,700);
this.setLocationRelativeTo(null);
this.setBackground(Color.black);
this.setDefaultCloseOperation(3);
this.setResizable(false);
this.setVisible(true);
/*
* 这里加入的监听机制有两个功能
* 1.MouseLIstener用以实现鼠标点击出现小球的功能。
* 2.KeyListener用以实现暂停继续动画的功能
*
*/
BallListener BL =new BallListener(this,this.getGraphics(),list);
this.addMouseListener(BL);
this.addKeyListener(BL);
//引入多线程
Thread t =new Thread(BL);
t.start();
}
public void paint(Graphics g) {
//次画布img实现双缓冲,用g2d来绘制图形
img = this.createImage(this.getWidth(), this.getHeight());
Graphics2D g2d = (Graphics2D) img.getGraphics();
//引入画笔抗锯齿
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
/*
* 将小球存放在Arraylist数组队列中
* 在下面的循环中将实现小球的吞噬和撞击功能
*/
for (int i = 0; i < list.size(); i++) {
/*
* 小球已被定义为Ball类
* 将取出的小球放在变量ball中
*/
Ball ball = (Ball) list.get(i);
//这里取出相遇的小球存放在tempb中
for(int j =0 ;j//i=j时说明取出的是ball自己
if(i!=j){
/*
再次判断是否发生吞噬,if中判断两球是否重叠,所用公式是,两球的圆心坐标(x1,y1),(x2,y2)以及两球的大小size1,size2应满足以下条件:x1x2+size2,y1+size1>y2+size2。
*/
if(ball.getX()(tempb.getX()+tempb.getSize())
&&(ball.getY()+ball.getSize())>(tempb.getY()+tempb.getSize())){
//如果相遇则发生吞噬,在Arraylist中取出temp对应的小球
list.remove(j);
//吞噬后新的小球体积是相遇小球的中的较大者体积加一
if(ball.getSize()<100){
int tempsize =ball.getSize();
ball.setSize(tempsize+1);
}
}
/*
再次判断是否相遇,if中判断两球是否相遇,所用公式是,两球的圆心坐标(x1,y1),(x2,y2)以及两球的大小size1,size2应满足以下条件:(x1-x2)^2+(y1-y2)^2<(size1-size2)^2
*/
if(((ball.getX()-tempb.getX())*(ball.getX()-tempb.getX())
+(ball.getY()-tempb.getY())*(ball.getY()-tempb.getY()))
<=(ball.getSize()-tempb.getSize())){
//碰撞后两球都会反弹
ball.setXspeed(-ball.getXspeed());
ball.setYspeed(-ball.getYspeed());
tempb.setXspeed(-tempb.getXspeed());
tempb.setYspeed(-tempb.getYspeed());
}
}
}
//在画布g2d上重新绘制所有小球的运动状态
ball.move(this,g2d);
}
//用g绘制次画布
g.drawImage(img, 0, 0, this);
}
}
需要说明的是paint会在run的重载方法中调用,用多线程的思路实现小球的运动过程。
下面是界面的监听机制类
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.ArrayList;
import java.util.Random;
//利用鼠标监听实现小球的生成,利用按键监听实现整个程序的暂停和继续
public class BallListener implements MouseListener,KeyListener,Runnable{
private int x,y;
private BallGame BG;
Graphics g;
private ArrayList list;
//stopFlag为停止功能键
private boolean stopFlag=true;
//pauseFlag为 暂停/继续 功能键
private volatile boolean pauseFlag=true;
//BallListener方法实现参数的传递:BallGame类界面BG,BG的画笔g,存放小球的数组队列list
public BallListener(BallGame BG,Graphics g,ArrayList list){
this.BG =BG;
this.g =g;
this.list =list;
}
//在此方法中生成小球
public void mousePressed(MouseEvent e) {
//得到鼠标的x,y坐标
x =e.getX();
y =e.getY();
//将得到的坐标赋给小球对象ball
Ball b =new Ball();
b.setX(x);
b.setY(y);
//为小球生成随机颜色,但和界面的背景色不同
Random rand = new Random();
do{
b.setColor( new Color( (new Double(Math.random()*128)).intValue()+128,
(new Double(Math.random()*128)).intValue()+128,
(new Double(Math.random()*128)).intValue()+128));
}while(b.getColor()==BG.getBackground());
//为小球生成随机的大小但大小不能小于等于10
do{
b.setSize(rand.nextInt(50));
}while(b.getSize()<=10);
//为小球生成随机的速度但x,y的速度不能同时为0
do{
b.setXspeed(rand.nextInt(8)-4);
b.setYspeed(rand.nextInt(8)-4);
}while(b.getXspeed()==0&&b.getYspeed()==0);
//将生成的小球加入数组队列list中
list.add(b);
}
//在此方法中实现暂停,继续等功能
public void keyPressed(KeyEvent e) {
//得到按键的值
int key =e.getKeyCode();
//switch实现不同的功能
switch(key){
//空格键时界面暂停,再次空格则会继续
case 32:
pauseFlag =!pauseFlag;
break;
//Esc键时界面停止,多线程结束
case 27:
stopFlag =false;
break;
case 10:
stopFlag =true;
pauseFlag=true;
list.clear();
BG.repaint();
this.run();
break;
}
}
//在run方法中每隔10ms调用一次BG的重写方法来实现之前所述功能
public void run() {
//外层的while循环保证多线程一直执行知道stopFlag变为false
while(stopFlag){
/*pauseFlag实现暂停功能,需要说明的是如果为声明pauseFlag为volatile型,
则pauseFlag在计算机中存放在内存,而多线程在寄存器中执行,数据会无法交换*/
if(pauseFlag){
BG.repaint();
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public void keyTyped(KeyEvent e) {}
public void mouseReleased(MouseEvent e) {}
public void mouseEntered(MouseEvent e) {}
public void mouseExited(MouseEvent e) {}
public void mouseClicked(MouseEvent e) {}
public void keyReleased(KeyEvent e) {}
}
以上就实现了小球的随机生成,碰撞,吞噬功能。