1. 程式人生 > >Java學習之道:彈球遊戲分步解析(二)——讓小球飛

Java學習之道:彈球遊戲分步解析(二)——讓小球飛

之前跟大家說要把事件監聽器和多執行緒分開來講,不過之後發現事件監聽器要涉及到很多小球運動的操作,所以,決定將兩個知識點合起來說,這樣會更便於大家理解:

實現小球在我們所繪製的窗體上運動就必須要用到多執行緒;讓小球類繼承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;

       }

}