class="MsoNormal" style="text-align: center; margin: 0cm 0cm 0pt;">弹球游戏分步解析(二)——让小球飞
之前跟大家说要把事件监听器和多线程分开来讲,不过之后发现事件监听器要涉及到很多小球运动的操作,所以,决定将两个知识点合起来说,这样会更便于大家理解:
实现小球在我们所绘制的窗体上运动就必须要用到多线程;让小球类继承Thread类,再重写void run(){}方法即可;
先上代码:
(注:浅蓝色字体不是本节要讲的内容,可以忽略)?
package jumpingBall;
?
import java.awt.Color;
import java.awt.Graphics;
import java.util.List;
import java.util.Random;
?
import javax.swing.JPanel;
//小球类是此游戏的关键,我们首先要分析他应该具备什么样的属性,实现什么样的方法
public class BallThread extends Thread {
private static final int North = 1;//用四个整形的数据代表四个方向
private static final int West = 2;
private static final int South = 3;
private static final int East = 4;
private int Xdirection = West;//记录小球在X轴上的方向
private int Ydirection = North;//记录小球在y轴上的方向
private int radios;//半径
private Color color;//颜色
private int Xspeed;//x方向速度
private int Yspeed;//y方向速度
private int X;//当前位置x
private int Y;//当前位置y
private int LastX;//最后位置x
private int LastY;//最后位置y
private int xband;
private int yband;
private JPanel jp;//面板
private Graphics g;//画布
private boolean pauseFlag = false;//暂停标志(默认值否)
private boolean stopFlag = false;//停止标志(false——表示存在)
private boolean beread = false;//是否被储存在文件里过(默认值否)
?????? public BallThread(JPanel jp){
??? ?????? ???this.jp = jp;
??? ?????? ???this.g = jp.getGraphics();
?????? }
?
?????? public void run(){
??????????????banLlistener band =new banLlistener(jp);//定义滑块
??? ?????? ???jp.addMouseMotionListener(band);//给滑块加入鼠标监听器
??? ?????? ???if(beread==false){//如果没有被储存在文件里过
??? ?????? ???this.setprivate();//方法作用:随机生成它的部分属性
??? ?????? ???}
//实现小球运动的思路为:才窗体上沿小球运动路线不断绘制小球,并将之前的小球擦掉
??? ?????? ???while(true){//永真表示球会一直运动
??????? ?????? ???
??? ??????????????? ???try{
??? ????????????????????????? ???sleep(30);
??? ??????????????? ???}catch(InterruptedException e){
??? ????????????????????????? ???e.printStackTrace();
??? ??????????????? ???}
??? ??????????????? ???if(stopFlag==true){//如果停止标示为true,停止该线程
??? ????????????????????????? ???clearBall();
??? ????????????????????????? ???return;
??? ??????????????? ???}
??? ??????????????? ???if(pauseFlag==true){//如果暂停标示为真,跳过之后的步骤进入下次循环
??? ????????????????????????? ???continue;
??? ??????????????? ???}
??? ??????????????? ???
??? ??????????????? ???this.clearBall();//清除原来位置的小球
??? ??????????????? ???this.move();//小球运动
??? ??????????????? ???this.drawBall();//在新的位置画出小球
?
??? ??????????????? ???
??? ?????? ???}
??? ?????? ???????????????? ???
}
?????? public void clearBall(){//清除小球
??? ?????? ???Color color = jp.getBackground();//
??? ?????? ???g.setColor(color);//
??? ?????? ???g.fillOval(X, Y, radios*2, radios*2);//用背景色,填充之前小球的印记
?????? }
?????? public void drawBall(){
??? ?????? ???g.setColor(color);//
??? ?????? ???g.fillOval(X, Y, radios*2, radios*2);
?????? }
?????? public void setprivate(){//设置小球属性
??? ?????? ???Random random = new Random();//随机
??? ?????? ????radios = 10+random.nextInt(10);//半径
??? ?????? ????color=newColor(random.nextInt(255),random.nextInt(255),random.nextInt(255));//颜色
??? ?????? ????Xspeed = 2 + random.nextInt(10);//x方向速度
??? ?????? ????Yspeed = 2+random.nextInt(10);//y方向速度
?????? }
?????? public void exit(boolean flag){//设置停止标示
??? ?????? ???stopFlag = flag;
?????? }
?????? public void setpause(boolean flag){//设置暂停标示
??? ?????? ???pauseFlag = flag;
?????? }
?????? public void move(){//让我们的小球在面板中飞起来,同时碰到边界被弹回
?
??? ?????? ???switch(Xdirection){//对于x方向
??? ?????? ???case 2:X = X - Xspeed;break;//如果小球的运动方向向西,X值减小
??? ?????? ???case 4:X = X + Xspeed;break;//如果小球的运动方向向东,X值增大
??? ?????? ???}
??? ?????? ???switch(Ydirection){//对于y方向
??? ?????? ???case 1:Y = Y - Yspeed;break;//如果小球的运动方向向北,Y值减小
??? ?????? ???case 3:Y = Y + Yspeed;break;//如果小球的运动方向向难,Y值增大
??? ?????? ???}
??? ?????? ???//如果碰到边界,方向改变
??? ?????? ???if(X<0+radios*2){
??? ??????????????? ???Xdirection = 4;
??? ?????? ???}
??? ?????? ???if(X>jp.getWidth()-radios*2){
??? ??????????????? ???Xdirection = 2;
??? ?????? ???}
??? ?????? ???if(Y<0+radios*2){
??? ??????????????? ???Ydirection = 3;
??? ?????? ???}
??? ?????? ???//如果掉到下面,该小球线程结束
??? ?????? ???if(Y>jp.getHeight()-radios*2){
??? ??????????????? ???//Ydirection = 1;
??? ??????????????? ???BallThread ball = new BallThread(jp);
??? ??????????????? ???this.exit(true);
??? ??????????????? ???for(int i = 0;i<Date.allBall.size();i++){
??? ????????????????????????? ??ball=Date.allBall.get(i);
??? ????????????????????????? ??if(X == ball.X&&Y == ball.Y){
??? ?????????????????????????????????? ??Date.allBall.remove(i);
??? ????????????????????????? ??}
??? ??????????????? ???}
??? ?????? ???}
??????????????//如果碰到滑块,弹回
??? ?????? ???if(Y<500+radios/2&&Y>490-radios*2&&X>=Date.xband&&X<=(Date.xband+100)){
??? ??????????????? ???Ydirection = 1;
??? ?????? ???}
?????? }
? ????????//下面全是get和set方法(定义以下方法主要在文件操作时用到):
?????? public int getXdirection() {
??????????????? return Xdirection;
?????? }
?
?????? public void setXdirection(int xdirection) {
??????????????? Xdirection = xdirection;
?????? }
?
?????? public int getYdirection() {
??????????????? return Ydirection;
?????? }
?
?????? public void setYdirection(int ydirection) {
??????????????? Ydirection = ydirection;
?????? }
?
?????? public int getRadios() {
??????????????? return radios;
?????? }
?
?????? public void setRadios(int radios) {
??????????????? this.radios = radios;
?????? }
?
?????? public Color getColor() {
??????????????? return color;
?????? }
?
?????? public void setColor(Color color) {
??????????????? this.color = color;
?????? }
?
?????? public int getXspeed() {
??????????????? return Xspeed;
?????? }
?
?????? public void setXspeed(int xspeed) {
??????????????? Xspeed = xspeed;
?????? }
?
?????? public int getYspeed() {
??????????????? return Yspeed;
?????? }
?
?????? public void setYspeed(int yspeed) {
??????????????? Yspeed = yspeed;
?????? }
?
?????? public int getX() {
??????????????? return X;
?????? }
?
?????? public void setX(int x) {
??????????????? X = x;
?????? }
?
?????? public int getY() {
??????????????? return Y;
?????? }
?
?????? public void setY(int y) {
??????????????? Y = y;
?????? }
?
?????? public int getLastX() {
??????????????? return LastX;
?????? }
?
?????? public void setLastX(int lastX) {
??????????????? LastX = lastX;
?????? }
?
?????? public int getLastY() {
??????????????? return LastY;
?????? }
?
?????? public void setLastY(int lastY) {
??????????????? LastY = lastY;
?????? }
?
?????? public int getXband() {
??????????????? return xband;
?????? }
?
?????? public void setXband(int xband) {
??????????????? this.xband = xband;
?????? }
?
?????? public int getYband() {
??????????????? return yband;
?????? }
?
?????? public void setYband(int yband) {
??????????????? this.yband = yband;
?????? }
?
?????? public boolean isPauseFlag() {
??????????????? return pauseFlag;
?????? }
?????? public boolean savePauseFlag() {
??????????????? return false;
?????? }
?
?????? public void setPauseFlag(boolean pauseFlag) {
??????????????? this.pauseFlag = pauseFlag;
?????? }
?
?????? public boolean isStopFlag() {
??????????????? return stopFlag;
?????? }
?
?????? public void setStopFlag(boolean stopFlag) {
??????????????? this.stopFlag = stopFlag;
?????? }
?
?????? public boolean isBeread() {
??????????????? return beread;
?????? }
?
?????? public void setBeread(boolean beread) {
??????????????? this.beread = beread;
?????? }
??????
?????? public boolean saveBeread() {
??????????????? return true;
?????? }
?
?????? public JPanel getJp() {
??????????????? return jp;
?????? }
?
?????? public void setJp(JPanel jp) {
??????????????? this.jp = jp;
?????? }
??????
}
?
定义了小球类之后,我们要考虑的另一个问题就是,我们什么时候要让小球在界面上飞,作为一个游戏,至少需要有开始按钮,当按钮被触发,游戏开始,所以我们需要用到的另一个工具就是事件监听器:
除了开始按钮,我们还为这个游戏做了其他功能:暂停,加一球,减一球;
接下来是代码:
文件一:Date,将小球使用一个链表存起来:
package jumpingBall;
?
import java.util.ArrayList;
import java.util.List;
?
public class Date {//此类专门存放全局变量
?public static int xband;
?public static int yband;
?public static List<BallThread> allBall = new ArrayList<BallThread>();//将链表声明为全局变量
}
?
?
package jumpingBall;
import java.awt.event.ActionEvent;
import java.awt.event.MouseMotionListener;
import java.util.ArrayList;
import java.util.List;
?
import javax.swing.JPanel;
?
import sun.net.www.content.audio.x_aiff;
?
?
?
public class ActionListener? implements java.awt.event.ActionListener{
?????
?????? //private List<BallThread> allBall = new ArrayList<BallThread>();
?????? private JPanel jpanel;
?????? private int xband;
?????? private int yband;
??????
?????? public ActionListener(JPanel jpanel){//构造方法
?????????? //this.allBall = allBall;
?????????? this.jpanel = jpanel;
?????? }
?????? public void actionPerformed(ActionEvent e) {
??????????????? // TODO Auto-generated method stub
??????????????? String cmd = e.getActionCommand(); //
??????????????? //选择开始选择?
??????????????? if(cmd.equals("Play")){
????????????????????????? ? //如果场上没球,添加一个
????????????????????????? ? if(Date.allBall.size()==0){
?????????????????????????????????? ? BallThread ball = new BallThread(jpanel);
?????????????????????????????????? ? Date.allBall.add(ball);
?????????????????????????????????? ? ball.start();
?????????????????????????????????? ?System.out.println("增加一个小球,场上小球个数变为:"+Date.allBall.size());
????????????????????????? ? }
????????????????????????? ? //如果场上有球,让所有静止的球动起来
????????????????????????? ? for(int i = 0;i<Date.allBall.size();i++){
?????????????????????????????????? ? BallThread ball= Date.allBall.get(i);
?????????????????????????????????? ? ball.setpause(false);
????????????????????????? ? }
????????????????????????? ?// banLlistener band = new banLlistener(jpanel);
????????????????????????? ? //jpanel.addMouseMotionListener(band);
??????????????? ? }
??????????????? ? //选择暂停选项
??????????????? ? if(cmd.equals("Pause")){
????????????????????????? ? //遍历场上所有小球,修改ball的pause属性
????????????????????????? ? for(int i = 0;i<Date.allBall.size();i++){
?????????????????????????????????? ? BallThread ball= Date.allBall.get(i);
?????????????????????????????????? ? ball.setpause(true);
????????????????????????? ? }
??????????????? ? }
??????????????? ? //选择增球
??????????????? ? if(cmd.equals("Add")){
????????????????????????? ? BallThread ball = new BallThread(jpanel);
????????????????????????? ? Date.allBall.add(ball);
????????????????????????? ? ball.start();//运行线程
????????????????????????? ?System.out.println("增加一个小球,场上小球个数变为:"+Date.allBall.size());
??????????????? ? }
??????????????? ? //选择减一球选项
??????????????? ? if(cmd.equals("Delet one ball")&&Date.allBall.size()!=0){
????????????????????????? ?BallThread ball = Date.allBall.get(Date.allBall.size()-1);
????????????????????????? ?ball.exit(true);//修改存在选项(设置其消失)
????????????????????????? ?Date.allBall.remove(Date.allBall.size()-1);//减一球
????????????????????????? ?System.out.println("减少一个小球,场上小球个数变为:"+Date.allBall.size());
??????????????? ? }
??????????????? ?
?????? }
?
}
此外还要在界面类中敲上以下代码(黑色加粗部分)
//javax.swing.JFileChooser使用此来选择文件
package jumpingBall;
?
import java.awt.Toolkit;
import java.awt.BorderLayout;
import java.awt.Menu;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JSeparator;
?
?
public class JFjumpingBall extends JFrame{
?
?????? /**
?????? ?* @param args
?????? ?* @throws IOException
?????? ?*/
?????? public static void main(String[] args) throws IOException {
??????????????? // TODO Auto-generated method stub
?
??????????????? JFjumpingBall ballgame = new JFjumpingBall();
??????????????? ballgame.JFshow();
?????? }
??????
?????? public void JFshow(){
??????????????? //建立一个窗体:
?????? ?? double width = Toolkit.getDefaultToolkit().getScreenSize().width;//定义width获取显示器在该分辨率下的宽
?????? ?? double height = Toolkit.getDefaultToolkit().getScreenSize().height;//定义height获取显示器在该分辨率下的高
?????? ?? this.setSize((int)width,(int)height);//设置窗体大小
?????? ?? this.setTitle("小鱼躲气泡");//设置标题
?????? ?? this.setLocationRelativeTo(null);//设置窗口居中
?????? ?? this.setDefaultCloseOperation(3);//设置关闭窗口程序停止运行
?????? ?? this.setLayout(new BorderLayout());//设置窗体布局(边框式布局)
??????????????? JPanel northPanel = new JPanel();//北部面板
??????????????? JPanel jpanel = new JPanel();//面板
??????????????? JPanel southjpanel = new JPanel();//南部面板
??????????????? northPanel.setLayout(new BorderLayout());//设置北部面板布局方式
??????????????? JPanel northLeftPanel = new JPanel();//北部面板左边
??????????????? JPanel northRightPanel = new JPanel();//……右边
??????????????? JPanel northCenterPanel = new JPanel();//……中间
??????????????? northLeftPanel.setSize(100,100); //
??????????????? northRightPanel.setSize(100, 100);//
??????????????? JButton jbplay = new JButton("Play");//放置游戏按钮(开始游戏)
??????????????? JButton jbPause = new JButton("Pause");//放置游戏按钮(游戏暂停)
??????????????? JButton jbAdd? = new JButton("Add");//放置游戏按钮(增加)
??????????????? JButton deletone = new JButton("Delet one ball");//放置游戏按钮(减少一个小球)
??????????????? northCenterPanel.add(jbplay);//将按钮放置在北部面板的中间面板
??????????????? northCenterPanel.add(jbPause);//同上
??????????????? northCenterPanel.add(jbAdd);//同上
??????????????? northCenterPanel.add(deletone);//同上
??????????????? northPanel.add(northCenterPanel,BorderLayout.CENTER);//将北部面板的各部分面板加在北部面板里
??????????????? northPanel.add(northLeftPanel,BorderLayout.WEST);//
??????????????? northPanel.add(northRightPanel,BorderLayout.EAST);//
??????????????? this.add(northPanel,BorderLayout.NORTH);//布置窗体
??????????????? this.add(jpanel,BorderLayout.CENTER);//
??????????????? this.add(southjpanel,BorderLayout.SOUTH);//
??????????????? this.setJMenuBar(JMenuline(jpanel));//给窗体添加菜单栏(菜单栏方法:JMenuline;方法声明在下部)
??????????????? this.setVisible(true);//设置窗体可见
??????????????? //List<BallThread> allBall = new ArrayList<BallThread>();//
??????????????? ActionListener l = new ActionListener(jpanel);//动作监听器
??????????????? jbplay.addActionListener(l);//jbplay添加动作监听器
??????????????? jbPause.addActionListener(l);//jbPause添加动作监听器
??????????????? jbAdd.addActionListener(l);//jbAdd添加动作监听器
??????????????? deletone.addActionListener(l);//delete添加动作监听器
?????? }
?????? public JMenuBar JMenuline(JPanel jpanel){
?????? ?? JMenuBar jme =new JMenuBar();//定义菜单栏
?????? ?? JMenu menuF = new JMenu("文件(F)");//菜单栏按钮
?????? ?? JMenuItem jmiFO = new JMenuItem("保存(save)");//定义菜单栏按钮的选项(保存)
?????? ?? JMenuItem jmiIO = new JMenuItem("读取(login)");//定义菜单栏按钮的选项(读取)
?????? ?? foListener listener = new foListener();//定义保存监听器
?????? ?? ioListener listener2 = new ioListener(jpanel);//定义读取监听器
?????? ?? jmiFO.addActionListener(listener);//将保存监听器加在jmiFO
?????? ?? jmiIO.addActionListener(listener2);//将读取监听器加在jmiIO
?????? ?? menuF.add(jmiFO);//将(保存)菜单栏按钮加在menuF里
?????? ?? JSeparator jSeparator = new JSeparator();//定义水平分割线
?????? ?? menuF.add(jSeparator);//将水平分割线加在menuF里
?????? ?? menuF.add(jmiIO);//将(读取)菜单栏按钮加在menuF里
?????? ?? jme.add(menuF);//讲此菜单栏按钮加在jme里
?????? ?? return jme;
?????? }
?
}