最近写了一个程序,可以通过按键在画板上生成随机大小随机颜色的小球并且小球可以在画板上运动,实现了鼠标点击小球可以进行消除的功能,并且还实现了小球的暂停与重新运动的操作。
首先我们还是得先将窗体设置好,然后在窗体上添加鼠标事件监听器还有键盘事件监听器。
package com.hnu.yc0802BallThread;
import java.awt.Graphics;
import javax.swing.JFrame;
public class BallFrame extends JFrame{
public static void main(String args[]){
BallFrame ba=new BallFrame();
ba.initUI();
}
/**
* 实现窗体的方法
*/
public void initUI(){
// 设置窗体基本属性
this.setSize(700,700);
this.setLocationRelativeTo(null);
this.setDefaultCloseOperation(3);
this.setResizable(false);
// 添加键盘及鼠标监听器
Action ka=new Action(this);
this.addKeyListener(ka);
this.addMouseListener(ka);
this.setVisible(true);
}
}
然后我们要定义小球类(继承Thread类),其中包括小球得基本属性,并且要确定好参数的传递方式,是用构造方法还是设置set与get方法。最后还得写run方法,其中就得写小球的运动算法。
package com.hnu.yc0802BallThread;
import java.awt.Color;
import java.awt.Graphics;
import java.util.Random;
public class Ball extends Thread{
private int x,y,movex,movey,size;//小球的起始坐标,每运动一次移动的坐标,大小
private BallFrame bf;
// 这两个布尔变量都是在线程运行时进行判断使用,后面会介绍用法
Boolean haha=false;
Boolean hahaha=true;
Color co;//小球的颜色
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;
}
/**
* 构造方法
* @param x小球起始横坐标
* @param y小球起始纵坐标
* @param movex 小球移动一步横坐标长度
* @param movey 小球移动一步纵坐标长度
* @param g 画笔
*/
public Ball(int x, int y, int movex, int movey, BallFrame bf,Color co,int size) {
super();
this.setX(x);
this.setY(y);
this.movex = movex;
this.movey = movey;
this.bf = bf;
this.co=co;
this.setSize(size);
}
public void run(){
Graphics g=bf.getGraphics();
while (hahaha){//hahaha(个人习惯用哈哈作为布尔变量,只要在我的代码中看到ha,那就代表布尔变量)
//这里的布尔变量控制循环语句的执行,当我要结束线程,就要结束这个循环,改变布尔变量即可
if (haha){//这里的布尔变量控制小球的暂停,但是这只是让小球停在那里没有运动,
//线程一直在执行,只是没有让线程执行后面的部分,所以说小球看起来不动,暂停了
continue;
}
g.setColor(bf.getBackground());
g.fillOval(getX(), getY(), getSize(), getSize());
//
setX(getX() + movex);
setY(getY() + movey);
g.setColor(co);
g.fillOval(getX(), getY(), getSize(), getSize());
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
接下来我们就要写实现事件监听的类,
package com.hnu.yc0802BallThread;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.Random;
public class Action implements KeyListener, MouseListener {
BallFrame bf;
Random rand;// 定义一个随机数变量,在小球的大小,颜色,运行速度随机时使用
PerfectQueue<Ball> pq;// 定义一个泛型队列变量,用来存储小球类型的对象
/**
* 构造方法,用来传参
*
* @param bf
*/
public Action(BallFrame bf) {
super();
this.bf = bf;
rand = new Random();
pq = new PerfectQueue<Ball>();
}
@Override
public void keyTyped(KeyEvent e) {
// TODO Auto-generated method stub
}
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_U) {// 当按下U键 随机生成小球
Ball ball = new Ball(0, 0, rand.nextInt(10) + 1,
rand.nextInt(10) + 1, bf, new Color(rand.nextInt(256),
rand.nextInt(256), rand.nextInt(256)),
rand.nextInt(100) + 20);
ball.start();// 启动线程,执行run方法,让小球动起来
pq.add(ball);// 每次都新建一个小球,然后将小球对象存储在队列中,在后面指定消除哪个小球时会用到
}
if (e.getKeyCode() == KeyEvent.VK_I) {// 按下I键暂停小球运动
// 暂停只是让线程空循环,不绘制图形,在Ball类run方法中有详细解释
/**
* 遍历队列,将所有小球的布尔变量haha(控制小球暂停,在Ball类run方法中有详细解释)变为true 暂停所有小球的运动
*/
for (int i = 0; i < pq.size(); i++) {
Ball ball = pq.get(i);
ball.haha = true;
}
}
if (e.getKeyCode() == KeyEvent.VK_O) {// 按下I键小球重新开始运动
// 启动是让线程不再空循环 要绘制图形
/**
* 遍历队列,将所有小球的布尔变量haha(控制小球暂停,在Ball类run方法中有详细解释)变为false 暂停所有小球的运动
*/
for (int i = 0; i < pq.size(); i++) {
Ball ball = pq.get(i);
ball.haha = false;
}
}
}
public void mouseReleased(MouseEvent e) {
boolean ha = false;// 定义一个局部布尔变量,在判断鼠标点击点附近有没有小球时使用
int minpq = 0;// 存储到鼠标点击点的最小距离的点的下标
int min = 119;// 小球的大小是119,要将小球的坐标(小球就是画的内切圆,将矩形左上角的坐标定位小球的坐标)与鼠标点击点取距离,小于119才有效
// 得到鼠标释放的坐标
int Mouse_x = e.getX();
int Mouse_y = e.getY();
/**
* 遍历队列,寻找鼠标点击点附近是否有符合要求的小球,有的话,取出距离鼠标点击点最近的那个
*/
for (int i = 0; i < pq.size(); i++) {
// 当不符合要求时,进入下一次循环
if (pq.get(i).getX() > Mouse_x || pq.get(i).getY() > Mouse_y
|| (Mouse_x - pq.get(i).getX()) > 119
|| (Mouse_y - pq.get(i).getY()) > 119) {
continue;
} else {
// pq.get(i).setX(800);
// pq.get(i).setY(800);
int a = (int) distence(Mouse_x, pq.get(i).getX(), Mouse_y, pq
.get(i).getY());// 此方法为定义的计算两点距离的方法
if (a < min) {
min = a;
minpq = i;
}
ha = true;// 说明鼠标附近有符合要求的小球
}
}
if (ha) {
pq.get(minpq).hahaha = false;// 将hahaha控制while语句循环的条件设置为false,停止此小球线程运行
Graphics g = bf.getGraphics();// 得到画笔
g.setColor(bf.getBackground());// 糊一个与背景色相同的小球覆盖上去
g.fillOval(pq.get(minpq).getX(), pq.get(minpq).getY(), pq
.get(minpq).getSize(), pq.get(minpq).getSize());
pq.delete(minpq);//在队列中删除此小球
}
}
// 求两点之间距离的算法
public double distence(int ax, int bx, int ay, int by) {
return Math.hypot(ax - bx, ay - by);
}
@Override
public void mouseEntered(MouseEvent e) {
// TODO Auto-generated method stub
}
@Override
public void mouseExited(MouseEvent e) {
// TODO Auto-generated method stub
}
@Override
public void keyReleased(KeyEvent e) {
// TODO Auto-generated method stub
}
@Override
public void mouseClicked(MouseEvent e) {
// TODO Auto-generated method stub
}
@Override
public void mousePressed(MouseEvent e) {
// TODO Auto-generated method stub
}
}
最后,将泛型队列代码附上
package com.hnu.yc0802BallThread;
public class PerfectQueue<E> {
private Object[] array;
private int size;
// 构造方法 实例化数组
public PerfectQueue() {
array = new Object[size];
}
// 添加方法
public void add(E o) {
Object array1[] = new Object[size + 1];
for (int i = 0; i < size; i++) {
array1[i] = array[i];
}
array1[size] = o;
size++;
array = array1;
}
public E get(int index){
if(index<0||index>=size)
return null;
return (E)array[index];
}
// 删除方法
public E delete(int index) {
if(index<0||index>=size)
return null;
Object[] temp=new Object[size-1];
for(int i=0;i<index;i++){
temp[i]=array[i];
}
for(int i=index+1;i<size;i++){
temp[i-1]=array[i];
}
Object obj=array[index];
size--;
return (E)obj;
}
// 查找方法
public boolean find(Object obj) {
for(int i=0;i<size;i++){
if(array[i]==obj){
return true;
}
}
return false;
}
public int size(){
return size;
}
}