小球碰撞(单个子线程)

前面我们利用多线程实现了一个多个小球运动的程序,但是我们知道每个操作系统所能开辟的线程数量是有限的,并且随着线程的增多,程序的运行性能会逐渐下降。因此,我们就想着把它转变为只有一个主线程和一个子线程的程序。

一、线程的理解

1.线程,是在进程中独立运行的子任务。为什么需要多线程编程呢?举个简单的例子,比如坦克大战的游戏。但游戏开始时,我们要求画面上要不断地生成新的飞机,但同时我们又要控制自己的飞机进行移动。如果我们只有一个主线程,那么一旦这个主线程在死循环执行生成新飞机的代码时,我们是没办法执行其他代码的,也就是我们没法控制自己的飞机。因此我们必须额外再开辟一个线程来控制我们自己的飞机。这就是线程的作用之一,它可以让我们的程序同时进行多个操作。

2.每一个运行的程序都会有自己的线程,有且只有一个。这个线程我们称之为主线程。这个主线程会依次执行我们的整个代码。而我们用start()方法开辟的新线程,它运行的是run()方法的代码。这个run()方法的代码会和我们的主线程同步进行(表面上看起来是同时进行的)。

3.线程结束后不能重新启动。

4.如果没有调用start()方法来启动线程,而是直接调用run(),那么这时run()只是一个普通方法,它需要在主线程中排队执行。

5.子线程的存在时间取决于run()方法。如果run()方法是一个死循环,那么这个线程就会一直存在,直到主线程停止。如果run()方法只是一个简单的运行代码,不是死循环,那么当run()方法执行完毕,这个子线程就会被关闭。

二、多个小球运动的基本思路

1.多线程

前面我们实现的多个小球运动是采用多线程来实现的。基本思路就是,为每一个小球开辟一个独立的线程,我们让小球类Ball去继承Thread线程类,并重写run()方法。每一次点击界面的时候,生成一个新的球类对象,并且为这个对象开辟一个线程。

2.单线程

为所有的小球开辟一个共用的子进程,这个子进程会不断地生成新的小球。因此我们让界面类BallFrame去继承Thread线程类,并重写run()方法。在这个run方法中我们通过一个循环来调用所有的小球对象,并让这些小球对象去执行move方法,实现所有的小球一同运动的效果。

三、详细解析

单线程多小球的基本结构

四、具体代码

//实现球运动的界面类BallFrame

import java.awt.Color;
import java.awt.Graphics;
import java.util.ArrayList;
import java.util.Random;

import javax.swing.JFrame;

public class BallFrame extends JFrame implements Runnable{
	public Ball ball;
	public Random random=new Random();
	
	ArrayList<Ball>list=new ArrayList();
	
	static public void main(String[] args) {
		BallFrame jf=new BallFrame();
		jf.initUI();
		Thread frameThread=new Thread(jf);
		frameThread.start();
	}
	
	public void initUI() {
		//初始化界面
		this.setTitle("小球运动");
		this.setSize(800, 600);
		this.setDefaultCloseOperation(3);
		this.setLocationRelativeTo(null);
		this.setResizable(false);
		
		this.setVisible(true);
		//在线程启动之前先增加一个小球对象
		ball=new Ball(this,100);
		list.add(ball);		
	}
	
	//重写重绘方法
	public void paint(Graphics g) {
		//调用父类的重绘方法
		super.paint(g);
		for(int i=1;i<list.size();i++) {
			g.setColor(list.get(i).color);
			g.fillOval(list.get(i).x, list.get(i).y, list.get(i).size, list.get(i).size);
		}
	}
	
	public void run() {
		int controlnum=0;//控制小球的生成速度
		while(true) {
			for(int i=0;i<list.size();i++) {
				list.get(i).move();
				list.get(i).speed();
				repaint();
				list.get(i).collide(i);
				if(list.get(i).blood<=0) list.remove(i);
			}
			if(controlnum==100) {
				//生成新的小球
				int randomX=random.nextInt(600);
				Color color=new Color(random.nextInt(256));
				int speednumber=random.nextInt(5);
				Ball ball=new Ball(randomX,0,random.nextInt(20)+20,color,speednumber-5,speednumber,this,100);
				list.add(ball);
				controlnum=0;
			}
			else controlnum++;
			//休眠10ms,也就是每隔10ms小球会移动一次
			try {
				Thread.sleep(10);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
}
import java.awt.Color;
import java.awt.Graphics;

public class Ball {
	public int x=0;//起始位置的x
	public int y=50;//起始位置的y
	public int size=30;//小球的大小
	public Color color=Color.black;//小球的颜色
	public Graphics g;//画笔
	public int speedx=3;//x的改变速度
	public int speedy=3;//y的改变速度
	public BallFrame bf;
	public int blood;//小球的血量
	//构造函数
	public Ball(BallFrame bf,int blood) {
		this.bf=bf;
		this.blood=blood;
	}
	//构造函数
	public Ball(int x,int y,int size,Color color,int speedx,int speedy,BallFrame bf,int blood) {
		this.x=x;
		this.y=y;
		this.size=size;
		this.color=color;
		this.speedx=speedx;
		this.speedy=speedy;
		this.bf=bf;
		this.blood=blood;
	}
	//控制小球的移动速度
	public void speed() {
		if(x+size>bf.getWidth()) {
			speedx=-Math.abs(speedx);
			blood-=10;
		}
		else if(x<0) {
			speedx=Math.abs(speedx);
			blood-=10;
		}
		if(y+size>bf.getHeight()) {
			speedy=-Math.abs(speedy);
			blood-=10;
		}
		else if(y<0) {
			speedy=Math.abs(speedy);
			blood-=10;
		}
	}
	//小球移动
	public void move() {
		y+=speedy;
		x+=speedx;
	}
	
	//判断小球之间是否发生碰撞
	public void collide(int i) {
		//判断是否发生了碰撞
		for(int j=0;j<bf.list.size();j++) {
			if(i==j) continue;//自己和自己不碰撞
			
			int DistanceX=x-bf.list.get(j).x;
			int DistanceY=y-bf.list.get(j).y;
			int RadiiI=size/2;
			int RadiiJ=bf.list.get(j).size/2;
			//两个小球之间的距离小于两者的半径和
			if((DistanceX*DistanceX+DistanceY*DistanceY)<=((RadiiI+RadiiJ)*(RadiiI+RadiiJ))) {
				if(x>bf.list.get(j).x) { //如果自己的x坐标大于发生碰撞的小球的x坐标,由数学知识可知应该朝正向运动
					speedx=Math.abs(speedx);
				}
				else	//如果自己的x坐标小于发生碰撞的小球的x坐标,由数学知识可知应该朝负向运动
				{
					speedx=-Math.abs(speedx);
				}
				if(y>bf.list.get(j).y) { //如果自己的x坐标大于发生碰撞的小球的x坐标,由数学知识可知应该朝正向运动
					speedy=Math.abs(speedy);
				}
				else	//如果自己的x坐标小于发生碰撞的小球的x坐标,由数学知识可知应该朝负向运动
				{
					speedy=-Math.abs(speedy);
				}
				blood-=10;//发生碰撞,血量减少
			}
			
		}
	}
}

五、反思总结

1.小球的移动速度不能过快,否则会连城一条线。可以重新定义一个controlnum来控制小球的移动速度,小球的移速是10ms移动一次,生成的话可以定义为1000ms。也就是,每移动100次再生成一个小球。

2.线程的启动必须在界面可见之后。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值