最初听闻“线程”这个词,是在那时候自己写的小程序存在着这样的诟病:触发按钮之后,监听器捕捉到用户操作,在其触发动作所执行的指令尚未结束前,按钮是会一直“凹下去”的,待到所有的指令运行结束之后,才会“弹起来”,只个时候才能再次点击按钮。听闻学习了线程之后就能解决这个问题。带着这样的好奇,走进了线程的学习。。。
在此之前,只听说过“进程”,“程序”,但到底什么是“线程”?。。。。。。通过学习,明白了原来每一个程序都会包含有一个或若干个进程,而每一个进程其实是由一个或若干个线程组成。线程,是程序执行流的最小单元,每一个线程就是一个进程的实体,线程本身不拥有系统资源,与同属一个进程的其他线程共同的享有着进程所拥有的资源,线程之间的关系:一个线程可以创建和撤消另一个线程,同一进程中的多个线程之间可以并发执行。
在java.util下面有一个叫Thread的类和一个叫Runnable的接口,解决问题的方式有两种:一,创建一个类来继承Thread类,并重写run()方法,然后实例化这个类的一个对象,通过调用start()方法来启动线程;二,定义一个接口来实现Runnable,并实现其run()方法,将所定义的接口作为Thread的构造方法的参数,最后再创建Thread类的对象并调用start()方法来启动线程。显然,第一种方式操作比较简单,就以它为例吧。
介绍了理论知识,该从代码着手了。我的理解其实很简单,那就是将之前所要运行的指令放入run()方法中即可。下面简单介绍弹球游戏开发:
很显然,这个游戏的实现要用到线程,思路是:随机生成的小球按照运动轨迹运动(球的起始位置,颜色,尺寸,运动方向以及速度在给定的范围内均是任意的),当小球接触到窗体的边框,运动方向按照“反射定律”发生相应的改变,小球之间接触到一起的时候会按照物理的碰撞原则弹开。
定义一个继承Thread的类 -- Ball :
定义一个监听器类 -- Listener:
再定义一个窗体类 -- frame :
最后定义一个类来调用main()方法,启动程序:
至此,一个弹球游戏就完成了,当然,还有好多需要改进的地方,比如添加一个背景动画,添加碰撞的声音啦,,,这些功能正在完善中,,欢迎广大朋友不吝赐教。
在此之前,只听说过“进程”,“程序”,但到底什么是“线程”?。。。。。。通过学习,明白了原来每一个程序都会包含有一个或若干个进程,而每一个进程其实是由一个或若干个线程组成。线程,是程序执行流的最小单元,每一个线程就是一个进程的实体,线程本身不拥有系统资源,与同属一个进程的其他线程共同的享有着进程所拥有的资源,线程之间的关系:一个线程可以创建和撤消另一个线程,同一进程中的多个线程之间可以并发执行。
在java.util下面有一个叫Thread的类和一个叫Runnable的接口,解决问题的方式有两种:一,创建一个类来继承Thread类,并重写run()方法,然后实例化这个类的一个对象,通过调用start()方法来启动线程;二,定义一个接口来实现Runnable,并实现其run()方法,将所定义的接口作为Thread的构造方法的参数,最后再创建Thread类的对象并调用start()方法来启动线程。显然,第一种方式操作比较简单,就以它为例吧。
介绍了理论知识,该从代码着手了。我的理解其实很简单,那就是将之前所要运行的指令放入run()方法中即可。下面简单介绍弹球游戏开发:
很显然,这个游戏的实现要用到线程,思路是:随机生成的小球按照运动轨迹运动(球的起始位置,颜色,尺寸,运动方向以及速度在给定的范围内均是任意的),当小球接触到窗体的边框,运动方向按照“反射定律”发生相应的改变,小球之间接触到一起的时候会按照物理的碰撞原则弹开。
定义一个继承Thread的类 -- Ball :
package 线程;
import java.awt.Color;
import java.awt.Graphics;
import java.util.ArrayList;
import java.util.Random;
import javax.swing.JPanel;
public class Ball extends Thread{
private Graphics g;
private JPanel southPanel;
private ArrayList<Ball> list;
//小球的默认参数:起始位置,半径,水平速度,竖直速度以及颜色
private int x = 100;
private int y = 100;
private int r = 20;
private int speedX = 5;
private int speedY = 5;
private Color color;
private boolean tagIsPause = false;
private boolean tagIsStop = true;
//构造方法,参数有:画布,面板,保存小球对象的队列
public Ball(Graphics g, JPanel southPanel, ArrayList<Ball> list) {
this.g = southPanel.getGraphics();
this.southPanel = southPanel;
this.list = list;
//实例化随机数对象
Random rd = new Random();
//随机半径
r = rd.nextInt(3) * 10 + 20;
//随机位置
x = rd.nextInt(southPanel.getPreferredSize().width - 2*r) + r;
y = rd.nextInt(southPanel.getPreferredSize().height - 2*r) + r;
//随机水平速度大小
speedX = (rd.nextInt(3) + 2) * 3;
//如果对随机数求余数为1,则方向向左,否则向右
if(rd.nextInt(10) % 2 == 0) speedX = - speedX;
//随机竖直速度
speedY = (rd.nextInt(3) + 2) * 3;
//如果对随机数求余数为1,则方向向上,否则向下
if(rd.nextInt(10) % 2 == 0) speedY = - speedY;
//随机颜色参数
color = new Color(new Random().nextInt(256), new Random().nextInt(256), new Random().nextInt(256));
}
//初始化参数的方法
public void initData() {
x = 100;
y = 100;
r = 20;
speedX = 5;
speedY = 5;
Color color;
tagIsPause = false;
tagIsStop = false;
}
//自定义一个休眠方法,其参数为休眠的时间(单位:毫秒)
public void MyWait(int millis) {
try {
sleep(millis);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//重写run()方法
public void run() {
while(tagIsStop) {
//调用自定义的休眠方法,使线程休眠20毫秒,一来可以减慢小球的速度,二来可以使计算机休眠,大大减少cpu的使用率
MyWait(20);
//实现暂停和开始
if(tagIsPause) {
continue;
}
//擦拭小球上一次的位置
clear();
//判断小球下一步的路径
move();
//绘制小球
drawBall(x, y, r);
}
}
//擦拭小球的方法
public void clear() {
g.setColor(southPanel.getBackground());
g.fillOval(x, y, 2*r, 2*r);
}
//对小球下一步的动作进行处理的方法
public void move() {
for(int i = 0, j = 0, ix = 0, jx = 0; i < Math.abs(speedX) || j < Math.abs(speedY); i ++, j ++, ix ++, jx ++) {
//每改变一个单位的横坐标,就判断“自己”是否与别的小球发生碰撞
isHit();
if(ix < Math.abs(speedX)) {
if(speedX > 0) x ++;
else if(speedX < 0) x --;
}
//每改变一个单位的纵坐标,就判断“自己”是否与别的小球发生碰撞
isHit();
if(jx < Math.abs(speedY)) {
if(speedY > 0) y ++;
else if(speedY < 0) y --;
}
}
//如果小球接触到窗体,则是其运动方向改变
if(x >= 800 - (r + 20) || x <= 10 + r) speedX = - speedX;
if(y >= 600 - (r + 10) || y <= 38 + 32) speedY = - speedY;
}
//判断小球之间是否碰撞的方法
public void isHit() {
//遍历所有的小球
for(int i = 0; i < list.size(); i ++) {
//获得当前的小球
Ball ball = list.get(i);
//如果是“自己”,则参数不变
if(ball.equals(this)) {
this.x = ball.x;
this.y = ball.y;
this.r = ball.r;
this.color = ball.color;
this.speedX = ball.speedX;
this.speedY = ball.speedY;
}
//如果不是“自己”,则判断是否发生碰撞
else
//如果发生碰撞了
if(Math.abs(ball.x - this.x) * Math.abs(ball.x - this.x) + Math.abs(ball.y - this.y) * Math.abs(ball.y - this.y) <= (ball.r + this.r) * (ball.r + this.r)) {
//碰撞之后,速度的改变符合两大物理定律:动量守恒定律和机械能守恒定律
ball.speedX = ((ball.r - this.r) * ball.speedX + 2 * this.r * this.speedX) / (ball.r + this.r);
this.speedX = ((this.r - ball.r) * this.speedX + 2 * ball.r * ball.speedX) / (ball.r + this.r);
ball.speedY = ((ball.r - this.r) * ball.speedY + 2 * this.r * this.speedY) / (ball.r + this.r);
this.speedY = ((this.r - ball.r) * this.speedY + 2 * ball.r * ball.speedY) / (ball.r + this.r);
}
}
}
//绘制一个小球的方法
public void drawBall(int x, int y, int r) {
g.setColor(color);
g.fillOval(x, y, 2*r, 2*r);
}
//暂停的方法
public void pause() {
tagIsPause = true;
}
//开始的方法
public void reStart() {
tagIsPause = false;
}
//停止的方法
public void Stop() {
tagIsStop = false;
}
}
定义一个监听器类 -- Listener:
package 线程;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.ArrayList;
import javax.swing.JPanel;
public class Listener implements MouseListener, ActionListener{
private Graphics g;
private JPanel southPanel;
private Frame frame;
private String cmd;
//保存小球对象的队列
private ArrayList<Ball> list = new ArrayList<Ball>();
//构造方法:参数为:画布,面板,以及窗体
public Listener(Graphics g, JPanel southPanel, Frame frame) {
this.g = g;
this.southPanel = southPanel;
this.frame = frame;
}
@Override
//获取动作命令
public void actionPerformed(ActionEvent e) {
cmd = e.getActionCommand();
}
@Override
public void mouseClicked(MouseEvent e) {
//判断触发的按钮
if("add".equals(cmd)) {
//实例化小球对象
Ball ball = new Ball(g, southPanel, list);
//将小球队想添加到队列中
list.add(ball);
//启动线程
ball.start();
}
if("pause".equals(cmd)) {
//遍历队列
for(int i = 0; i < list.size(); i ++) {
//获得当前的小球对象
Ball ball = list.get(i);
//调用暂停方法
//ball.suspend();
ball.pause();
}
}
if("restart".equals(cmd)) {
//遍历队列
for(int i = 0; i < list.size(); i ++) {
//获得当前的小球对象
Ball ball = list.get(i);
//调用开始方法
//ball.resume();
ball.reStart();
}
}
if("stop".equals(cmd)) {
//遍历队列
for(int i = 0; i < list.size(); i ++) {
//获得当前的小球对象
Ball ball = list.get(i);
//暂停小球的运动
ball.pause();
//终止线程
ball.Stop();
}
//初始化窗体,即“清屏”
frame.iniUI();
}
}
@Override
public void mousePressed(MouseEvent e) {
// TODO Auto-generated method stub
}
@Override
public void mouseReleased(MouseEvent e) {
// TODO Auto-generated method stub
}
@Override
public void mouseEntered(MouseEvent e) {
// TODO Auto-generated method stub
}
@Override
public void mouseExited(MouseEvent e) {
// TODO Auto-generated method stub
}
}
再定义一个窗体类 -- frame :
package 线程;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
@SuppressWarnings("serial")
public class Frame extends JFrame{
private Graphics g ;
public void iniUI() {
this.setSize(820, 678);
//this.setLocationRelativeTo(null);
JPanel jp = new JPanel();
jp.setLayout(new BorderLayout());
JPanel northPanel = new JPanel();
JButton jb1 = new JButton("添加");
JButton jb2 = new JButton("暂停");
JButton jb3 = new JButton("开始");
JButton jb4 = new JButton("停止");
jb1.setActionCommand("add");
jb2.setActionCommand("pause");
jb3.setActionCommand("restart");
jb4.setActionCommand("stop");
northPanel.add(jb1);
northPanel.add(jb2);
northPanel.add(jb3);
northPanel.add(jb4);
northPanel.add(new JLabel("点击“停止”清屏"));
northPanel.setBackground(Color.GRAY);
jp.add(northPanel, BorderLayout.NORTH);
JPanel southPanel = new JPanel();
southPanel.setPreferredSize(new Dimension(this.getWidth(), this.getHeight() -northPanel.getPreferredSize().height));
southPanel.setLayout(new FlowLayout());
southPanel.setBackground(new Color(255, 255, 255));
jp.add(southPanel, BorderLayout.SOUTH);
this.add(jp);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setVisible(true);
Listener l = new Listener(g, southPanel, this);
jb1.addActionListener(l);
jb2.addActionListener(l);
jb3.addActionListener(l);
jb4.addActionListener(l);
jb1.addMouseListener(l);
jb2.addMouseListener(l);
jb3.addMouseListener(l);
jb4.addMouseListener(l);
}
}
最后定义一个类来调用main()方法,启动程序:
package 线程;
public class MianTest {
public static void main(String[] args) {
Frame fr = new Frame();
fr.iniUI();
}
}
至此,一个弹球游戏就完成了,当然,还有好多需要改进的地方,比如添加一个背景动画,添加碰撞的声音啦,,,这些功能正在完善中,,欢迎广大朋友不吝赐教。