弹球游戏是一款模拟多线程运行的游戏,利用继承Thread实现多线程。
效果图:小球之间会相互碰撞并交换速度在弹开。按钮能实现随机添加、移除小球并暂停小球移动。
具体实现:
1、创建界面(包含主函数)。
public class BallFrame extends JFrame {public static void main(String[] args) { BallFrame bf = new BallFrame(); bf.initUI(); } public void initUI(){ //设置界面属性,包括按钮背景,添加监听 } }
//创建一个链表存储小球 private ArrayList<Ball> list = new ArrayList<Ball>();
2、创建小球类,继承Thread类。这个类包含以下内容。
public class Ball extends Thread { //需要设置的属性有:private int x, y;// 小球圆心坐标 private Graphics2D g; Random rand = new Random(); private ArrayList<Ball> list;//存贮每个小球 int r = 12;//小球半径 int green,red,blue;//小球的颜色 }
(1)、重写构造方法,主要用来传递参数,包括画笔,面板等。
(2)、画一个小球的方法。
public void drawNew(Graphics2D g) { // 绘制新的小球 for (int i = r; i > 0; i--) {//设置颜色使小球看起来具有立体感。 if(green<235)green=G + 8*(r-i) ; if(red<235)red=R + 8*(r-i) ; if(blue<235)blue=B + 8*(r-i) ; g.setColor(new Color(green,red,blue)); g.fillOval(x - r / 2 - i / 2, y - r / 2 - i / 2, i * 2, i * 2); } }
(3)、小球的移动方法。
public void move() { x += xspeed; y = y+yspeed; }
(4)、擦除小球的方法,画出新的小球之前要把上一个小球擦出,不然画不出小球的动态效果。
public void draw(Graphics2D g) { // 擦除上一次绘制的小球 g.setColor(Color.black); g.fillOval(x - r - 1, y - r - 1, r * 2 + 2, r * 2 + 2); }
(5)、判断小球碰撞的方法,判断这个小球是否与链表内其他的小球存在碰撞,同时也判断是否与边界发生碰撞。
public void collide() { int index=list.indexOf(this); for (int i =index; i < list.size(); i++) { Ball ball = list.get(i); // 判断是否发生碰撞 if (ball != this) { // 计算两个小球的距离 int d = (int) Math.sqrt((this.x - ball.x) * (this.x - ball.x) + (this.y - ball.y) * (this.y - ball.y)); if (d < (this.r + ball.r+2)) { int m = this.xspeed; this.xspeed = ball.xspeed; ball.xspeed = m; m = this.yspeed; this.yspeed = ball.yspeed; ball.yspeed = m; } } }//判断是否与边界发生碰撞 if (x + r > centerPanel.getWidth() || x < r) xspeed = -xspeed; if (y + r > centerPanel.getHeight() || y < r) yspeed = -yspeed; }
(6)、线程运行的方法。
public void run() { while (true) { this.draw(g); this.move(); this.collide(); this.drawNew(g); try {//每40ms循环一次模拟小球的动态效果 Thread.sleep(40); } catch (InterruptedException e) { e.printStackTrace(); } } }
3、事件的处理(添加、删除、暂停),主要通过鼠标实现。
(1)、添加小球。在随机位置产生一个小球,初始速度也随机。
if (e.getActionCommand().equals("添加")) {//随机设置小球的初始位置 int x = rand.nextInt(centerPanel.getWidth() - 24) + 12; int y = rand.nextInt(centerPanel.getHeight() - 24) + 12; // 创建小球对象 Ball ball = new Ball(list, x, y, centerPanel, this); ball.start();//启动线程 list.add(ball);//将小球存入链表 System.out.println(list.size()); flag = true; }
(2)、删除小球,随机删除界面中一个小球。
if (e.getActionCommand().equals("移除")) { // 随机移除小球 if (list.size() > 0) { int index = rand.nextInt(list.size()); Ball ball = list.remove(index); ball.draw(g);//清除被移除的小球 ball.stop(); System.out.println(ball); } else System.out.println("没有可移除的小球!"); }
(3)、暂停小球。
Thread中有可以让线程等待的方法,但是时间不具有灵活性,这里考虑用sleep方法来实现。
在run()方法中插入sleep,手动改变sleep的条件。
public void run() { while (true) { this.draw(g); this.move(); this.collide(); this.drawNew(g); try { Thread.sleep(40); } catch (InterruptedException e) { e.printStackTrace(); } //以下是插入的代码 while(flag){ //flag就是控制暂停的条件 try { Thread.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } } } } //监听中的方法 if (e.getActionCommand().equals("暂停")) { if (flag == false) { flag = true; } else if (flag == true) { flag = false; } for (int i = 0; i < list.size(); i++) { Ball ball = list.get(i); ball.setFlag(flag); } }
完整代码:
import java.awt.BorderLayout; import java.awt.Color; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JPanel; public class BallFrame extends JFrame { private static final long serialVersionUID = 1L; public static void main(String[] args) { //线程 BallFrame bf = new BallFrame(); bf.initUI(); } public void initUI(){ this.setTitle("弹球"); this.setSize(400, 500); this.setDefaultCloseOperation(3); this.setLocationRelativeTo(null); this.setResizable(false); /***********北边************/ JPanel northPanel = new JPanel(); northPanel.setBackground(Color.black); JButton butAdd = new JButton("添加"); JButton butRemove = new JButton("移除"); JButton butPause = new JButton("暂停"); northPanel.add(butAdd); northPanel.add(butRemove); northPanel.add(butPause); this.add(northPanel,BorderLayout.NORTH); /***********中间************/ JPanel centerPanel = new JPanel(); centerPanel.setBackground(Color.black); this.add(centerPanel,BorderLayout.CENTER); this.setVisible(true); //事件处理类 BallListener bl = new BallListener(centerPanel); //给事件源添加动作监听方法,指定事件处理类的对象bl butAdd.addActionListener(bl); butRemove.addActionListener(bl); butPause.addActionListener(bl); } }
import java.awt.Color; import java.awt.Graphics2D; import java.awt.RenderingHints; import java.util.ArrayList; import java.util.Random; import javax.swing.JPanel; /** * 小球类 */ public class Ball extends Thread { private int x, y;// 小球圆心坐标 private Graphics2D g; Random rand = new Random(); private JPanel centerPanel; private ArrayList<Ball> list; int r = 12; int green,red,blue; int G = rand.nextInt(155); int R = rand.nextInt(155); int B = rand.nextInt(155); int xspeed = 3; int yspeed = 3; BallListener bl; public Ball(ArrayList<Ball> list, int x, int y, JPanel centerPanel, BallListener bl) { this.x = x; this.y = y; this.list = list; this.centerPanel = centerPanel; this.g = (Graphics2D) centerPanel.getGraphics(); this.bl = bl; // 设置取表画笔的锯齿状 g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); } private boolean flag = true; public void setFlag(boolean flag) { this.flag = flag; } public boolean getFlag() { return flag; } public void draw(Graphics2D g) { // 擦除上一次绘制的小球 g.setColor(Color.black); g.fillOval(x - r - 1, y - r - 1, r * 2 + 2, r * 2 + 2); } public void drawNew(Graphics2D g) { // 绘制新的小球 for (int i = r; i > 0; i--) { if(green<235)green=G + 8*(r-i) ; if(red<235)red=R + 8*(r-i) ; if(blue<235)blue=B + 8*(r-i) ; g.setColor(new Color(green,red,blue)); g.fillOval(x - r / 2 - i / 2, y - r / 2 - i / 2, i * 2, i * 2); } } public void move() { x += xspeed; y = (int)(y+yspeed); } public void collide() { int index=list.indexOf(this); for (int i =index; i < list.size(); i++) { Ball ball = list.get(i); // 判断是否发生碰撞 if (ball != this) { // 计算两个小球的距离 int d = (int) Math.sqrt((this.x - ball.x) * (this.x - ball.x) + (this.y - ball.y) * (this.y - ball.y)); if (d < (this.r + ball.r+2)) { int m = this.xspeed; this.xspeed = ball.xspeed; ball.xspeed = m; m = this.yspeed; this.yspeed = ball.yspeed; ball.yspeed = m; } } } if (x + r > centerPanel.getWidth() || x < r) xspeed = -xspeed; if (y + r > centerPanel.getHeight() || y < r) yspeed = -yspeed; } public void run() { while (true) { this.draw(g); this.move(); this.collide(); this.drawNew(g); try { Thread.sleep(40); } catch (InterruptedException e) { e.printStackTrace(); } while(flag^true){ try { Thread.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } } } } }
package study0528ball; import java.awt.Graphics2D; import java.awt.RenderingHints; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.ArrayList; import java.util.Random; import javax.swing.JPanel; public class BallListener implements ActionListener { private JPanel centerPanel; private Graphics2D g; private ArrayList<Ball> list = new ArrayList<Ball>(); private boolean flag; private Random rand = new Random(); public boolean isFlag() { return flag; } public BallListener(JPanel centerPanel) { this.centerPanel = centerPanel; g = (Graphics2D) centerPanel.getGraphics();// 强制转型 // 设置取表画笔的锯齿状 g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); } @SuppressWarnings("deprecation") @Override public void actionPerformed(ActionEvent e) { if (e.getActionCommand().equals("添加")) { int x = rand.nextInt(centerPanel.getWidth() - 24) + 12; int y = rand.nextInt(centerPanel.getHeight() - 24) + 12; // 创建小球对象 Ball ball = new Ball(list, x, y, centerPanel, this); ball.start(); list.add(ball); System.out.println(list.size()); flag = true; } else if (e.getActionCommand().equals("移除")) { // 随机溢出小球 if (list.size() > 0) { int index = rand.nextInt(list.size()); Ball ball = list.remove(index); ball.draw(g); ball.stop(); System.out.println(ball); } else System.out.println("没有可移除的小球!"); } else if (e.getActionCommand().equals("暂停")) { if (flag == false) { flag = true; } else if (flag == true) { flag = false; } for (int i = 0; i < list.size(); i++) { Ball ball = list.get(i); ball.setFlag(flag); } } } }
时间: 2024-10-13 21:21:16