程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> 創建Eclipse游戲插件,第3部分: 啟動游戲

創建Eclipse游戲插件,第3部分: 啟動游戲

編輯:關於JAVA

雖然多數用戶都把 Eclipse 當成構建 Java ™ 應用程序的集成開發環境,實際上它是更基本的東西。Eclipse 是構建插件的框架,允許擴展其功能去解決幾乎任何問題 —— 只要利用一套 API 和現成可用的庫。在這份四個部分的 “創建 Eclipse 游戲插件” 教程系列中,將解決多數程序員每天都會遇到的一個迫切問題:如何不用切換應用程序就抽出時間玩一個迅速的視頻游戲,還能讓它不太明顯。教程中將開發一個簡單的程序,讀取進入視圖的蟲子,並把它們打爆。游戲將在 Eclipse 中作為插件運行,這個游戲演示了如何編寫 Eclipse API,如何使用 Standard Widget Toolkit、Open Graphics Library 和 Lightweight Java Games Library。第 3 部分將增加蟲子和 BB 彈之間的碰撞檢測並破壞蟲子。

開始之前

這個系列面向的是對使用 OpenGL 構建 Eclipse 游戲插件有興趣的開發人員。這份教程在 第 2 部分 的基礎上繼續開發,用 OpenGL 為 BB 彈添加移動和碰撞檢測。

關於這個系列

在這個四部分的系列中,介紹用來創建特性完整的 Eclipse 插件的基本技術、工具和庫,將使用 Standard Widget Toolkit(SWT)和 OpenGL 庫提供圖形。第 1 部分 介紹如何構建簡單視頻游戲的框架,通過創建插件,可以在 Eclipse 內部啟動並玩這個游戲。第 2 部分 在第 1 部分創建的基本框架基礎上,開始用 Open GL 添加實際的可視元素。第 3 部分添加實際的游戲元素,讓用戶能夠與第 2 部分創建的圖形進行交互。第 4 部分把前三部分創建的所有內容合在一起,確保它們能一起工作。

關於這份教程

這份教程從 第 2 部分 結束的地方開始,使用我們已經創建的形狀和功能讓游戲走向實用。在這篇文章中,將做以下工作:

為 BB 槍添加移動。

為 BB 彈和蟲子添加碰撞效果,使被擊中的蟲子粉碎並消失,顯示文本 “POW”。

前提條件

這份教程假設讀者擁有 Java 語法和編碼以及 Eclipse 插件編程的基本知識,正如這個系列的 第 1 部分 所示。圖形編程的知識會有益,但並不是必需的。不要求關於 OpenGL 的知識。

系統需求

需要以下軟件:

Eclipse Eclipse 是創建第 1 部分的插件的框架。現在要繼續利用 Eclipse 構建游戲插件。請從 Eclipse.org 下載 Eclipse V3.2 M3 或以上版本 。Eclipse SWT SWT 是 Eclipse 的部件包,用於制作窗口,由 IBM 捐贈給 Eclipse。 請下載 SWT 3.2 M3 或以上版本。Eclipse OpenGL 需要用 OpenGL 來創建形狀等等。請下載實驗性的 org.eclipse.opengl binding, version 0.5 for SWT 3.2。使用 OpenGL 的 Eclipse 示例插件 請下載 使用 OpenGL 的帶有一個視圖的示例插件。將用這個插件中的源代碼作為構建自己的定制 OpenGL 布景的框架。Java 技術 Eclipse 和它的所有插件都需要 Java 技術。

概述和設置

在 第 2 部分 中,我們著重用 OpenGL 構建了游戲對象。現在將編寫游戲功能的代碼。

當前進展

目前,我們已經用 OpenGL 開發了幾個形狀,包括貼了圖的 BB 槍、球形的蟲子和圓柱形的子彈。我們還創建了在蟲子被擊中時顯示的文本(“POW”)。下面,我們將了解要編寫的功能。

游戲

游戲的各部分已經就位,可以編寫代碼了。先從放在一條線上的 BB 槍和蟲子開始,槍是射擊一方。應當能夠上下左右移動 BB 槍,並射出 BB 彈,就像我們在第 2 部分中用空格鍵所做的那樣。但是這次,子彈不僅僅是穿過蟲子,我們要編寫代碼,讓子彈觸發 “打爆” 蟲子功能,並顯示文本 “POW”。在半秒之後,蟲子和 “POW” 文本消失。

移動 BB 槍

每個游戲都允許玩家移動他控制的部件 —— 在這個示例中就是 BB 槍。在添加這個功能之前,需要為我們創建和初始化的每個對象創建 3 維坐標。這一節介紹這個功能,這個功能允許玩家四處移動槍。

添加正確的坐標:蟲子

在這份教程後面,當添加碰撞檢測時,需要知道游戲中每個部件的正確坐標。請把坐標添加到 Bug 類中,如清單 1 所示。

清單 1. 掛上蟲子的坐標

...
    private float ox, oy, oz;
    public Bug(float[] color, float ox, float oy, float oz) {
      this.ox = ox;
      this.oy = oy;
      this.oz = oz;
...

現在有了當前蟲子的 x、y 和 z 坐標。需要重載 Bug 類的 draw 方法,如清單 2 所示。

清單 2. draw 方法

public void draw(){
       GL.glTranslatef(ox, oy, oz);
       super.draw();
       GL.glTranslatef(-ox, -oy, -oz);
     }

現在我們要把原點轉到繪制蟲子的位置,繪制蟲子,然後換回原點。

添加正確的坐標:子彈

除了向 Bullet 類添加 3 維坐標之外,還必須添加其他一些東西。例如,為了避免每秒發射數百次,我們將限制槍的發射速率。請參閱清單 3。

清單 3. 添加新變量

...
     private float ox, oy, oz;
     private float translationGunX;
     private float translationGunY;
     private GameScene game;
     private static long lastShotMilliseconds;
     public Bullet(GameScene game, float ox, float oy, float oz) {
       lastShotMilliseconds = System.currentTimeMillis();
       this.game = game;
       this.ox = ox;
       this.oy = oy;
       this.oz = oz;
...

在創建 Bullet 類時,把靜態變量 lastShotMilliseconds 初始化為當前時間,並設置 x、y 和 z 坐標,就像對 Bug 類所做的那樣。請按照清單 4 修改發射 BB 彈(稱為 “bullets”)的方法。

清單 4. 發射子彈

public void shoot(){
     for(int i = 0; i < bullets.length; i++)
       if(!bullets[i].fired){
          bullets[i].shoot(gun.translationx, gun.translationy);
          break;
       }
   }

現在發射 BB 彈時將提供槍的當前坐標,這樣在射擊時 BB 彈就會在槍口指向的位置出來,而不是在槍的原始位置出來。請照此修改 Bullet 類的 shoot 方法,如清單 5 所示。

清單 5. 修改 shoot 方法

public void shoot(float tGunX, float tGunY){
       long now = System.currentTimeMillis();
       if(now - lastShotMilliseconds < 250)
         return;
       lastShotMilliseconds = now;
       translationGunX = tGunX;
       translationGunY = tGunY;
...

這裡就是射擊的地方,但是只有不超過允許的射擊速率才可以。然後設置槍的坐標,分別保存在 translationGunX 和 translationGunY 中。請修改 draw 方法,利用槍和子彈的坐標,如清單 6 所示。

清單 6. 在正確的位置繪制槍

public void draw(){
       if(translation >= -100 && fired){
         GL.glTranslatef(translationGunX + ox,
                 translationGunY + oy,
                 translation + oz);
         super.draw();
         GL.glTranslatef(-translationGunX - ox,
                 -translationGunY - oy,
                 -translation - oz);
       }
     }

就像在 Bug 類中一樣,在繪制 BB 槍之前,要把原點轉換到要繪制 BB 槍的位置,然後再轉換回原點。

添加正確的坐標:槍

現在設置 Gun 類。Gun 類需要沿著 x 和 y 平面移動,移動從子彈的起始位置開始。請修改 Gun 類的構造函數添加這個功能,如清單 7 所示。

清單 7. 修改 Gun 類

...
     private float ox, oy, oz;
     private float translationx;
     private float translationy;
     public Gun(float ox, float oy, float oz) {
       translationy = 0;
       translationx = 0;
       this.ox = ox;
       this.oy = oy;
       this.oz = oz;
...
這段代碼把槍的位置初始化為它的原始位置,至於槍,則由清單 8 中的代碼繪制。

清單 8. 繪制槍

public void draw(){
       GL.glTranslatef(translationx + ox,
               translationy + oy,
               oz);
       super.draw();
       GL.glTranslatef(-translationx - ox,
               -translationy - oy,
               -oz);
     }

很好!三個類都在正確的位置顯示。剩下的惟一一件事就是如何初始化它們,下面馬上介紹。

初始化各個部件

在這裡,我們把游戲中每個部件的初始坐標發送到它們各自的構造函數。它們的初始位置與第 2 部分中的位置一樣,但是現在的處理不同,以支持碰撞偵測。請參閱清單 9。

清單 9. 初始化游戲部件的位置

...
     this.gun = new Gun(0, 0, 12);

     bugCount = ShootoutView.viewer.getTable().getItemCount();
     this.bugs = new Bug[bugCount];
     float tx = -Bug.RADIUS*bugCount;
     for (int i = 0; i < this.bugs.length; i++){
       this.bugs[i] = new Bug(COLOR[i % COLOR.length], tx, 0, -8);
       tx += 2*Bug.RADIUS;
     }

     pow = new Pow();

     bullets = new Bullet[25];
     for(int i = 0; i < bullets.length; i++)
       bullets[i] = new Bullet(this, .2f, -.2f, 9.5f);
...
現在,在創建部件中的對象時,也傳遞它們的初始位置。

游戲性和用戶交互

沒有用戶交互的游戲就不是游戲了。這個游戲通過鍵盤輸入來玩。也可以修改游戲,讓它接受鼠標或其他輸入設備的輸入。現在來控制槍。

用鍵盤輸入控制槍

在得到鍵盤輸入時,需要設置 Gun 類中的布爾值,讓它表示槍的移動方向。請修改方向鍵的事件代碼,如清單 10 所示。

清單 10. 處理 keyPressed 事件

public void keyPressed(KeyEvent e) {
     switch (e.keyCode) {
     case SWT.ARROW_UP:
       game.moveGun(false, true, false, false);
       break;
     case SWT.ARROW_DOWN:
       game.moveGun(false, false, false, true);
       break;
     case SWT.ARROW_LEFT:
       game.moveGun(false, false, true, false);
       break;
     case SWT.ARROW_RIGHT:
       game.moveGun(true, false, false, false);
       break;
     case SWT.PAGE_UP:
...

在這裡,我們調用 moveGun 方法。這個方法調用 Gun 類的 move 方法,設置一個布爾值,表示槍的移動方向。然後,處理 keyReleased 事件,如清單 11 所示。

清單 11. 處理 keyReleased 事件

public void keyReleased(KeyEvent e) {
     switch (e.keyCode) {
     case SWT.ARROW_UP:
     case SWT.ARROW_DOWN:
     case SWT.ARROW_LEFT:
     case SWT.ARROW_RIGHT:
       game.moveGun(false, false, false, false);
       break;
     }
   }

現在,在釋放鍵的時候,槍的方向會被清除。

下面,把需要的方法添加到 GameScene 類和 Gun 類。

添加鉤子到 Gun 類

在槍移動時,事件通知被發送到 keyEvent 偵聽器。在第 2 部分的實現中,SceneGrip 類是處理這些事件的偵聽器。所以,在按下方向鍵時,SceneGrip 調用 GameScene 類的 moveGun 方法。請定義這個 moveGun 方法,如清單 12 所示。

清單 12. 移動槍

...
   public void moveGun(boolean movingPosX, boolean movingPosY,
             boolean movingNegX, boolean movingNegY){
     gun.move(movingPosX, movingPosY, movingNegX, movingNegY);
   }

我們只是把布爾變量傳遞給 Gun 類的 move 方法。現在把 move 方法添加到槍,如清單 13 中的代碼所示。

清單 13. 把移動方向添加到 Gun 類

private boolean movingPosX;
     private boolean movingPosY;
     private boolean movingNegX;
     private boolean movingNegY;
     public void move(boolean movingPosX, boolean movingPosY,
              boolean movingNegX, boolean movingNegY){
       this.movingPosX = movingPosX;
       this.movingPosY = movingPosY;
       this.movingNegX = movingNegX;
       this.movingNegY = movingNegY;
     }

用布爾值表示槍的當前移動方向,並把它們保存在 Gun 類本地留作後用。

有了槍的方向之後,槍的移動就可以實現動畫效果了。

動畫實現槍的移動

現在我們知道了槍要移動的方向,可以用 TimerTask 實現移動,做出動畫效果,如清單 14 所示。

清單 14. 移動槍

public Gun(float ox, float oy, float oz) {
       this.ox = ox;
       this.oy = oy;
       this.oz = oz;
       translationy = 0;
       translationx = 0;
       movingPosX = false;
       movingPosY = false;
       movingNegX = false;
       movingNegY = false;
       t = new Timer();
       tt = new TimerTask(){
         float max = 10;
         float delta = 0.01f;
         public void run(){
           if(movingPosY)
             translationy += delta;
           if(movingPosX)
             translationx += delta;
           if(movingNegY)
             translationy -= delta;
           if(movingNegX)
             translationx -= delta;

           if(translationx < -max)
             translationx = -max;
           if(translationx > max)
             translationx = max;
           if(translationy < -max)
             translationy = -max;
           if(translationy > max)
             translationy = max;
         }
       };
       t.scheduleAtFixedRate(tt, 0, 2);
...

首先,添加新的變量並把它們初始化為 false,表示槍在開始時並未移動。然後設置 TimerTask 的 run 方法,根據槍的當前方向 ,加上或減去 translationx 或 translationy。另外,通過限制移動不能超過 x 軸和 y 軸 +/- 極限,限制槍的移動。這樣,槍就不會離開原點太遠,因為蟲子怎麼也不會在那裡。

碰撞檢測

多數計算機游戲都使用某種碰撞檢測。在許多情況下,碰撞檢測用在一個范圍上,好讓玩家操縱某個東西在屏幕上移動。在這個游戲中,我們在 BB 彈和蟲子之間實現了碰撞檢測。

游戲和碰撞檢測

如果沒有某種形式的碰撞檢測,計算機游戲就沒有意義,因為沒有它游戲就無法對玩家做的 “好事” 作出響應(在這個游戲中,“好事” 指的就是擊中了一只蟲子)。第一人稱射擊游戲用許多方式實現碰撞檢測,例如可以攻擊的牆或身體的一部分,采用某些比其他方式更致命的射擊。爆炸也涉及碰撞檢測,與大型 BB 彈的功能類似,而且離得越遠,受的傷害越小。

碰撞檢測實現

實現碰撞檢測有多種方法,有些比較復雜。游戲編程對計算機處理能力的消耗很大。在游戲中可做的事情很多,如果同時做這些事,那麼游戲會慢下來,甚至不堪忍受。最復雜的碰撞檢測方法可以是強力算法,搜索對象表面的每個像素,查看 BB 彈是否擊中了它。另一個方法可能是某種非線性函數,檢測曲線對象上的碰撞;但是這個方法可能會更復雜。在這個教程中,我們將使用相對簡單的碰撞檢測。

簡單的碰撞檢測

為了最大限度地利用這個游戲,在每件事上我們都用最簡單的方法,包括碰撞檢測。簡單方法的好處就是游戲的玩家並不介意碰撞檢測是否完美。一個簡單的方法是 3 維距離算法,可以用 Bug.RADIUS 進行計算,這樣如果一顆 BB 彈進入了蟲子的范圍,就觸發蟲子上的 “爆炸”。不過這可能會涉及一個平方函數,這個函數是比較運算密集型的。更好的方法可能是一種簡單的 3 維六邊形窗口化函數。這個函數需要 BB 彈所在的點,以及蟲子位於其中的最小盒子,這樣,可以想像有一個看不到的立方體包著蟲子。如果 BB 彈進入這個立方體,蟲子就被擊中了。這一節剩下的部分將實現這個算法。

擴展 Bug 類

為了幫助 Bug 類進行碰撞檢測,我們需要添加兩個布爾類型的變量,區分活著的、爆炸的和死掉的蟲子。這些變量有助於在 Bug 類中保存蟲子的狀態 —— 這意味著如果蟲子是活的,就應當顯示並正確地活動。如果蟲子爆炸了,就顯示為爆炸。如果死掉,就不應當影響游戲或顯示。請添加這些狀態變量和計時器功能,如清單 15 所示。

清單 15. 擴展 Bug 類的功能

private boolean blowUp;
     private boolean dead;
     Timer t;
     TimerTask tt;
     public Bug(float[] color, float ox, float oy, float oz) {
       dead = false;
       blowUp = false;
       t = new Timer();
...

添加了兩個布爾變量保存蟲子是否爆炸,添加了一個計時器,用來顯示 “POW” 文本,並讓蟲子消失。現在我們學習在哪裡放置碰撞檢測的代碼。

在哪裡檢測

既然已經知道了在碰撞檢測中要做什麼,現在就要把檢測碰撞的代碼添加到某個地方。可以把代碼添加到蟲子或 BB 彈(子彈)上。但是,子彈通常比蟲子多,所以我們在 Bullet 類的計時器任務中做這件事,如清單 16 所示。

清單 16. 子彈負責檢測是否擊中了蟲子

public void shoot(float tGunX, float tGunY){
...
       tt = new TimerTask(){
         public void run(){
           translation-=0.1;
           for(int j = 0; j < game.bugs.length; j++){
             if(!game.bugs[j].blowUp && !game.bugs[j].dead)
               game.bugs[j].checkShot(Bullet.this);
           }
           if(translation < -100){
...

我們循環檢查每個蟲子,如果蟲子沒爆炸,也沒死,就調用 checkShot,檢查是否擊中了它。下面來實現這個方法。

實現最簡單的碰撞檢測

現在進入碰撞檢測算法的實質部分。checkShot 算法檢測 BB 彈是否進入了蟲子所在的立方體(如前所述)。請把這個方法添加到 Bug 類,如清單 17 所示。

清單 17. 蟲子和 BB 彈之間的核心碰撞檢測算法

public void checkShot(Bullet b){
       // position of end closest to the gun
       float bx = b.ox + b.translationGunX;
       float by = b.oy + b.translationGunY;
       float bz = b.oz + b.translation;

       // center point of the circle
       float x = ox;
       float y = oy;
       float z = oz;

       // 3-dimensional window of the bug
       float x1 = x - RADIUS;
       float x2 = x + RADIUS;
       float y1 = y - RADIUS;
       float y2 = y + RADIUS;
       float z1 = z - RADIUS;
       float z2 = z + RADIUS;

       // if the bullet is inside the bug, he's going to blow up 
       if(bx > x1 && bx < x2)
         if(by > y1 && by < y2)
           if(bz > z1 && bz < z2)
             blowUp = true;
     }

首先,得到 BB 彈的確切(x, y, z)位置,然後得到蟲子的中心點。接下來,通過加/減蟲子的半徑(在 Bug.RADIUS 中定義)得到構成立方體的六個點,每個軸兩個點。現在有了必要的值,可以判斷點(x, y, z)是否在蟲子所在的立方體之中。如果正在檢測沿著 x 軸的碰撞,那麼在 x1 和 x2 之間(可以用 bx > x1 && bx < x2 計算)的蟲子就會觸發碰撞。對於其他兩個軸,y 和 z 軸也如法炮制,這樣就會知道 BB 彈是否落入蟲子的范圍內,並把布爾變量 blowup 設為 true。下一節介紹如何處理這個工作和啟用破壞蟲子的動畫。

破壞蟲子

如果我們擊中了蟲子,就需要觸發讓它爆炸的動畫,顯示 “POW” 文本,然後消失。

響應用戶輸入和事件

如果開槍擊中,而被擊中的對象什麼也沒發生,那麼游戲不會讓人興奮和上瘾。所以,在游戲中對事件響應的方式要使游戲更興奮、更好玩。在這個游戲中,我們要讓蟲子爆炸,顯示 “POW”,然後消失。還可以添加其他事件,例如在所有蟲子爆炸和死掉時,可以顯示 “We win” 或者出現一個更大更強壯的蟲子,只有擊中它的兩只眼睛才能打掉它。我們也可以給用戶設一個時間限制,如果在指定時間內沒有把蟲子破壞掉,就觸發一個事件,告訴用戶游戲結束。這節剩下的部分添加的代碼,在蟲子標記為爆炸的時候(布爾變量 blowup 為 true)觸發一個事件,開始顯示 “POW”。

顯示 “POW”

蟲子爆炸的第一個事件顯示 “POW”。所以,只需要在蟲子爆炸卻還沒死的時候繪制 POW。我們在 drawScene 方法中添加這個功能,如清單 18 所示。

清單 18. 蟲子爆炸時顯示 POW

protected void drawScene() {
     super.drawScene();
     this.grip.adjust();

     GL.glBindTexture(GL.GL_TEXTURE_2D, Gun.TEXTURES[1]);
     boolean drawPow = false;
     for(int i = 0; i < bugs.length; i++)
       if(!drawPow && bugs[i].blowUp && !bugs[i].dead)
         drawPow = true;
     if(drawPow){
       pow.draw();
     }

     for(int i = 0; i < bullets.length; i++)
...

在這裡,檢查每個蟲子,如果蟲子爆炸了卻還沒死(沒有消失),就顯示 “POW”。接下來,添加顯示爆炸蟲子的代碼。

把蟲子炸掉

既然顯示了 “POW”,現在添加把蟲子炸掉的代碼。請修改 Bug 類的 draw 方法,如清單 19 所示。

清單 19. 炸掉蟲子

public void draw(){
       GL.glTranslatef(ox, oy, oz);
       if(blowUp)
         this.explode();
       super.draw();
       GL.glTranslatef(-ox, -oy, -oz);
     }

如果蟲子的布爾變量 blowUp 設置為 true,那麼這個代碼會炸掉蟲子,並顯示蟲子爆炸的碎片。接下來,配置一個計時器,讓蟲子消失。

讓蟲子的碎片消失

蟲子爆炸之後,就要讓它消失。與其他游戲類似,被消滅的敵人要等一會兒才消失。下面的代碼讓爆炸的蟲子在半秒之後消失。請修改 Bug 類的 draw 方法,如清單 20 所示。

清單 20. 讓死蟲子和蟲子碎片消失

public void draw(){
       if(dead)
         return;
       GL.glTranslatef(ox, oy, oz);
       if(blowUp){
         this.explode();
         tt = new TimerTask(){
           public void run(){
             cancel();
           }
           public boolean cancel(){
             boolean cancelled = super.cancel();
             dead = true;
             return cancelled;
           }
         };
         t.scheduleAtFixedRate(tt, 500, 500);
       }
       super.draw();
       GL.glTranslatef(-ox, -oy, -oz);
     }

如果蟲子死掉,就從方法返回,什麼也不繪制。另外,除了在布爾變量 blowUp 為 true 的時候把蟲子炸掉,我們還初始化了一個計時器任務,在半秒之後把布爾變量 dead 設為 true。

玩和重新開始游戲

玩游戲與第 2 部分中一樣。但是,在所有蟲子都被擊中的時候,我們想重新開始游戲,射掉更多蟲子。這是這一節的內容。

初始化游戲部件

游戲開始時通常有一個初始設置,用戶據此移動和操縱游戲。所以,我們需要把游戲部件初始化的部分隔離出來,好讓這項工作能夠進行。請修改 initGL 方法,並添加一個 initPieces 方法,如清單 21 所示。

清單 21. 初始化游戲部件

...
     GLU.gluQuadricNormals(Bug.QUADRIC, GLU.GLU_SMOOTH);

     GL.glEnable(GL.GL_TEXTURE_2D);

     initPieces();
   }

   public void initPieces(){
     this.gun = new Gun(0, 0, 12);

     bugCount = \ 
     ShootoutView.viewer.getTable().getItemCount();
     this.bugs = new Bug[bugCount];
     float tx = -Bug.RADIUS*bugCount;
     for (int i = 0; i < this.bugs.length; i++){
       this.bugs[i] = new Bug(COLOR[i % \ 
       COLOR.length], tx, 0, -8);
       tx += 2*Bug.RADIUS;
     }

     pow = new Pow();

     bullets = new Bullet[25];
     for(int i = 0; i < bullets.length; i++)
       bullets[i] = new Bullet(this, .2f, -.2f, 9.5f);
   }

我們采用了來自 initGL 方法的原始代碼,創建了一個新方法 initPieces,然後把代碼放在這個方法內。現在可以重新初始化游戲設置,供玩游戲使用。

釋放部件

就像對部件初始化所做的那樣,對釋放部件也要做同樣的事。請修改 dispose 方法,添加一個 disposePieces 方法,如清單 22 所示。

清單 22. 釋放部件

public void disposePieces() {
     this.gun.dispose();
     for(int i = 0; i < bugs.length; i++)
       bugs[i].dispose();
     for(int i = 0; i < bullets.length; i++)
       bullets[i].dispose();
     pow.dispose();
   }

   public void dispose() {
     GLU.gluDeleteQuadric(Gun.QUADRIC);
     GLU.gluDeleteQuadric(Bullet.QUADRIC);
     GLU.gluDeleteQuadric(Bug.QUADRIC);
     disposePieces();
     super.dispose();
   }

我們只是刪除了現有的釋放代碼,並把它們移動到 disposePieces 方法中。

重新開始游戲

現在添加了處理舊部件和初始化新部件的功能,可以在 ShootoutView 類中添加合適的功能了。請修改 ShootoutView 類中的以下代碼段,如清單 23 所示。

清單 23. 重新開始游戲

...
     startGameButton.setText("(Re)start Game");
     startGameButton.addSelectionListener(new SelectionAdapter() {
       public void widgetSelected(SelectionEvent event) {
...
           if(!ShootoutView.this.sceneRunning){
...
             ShootoutView.this.sceneRunning = true;
           }
           else{
             ShootoutView.this.scene.disposePieces();
             ShootoutView.this.scene.initPieces();
           }
         }
...

如果布景已經啟動運行,就需要重新初始化它,如 else 語句中的代碼所示。這就行了!現在,只要殺死了所有蟲子,就可以點擊 “(Re)start Game” 按鈕讓它們全復活。下面簡要總結一下如何才能讓這個游戲與眾不同。

要考慮的事情

OpenGL 是個強大的圖形編程 API,在編程時還有多個選項可用。例如,可以利用它的 2 維特性,創建平面 2 維游戲,就像老式的 Atari 游戲做的那樣。

正如提到過的,還可以做其他改進。一個改進是添加蟲子的隨機或定向移動,當它們到達某一點時,可以在屏幕的另一邊出現,就像 Atari's Asteroids 一樣;或者從牆上彈回,繼續向另一個方向移動。這可以讓游戲更難,更有挑戰性,更有意思,運動技能和手眼協調會得到測試,因為必須在 3 維空間中移動和瞄准並擊中目標。

添加聲音也是可能的。通過這種方式,可以讓每次命中和爆炸時都有聲音,不僅用視頻而且用音頻刺激游戲玩家。

最後,可以看看其他游戲,找找可以應用到自己游戲中的想法。

結束語

游戲終於完成了!我們用 OpenGL 在標准的 Eclipse 窗口中完成了一個 Eclipse 游戲。現在可以在工作的間隙,打開 Shootout 視圖,在 Eclipse 上玩游戲,稍事休息,射掉代表任務列表中每個項目的蟲子。

在第 4 部分中,將總結插件的完整操作和部署。

本文配套源碼

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved