任务:
1、用一个线程控制所有的小球对象
2、控制小球的暂停/恢复
3、小球碰撞反弹
代码实现:
一、窗体创建
public class UI extends JFrame {
public void showUI(){
//窗体
setTitle("线程游戏");
setSize(900,900);
//居中显示
setLocationRelativeTo(null);
//退出线程
setDefaultCloseOperation(EXIT_ON_CLOSE);
//设置窗体背景颜色
getContentPane().setBackground(Color.WHITE);
//流式布局管理器
setLayout(new FlowLayout());
//画笔对象:在界面程序中显示自定义类型
//自定义内容显示在哪个组件上,画笔就从该组件上获取
//从窗体上获取画笔对象
//鼠标监听器
//引用类型:(接口)interface,(类)class,数组
GameMouse mouse = new GameMouse();
//添加按钮
String[] s = {"开始","暂停","添加"};
for (int i = 0; i < s.length ; i++) {
JButton bt = new JButton(s[i]);
bt.setSize(60,40);
add(bt);
bt.addActionListener(mouse);
}
setVisible(true);
Graphics g = getGraphics();
mouse.gr = g;
//给窗体添加键盘监听器方法
addKeyListener(mouse);
//让窗体获取焦点
requestFocus();
}
public static void main(String[] args) {
new UI().showUI();
}
}
在窗体创建时,需要注意几个点:
①setVisible方法应在getGraphics方法前面,创建的按钮(在窗体需要控制的对象)都需添加监听器。
②新知识:获取焦点requesFocus();顾名思义,就是获取你需要操作的对象将它“聚焦”,例如:平时你在登陆qq界面时,有个账号输入框和密码输入框,假如你先鼠标点击了电脑桌面的app,这时聚焦点不在qq账号输入框那,你需要用鼠标点击一下(聚焦一下),才能输入。
二、创建小球类
package BallGamev4;
import java.awt.*;
public class Ball {
//属性
public int x,y,speedX,speedY,size;
public Color color;
//初始化属性
public Ball(){
x = (int)(Math.random()*700);//Math.random()是一个[0.0,1.0]区间的随机数
y = (int)(Math.random()*600);
speedX = 3;
speedY = 3;
size = (int)(Math.random()*30+40);
color = Color.BLACK;
}
public Ball(int x,int y){
this.x = x;
this.y = y;
size = 50;
color = Color.BLACK;
}
//绘制小球
public void drawBall(Graphics g){
g.setColor(Color.WHITE);
g.fillOval(x,y,size,size);
x += speedX;
y += speedY;
g.setColor(color);
g.fillOval(x,y,size,size);
if(x+size > 900 || x<0){
speedX = -speedX;
}
if(y+size > 900 || y<0){
speedY = -speedY;
}
}
}
在小球类中,我们实现了小球撞墙反弹功能,在这里我们有设置小球speedX,speedY的关于x,y轴上的速度,只要当球碰撞到边界时,把速度修改为负的就好了。
还有一种实现小球撞墙反弹,这里我们只有一个速度变量,添加了一个角度alpha变量.看似第一种简单得多。
x+=speed*Math.sin(alpha*Math.PI/180);
y-=speed*Math.cos(alpha*Math.PI/180);
if(x<=10||x>=730)alpha=360-alpha;
if(y<=220||y>=730)alpha=180-alpha;
三、监听器类
package BallGamev4;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.ArrayList;
public class GameMouse implements ActionListener, KeyListener {
UI ui = new UI();
//画笔:引用传递
public Graphics gr;
public BallThread bt;
public ArrayList<Ball> listBall = new ArrayList<>();
public Ball mb;
//创建对象:类名 对象名 = new 构造方法
//构造方法:public 类名(参数类型 参数名){方法体。。}
//作用1、创建对象 2、初始化属性
//每个类都有一个默认的无参构造方法,当自定义构造方法,那么默认的无参构造方法就被替代了
//单例模式:
@Override
public void actionPerformed(ActionEvent e) {
//让窗体获取焦点:
ui.requestFocus();
System.out.println("点击开始");
String s = e.getActionCommand();
//获取当前事件源对象
JButton jbt = (JButton) e.getSource();
if("暂停".equals(s)){
bt.flag = true;
jbt.setText("恢复");
}else if("恢复".equals(s)){
bt.flag = false;
jbt.setText("暂停");
}else if("开始".equals(s)){
if(bt==null){
//创建线程对象
bt = new BallThread(gr,listBall);
//启动线程,每个线程只能调用一个start方法
Thread t = new Thread(bt);
t.start();
}
}else if("添加".equals(s)){
Ball ball = new Ball();
listBall.add(ball);
}
}
@Override
public void keyTyped(KeyEvent e) {
}
@Override
public void keyPressed(KeyEvent e) {
}
@Override
public void keyReleased(KeyEvent e) {
}
public Graphics getGr() {
return gr;
}
public void setGr(Graphics gr) {
this.gr = gr;
}
}
注意:①获取按钮上的字符用的是getActionCommand方法。
②获取当前事件源对象getSource方法。
③我们为了只让启动一条线程,在启动线程前做个判断,若线程对象为null才从新创建。
④我们实现小球添加是通过创建一个动态数组,点击一下“添加”就新建一个小球对象,后面画的时候再遍历它。
⑤我们实现小球暂停是在小球线程类中创建一个布尔类型,如果点击“暂停”按钮,布尔值变为true,然后在线程类中
if(flag){
continue;
}
线程run方法就不会往下运行了,从而就不调用小球的draw方法,实现了暂停。
四、小球线程类
package BallGamev4;
import java.awt.*;
import java.util.ArrayList;
/**
* 继承线程类: Thread
* 实现Runnable接口
*/
public class BallThread implements Runnable{
public Graphics gr;
public boolean flag = false;//用来控制线程暂停的标记
public ArrayList<Ball> listBall;
public BallThread(Graphics gr,ArrayList<Ball> listBall){
this.gr = gr;
this.listBall = listBall;
}
//重写run方法:启动线程后自动执行的方法
//当run方法执行完,该线程结束,它占用的资源被回收
@Override
public void run() {
int x = (int)(Math.random()*700),y=0;
while(true){
//延时
try {
Thread.sleep(10);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
if(flag){
continue;
}
//遍历listBall列表
for (int i = 0; i < listBall.size(); i++) {
Ball ball = listBall.get(i);
ball.drawBall(gr);
}
}
}
}
![](https://i-blog.csdnimg.cn/blog_migrate/6ad44eaa30960ee54bcd3992a140bfd6.png)