Java練手項目2:基於Java的坦克大戰遊戲(學習Java必備!!!)

1.引言

隨着社會和時代的進步,來自各個方面的壓力讓人沒精打采,爲了分解人們的壓力,休養那變得疲頓的頭腦和勞累的身心,特設計了坦克大戰小遊戲,遊戲操作非常容易,只要將手指放在鍵盤上敲擊相關的遊戲鍵就可以玩,在玩遊戲的過程中能夠體驗現實生活中沒有的快樂,既有利於身心健康,又不會影響工作和學習。本遊戲採用的是基於J2SE標準平臺的java編程技術,在Windows 7操作系統中使用Eclipse軟件進行代碼編譯,通過方法Graphics()來進行遊戲地圖界面的繪製,使用了接口技術使一個類能夠實現多個接口,使用套接字Socket來完成client端和server端的連接。

Java是一項面向對象編程語言,既包含了C語言的全部優點,又具有面向對象,跨平臺性,安全性等特點,是現在程序設計中較爲常用的編程語言。Java具備了“一次編譯,處處運行”的特點,很好的體現了其跨平臺性和麪向對象的特點,允許程序員用感性的思路來進行繁雜的編程。

Eclipse是一個基於java的開放源代碼的可擴展開發平臺,是知名的跨平臺的自由集成開發環境(IDE)Eclipse是一個基於,還捎帶了一個標準規範的插件集,包含了Java開發工具(JDK),Eclipse因爲安裝不同的插件,所以它支持不同的計算機語言,主要用來Java語言開發。

Graphics類是軟件包java.awt(其全部類都用來用戶界面的創建和圖形圖像的繪製)下的類,它同意一個應用程序繪製到組件,以及在屏幕圖像上進行繪製。Graphics 對象封裝了 Java 支持的基本呈現操作所需的狀態信息。Graphics()方法構造了一個新的 Graphics 對象, 由於 Graphics類是抽象類,因此Graphics()方法不可以被直接調用,此構造方法是圖形上下文的默認構造方法,通過在組件上調用 getGraphics() 來創建圖形上下文,或者從其他圖形上下文獲取。 

 

2.系統分析

2.1 需求和技術分析

如今的遊戲已經成爲世界上最大的娛樂休閒項目之一,遊戲市場規模持續增長,潛力巨大,我國政府一向以來都特別鼓勵遊戲產業的發展,特別是我國當地的遊戲產業,扶持力度連年加大,由此可見,我國對遊戲產業的重視程度。該坦克大戰遊戲是對紅白機經典90坦克大戰的延續,對於80後,90後來說,都是童年裏最寶貴的回憶,而80後,90後恰好佔據着當今遊戲人羣的主體,對於他們來說,該坦克大戰遊戲不僅可以減輕人們的社會壓力,放鬆身心,也可以回味小時候玩紅白機遊戲的瘋狂時光,又不會沉迷於遊戲,老少咸宜,能夠更好地體驗遊戲的樂趣。

該程序代碼有着賊高的運用率,因此,設計時必須要有相當縝密的邏輯條理思維,還要考慮一些無法操控的因素和所有可能出現的突發事件。

(1)玩家能夠通過敲擊遊戲鍵來操縱玩家坦克的動作,但對於敵方坦克來說,就要有第一定的自主性和智能型,因爲是自動運行。同時,屏幕上的敵方坦克需要開創一個線程讓其自主運行來應對數量過多而導致的混亂。要精密設置敵方坦克的操作運行算法,不要使遊戲太過單一。

(2)要對所有坦克打出的子彈進行實時監測並判斷它打到了什麼物體對象,因此需要開闢一個獨立的線程來處理子彈,還需要控制好所有的物體對象。在同一時候,在JVM虛擬機上保持運行這麼多的線程,可能會造成程序的遲鈍,甚至癱瘓。

(3)由於遊戲界面中物體對象繁多,爲了避免重疊運行,玩家坦克在前進時需要時刻地掃描周圍環境。  

(4)遊戲的動態畫面是一個優秀程序不可缺少的組成成分,精美的用戶界面是引起玩家興趣的關鍵,相關的構圖美化技術也需要有所考慮。

(5)在遊戲地圖中會有許多各種不同的物體對象,這不是繪圖方法能夠解決的,而且過多的大型photo會束縛程序的大小,所以要準確掌握Graphcis()方法的使用。同時使用讀取外部文件的方法來加載遊戲關卡,因爲內存有限,不適合用於存儲地圖關卡。

(6)遊戲要對玩家的分數進行記錄,這就需要對其功能和屬性進行妥善的策劃,還需要製作良好的解決方案來處理其存儲方式。

(7)爲了確保遊戲程序的運行順暢,需要對結構進行嚴格把控,將算法完善得更精準,還可以運用混淆器對打包後的軟件程序進行優化。

2.2 功能分析

該坦克大戰選擇使用以往的遊戲規矩。服務器端創建並設置一個主機,客戶端申請連接加入,若其IP輸入判斷無誤,載入地圖關卡並開始遊戲,在遊戲界面中,會實時顯示敵方坦克數量和玩家坦克的生命數量及分數。敵方坦克自行移動和打出子彈,玩家通過敲擊鍵盤來操控自己坦克的動作並打出子彈,子彈無法打中相同陣營的坦克,當兩方陣營的子彈相交時會相互抵消,打中對方坦克時會產生爆炸效果,中途可以暫停、發送信息,玩家坦克喫掉超級武器後會賦予其特殊的功能,在遊戲地圖界面中還同時遊戲中還包含了通信功能。如果取得了勝利,會顯示“你過關了!”,如果失敗了,則系統給出“GAME OEVR!還想再玩一次嗎?(y/n)”的提示,如果玩家雙方都選擇繼續遊戲,則遊戲重新加載並開始,不然結束並退出遊戲界面。

 

3.總體設計

3.1 總體功能

遊戲由服務器端和客戶端兩部分組成。

在服務器端,ServerModel類主要用來創建主機,ServerView類主要負責服務器端圖形界面的面板信息的設置,ServerControler類處理來自服務器視圖框架的輸入,包括創立通信與幫助信息等,enemy類主要負責敵方坦克的創建,player類主要用來設置玩家的得分及其顯示位置等信息,drawingPanel類主要負責服務器端界面窗口的創建和設置,powerUp類主要用來設置子彈屬性,例如加快速度、提升火力等,feedbackHandler類主要用來解碼從客戶端發來的指令字符串,再將其轉換成指令來判斷遊戲失敗後玩家是否繼續遊戲的問題。

在客戶端,ClientModel類主要用來設置與服務器的連接,ClientView類主要負責客戶端端圖形界面的面板信息,ClientControler類主要負責處理來自客戶端視圖框架的輸入和創立通信與幫助信息等,drawingPanel主要用來設置客戶端窗口界面,instructionHandler類主要用來解碼從服務器端發來的指令字符串,再將其轉換成指令來判斷遊戲失敗後玩家是否繼續遊戲的問題,shield類主要負責設置坦克喫掉頭盔圖標獲得保護時的狀態,normalObject類主要用來創建和描繪其他物體對象。

在服務器端和客戶端中都存在的類中,Actor類主要用來創建接口,base類主要用來創建基地並設置屬性,bullet類主要用來創建子彈並設置屬性,Ticker類主要用來創建時間信息,bomb類主要用來創建子彈打出後產生的爆炸效果,river類主要用來創建河道並設置屬性,grass類主要負責創建草坪並設置屬性,Steelwall類主要用來創建鐵牆並設置屬性,wall類主要用來創建和設置普通牆及其屬性,level類負責創建關卡。如表1,表2所示。

表1  遊戲服務器端各類功能表

ServerModel

創建主機

ServerView

設置服務器端圖形界面的面板信息

ServerControler

處理來自服務器視圖框架的輸入

enemy

創建敵方坦克

player

設置玩家的得分及其顯示位置等信息

drawingPanel

創建和設置服務器端界面窗口

powerUp

加快子彈速度並提升火力

feedbackHandler

判斷指令並執行

Actor

創建接口

base

創建並設置基地

Ticker

創建並設置時間信息

bullet

創建子彈並設置屬性

bomb

設置爆炸效果

river

創建河道並設置屬性

grass

創建草坪並設置屬性

Steelwall

創建鐵牆並設置屬性

wall

創建普通牆並設置屬性

level

創建關卡

 

表2  遊戲客戶端各類功能表

ClientModel

設置與服務器的連接

ClientView

設置客戶端端圖形界面的面板信息

ClientControler

負責處理來自客戶端視圖框架的輸入

drawingPanel

設置客戶端窗口界面

instructionHandler

判斷指令並執行

shield

設置玩家坦克防護盾

normalObject

創建並描繪其他的物體對象

level

創建關卡

base

創建並設置基地

Ticker

創建並設置時間信息

bullet

創建子彈並設置屬性

bomb

設置爆炸效果

river

創建河道並設置屬性

wall

創建普通牆並設置屬性

 

客戶端玩家輸入主機地址來完成與服務器玩家的連接,雙方通過使用指令鍵來操控自己的坦克,敵方坦克和子彈則是自主隨機運行,遊戲中會對玩家的分數進行記錄,還增加了特殊武器,另外,此遊戲還進行了小小的創新,添加了通信功能,客戶端與服務器端的連接訪問通過使用套接字Socket來實現。

其總體功能如圖1所示。

 

 

3.2 坦克大戰總體流程圖

如圖2所示。

 

4.詳細設計

4.1 面板功能設計

4.1.1 基地的設計

base類定義了幾個變量,通過構造器初始化了基地的變量參數,使用g.drawImage()方法設置一幅圖片來代表基地,通過public void move(){}來處理基地受到鐵牆防護時的變化,使用if()判斷語句判斷鐵牆的保護時間。遊戲的核心重點自然就是基地了,一旦基地被毀,則玩家失敗,遊戲結束。遊戲面板是遊戲程序的關鍵,這裏使用了方法paintComponent(Graphics g)來進行建立並設置其屬性,具體實現代碼如下:

public void draw(Graphics g){

g.drawImage(base, xPos - 12, yPos - 12, null );}

public void paintComponent(Graphics g) {

Graphics offScreenGraphics;

if (offScreenImage == null) {

offScreenImage = createImage(640, 550);

}

offScreenGraphics = offScreenImage.getGraphics();

myPaint(offScreenGraphics);

g.drawImage(offScreenImage, 0, 0, this);}

4.1.2敵方坦克的設計

enemy類設置了敵方坦克的共同屬性,並根據不同外形的坦克設置了不同的屬性,如橢圓形的坦克的移動速度會比較快,擁有多層顏色坦克的生命力與其擁有的顏色數量一樣,利用隨機函數Math.random()*4隨機生成一個隨機值,並轉換成整形數值,將此值賦給變量direction來作爲敵方坦克生成時的方向,再將Math.random()*200生成的隨機值轉換成整形數值,賦予變量interval來作爲生成時的時間間隔,並且設置了地方坦克的移動週期,在一個週期內將會朝着相同的方向繼續移動,並設置了其發射子彈的遂進行。而在特殊屬性中,分別設置了敵方坦克的的火力、速度、圖標等屬性,再用方法draw(Graphics g){}向地圖中加入敵方坦克。具體實現代碼如下:

interval = (int)(Math.random()*200);

direction = (int)(Math.random()*4);

if(type ==args1 ){

firePosibility = args2;

speed = args3;

textures = new Image[args4];}

public void draw(Graphics g){

     if(flashing && gameModel.gameFlow%10 > 4)

          g.drawImage(textures[textures.length-4+direction], xPos - size, yPos - size, null);

     else

          g.drawImage(textures[direction], xPos - size, yPos - size, null);}

4.1.3河道、草坪的設計

grass類繼承了Actor接口,通過grass類構造器定義了草坪的x,y座標和矩形邊界以及圖標,通過public void draw(Graphics g) {}方法繪製了草坪。遊戲雙方坦克及其子彈可以自由通過草坪。具體實現代碼如下:

public grass(int a, int b){

xPos = a;

yPos = b;

border = new Rectangle(0,0,0,0);

}

public void draw(Graphics g) {

g.setColor(new Color(0, 225, 0));

for(int i = yPos - 11; i <= yPos + 12; i+=5)

g.drawLine(xPos - 12, i, xPos + 12, i);

for(int i = xPos - 11; i <= xPos + 12; i+=5)

g.drawLine(i, yPos - 12, i, yPos + 12);

    g.setColor(new Color(0, 128, 0));

for(int i = yPos - 10; i <= yPos + 12; i+=5)

g.drawLine(xPos - 12, i, xPos + 12, i);

for(int i = xPos - 10; i <= xPos + 12; i+=5)

g.drawLine( i, yPos - 12, i, yPos + 12);

}

river類繼承了Actor接口,用river類構造器定義了河道的x,y座標和矩形邊界以及圖標,使用g.drawImage(Image,int,int, ImageObserver)方法設置一幅圖片來代表河道。以前各個經典版本的坦克大戰遊戲都將河道設置爲不允許坦克經過,但子彈可以自由通過,本程序爲了遵循經典,也如此設計。具體實現代碼如下:

public river(int a, int b, ServerModel gameModel){

this.gameModel = gameModel;

river = gameModel.textures[71];

xPos = a;

yPos = b;

Border = new Rectangle(xPos - 12, yPos - 12, 25, 25);}

g.drawImage(river, xPos - 12, yPos - 12, null)}

4.1.4牆與鐵牆的設計

該模塊通過new Rectangle(int x,int y,int width,int height)完成了一個矩形的創建,然後將其具體值賦給變量數組border[數組索引]生成了牆。座標x和y爲繪製矩形時的起始點,width,height分別爲矩形繪製的寬和高。通過構造器定義普通牆和鐵牆的矩形邊界和圖標。具體實現代碼如下:

generalBorder = new Rectangle(xPos - 12, yPos - 12, 25, 25);

border[0] = new Rectangle(xPos - 11, yPos - 11, 11, 11);

border[1] = new Rectangle(xPos + 1, yPos - 11, 11, 11);

border[2] = new Rectangle(xPos - 11, yPos + 1, 11, 11);

border[3] = new Rectangle(xPos + 1, yPos + 1, 11, 11);

public wall(int a, int b, int orientation, ServerModel gameModel){

xPos = a;

yPos = b;

this.gameModel = gameModel;

wall = gameModel.textures[70];

generalBorder = new Rectangle(xPos - 12, yPos - 12, 25, 25);}

4.1.5界面窗口的創建

再該模塊中,在ServerView類的構造器中用super()方法調用父類構造器設置窗口題目爲“坦克大戰”,使用JButton(String)定義了六個(退出、幫助、發送、暫停/繼續、建立主機和隱藏)鼠標點擊事件(即所謂的按鈕),JTextField定義文本框,並將其設置爲不可編輯。使用new drawingPanel()和setBackground(Color c)創建一個面板並設置背景顏色,再通過setBounds()和setLayout()方法定義了頁面的大小並將頁面佈局定義爲空。通過add()方法向頁面添加按鈕和文本框。使用setColor(Color c)方法設置面板顏色爲指定顏色,再通過繼承自java.awt.Graphics類中的drawString(String,int,int)方法向面板添加並輸出當前關數及剩餘敵人數,通過if判斷語句進行判斷,如果消滅坦克數量大於敵方坦克數量則輸出勝利場景。

4.2子彈功能設計

該模塊用setColor()方法設置子彈顏色爲淺灰色,使用g.fillRect(int,int,int,int)方法設置子彈水平或垂直髮射時的形狀,子彈和什麼東西相交通過if()判斷語句和equals()方法來鑑定,然後再處理相交時子彈和其他對象的屬性變化。具體代碼如下:

public void draw(Graphics g) {

g.setColor(Color.lightGray);

if(direction == 0 || direction == 1)

g.fillRect(border.x + 1, border.y +1, 3, 9);

if(direction == 2 || direction == 3)

g.fillRect(border.x +1, border.y + 1, 9, 3);

}

if(!border.intersects(map)){

gameModel.removeActor(this);

notifiyOwner();

makeBomb();

writeToOutputLine();

return;

if(gameModel.actors[i].getType().equals("steelWall")){

Steelwall temp =(Steelwall)gameModel.actors[i];

if(!temp.walldestoried){

temp.damageWall(border,bulletpower,direction);

if(temp.bulletdestoried)

hitTarget = true;

}

}else if(gameModel.actors[i].getType().equals("wall")){

wall temp = (wall)gameModel.actors[i];

if(!temp.walldestoried){

temp.damageWall(border,bulletpower,direction);

if(temp.bulletdestoried)

hitTarget = true;

}

}else if(gameModel.actors[i].getType().equals("bullet")){

bullet temp = (bullet)gameModel.actors[i];

if(temp.owner.getType().equals("Player")){

hitTarget = true;

gameModel.removeActor(gameModel.actors[i]);

temp.notifiyOwner();

}

}else if(gameModel.actors[i].getType().equals("Player")){

if(owner.getType().equals("enemy")){

player temp = (player)gameModel.actors[i];

    temp.hurt();

}else{

}

hitTarget = true;

}else if

(gameModel.actors[i].getType().equals("enemy") && owner.getType().equals("Player")){

enemy temp = (enemy)gameModel.actors[i];

player tempe = (player)owner;

if(temp.health == 0)

tempe.scores+=temp.type*100;

temp.hurt();

hitTarget = true;

}else if(gameModel.actors[i].getType().equals("base")){

base temp = (base)gameModel.actors[i];

temp.doom();

hitTarget = true;

gameModel.gameOver = true;

}

}

}

}

}

if(hitTarget){

gameModel.removeActor(this);

notifiyOwner();

makeBomb();

writeToOutputLine();

return;

}

4.3坦克功能設計

坦克喫掉了什麼特殊武器圖標通過if()判斷語句和equals()方法來鑑定,如果喫到TNT圖標,則已經出現了的敵方坦克全部被炸燬;如果喫到坦克圖標,玩家坦克加一條生命;如果喫到五角星圖標,則提升玩家坦克子彈火力並且速度加快,可以打破鐵牆;若是頭盔圖標,則玩家坦克獲得防護盾且免疫敵方子彈;如果喫到鐵牆圖標,則基地由普通牆變爲鐵牆,如果喫到鐘錶圖標,則時間停止,所有敵方坦克靜止。具體代碼如下:

if(gameModel.actors[i].getType().equals("powerUp")){

scores+=50;powerUp temp = (powerUp)gameModel.actors[i];

int function = temp.function;

if(function == 0){  upgrade();

}else if(function == 1){ base tempe = (base)gameModel.actors[4];tempe.steelWallTime = 600;

}else if(function == 2){  

         for(int j = 0; j < gameModel.actors.length; j++)

if(gameModel.actors[j] != null)

if(gameModel.actors[j].getType().equals("enemy")){

enemy tempe = (enemy)gameModel.actors[j];

gameModel.addActor(new bomb(tempe.xPos, tempe.yPos, "big", gameModel));

gameModel.removeActor(gameModel.actors[j]);}

level.NoOfEnemy = 0;level.deathCount = 20 - level.enemyLeft;}else if(function == 3){

InvulnerableTime = 300 + (int)Math.random()*400;

}else if(function == 4){

enemy.freezedTime = 300 + (int)Math.random()*400;

    enemy.freezedMoment = ServerModel.gameFlow;

}else if(function == 5){

if(status < 3)numberOfBullet++;

status =4;health = 2;if(type.equals("1P"))

for(int j = 0; j < 4; j ++)textures[j] = gameModel.textures[66+j];

else

for(int j = 0; j < 4; j ++)

         textures[j] = gameModel.textures[84+j];

                 }else if(function == 6){ life++;}

4.4服務器設計

4.4.1 ServerModel類

在ServerModel類,實現了ActionListener接口,具備了監聽功能。創建了一些連接變量和遊戲變量,設置了布爾類型的服務器狀態變量,使用構造器完成了消息隊列信息的設置,使用createServer(){}方法建立主機,當布爾變量serverCreated的值爲true時,主機創建成功,還設置了一個端口號,用try{}catch{}語句處理代碼執行時發生的異常,並給出錯誤提示,服務器通過accept()方法與客戶端建立連接,當端口號沒有被其他應用程序佔用並IP地址正確,則成功完成連接,載入遊戲,如若不然,就會顯示相應的錯誤提示。使用addMessage()在屏幕上顯示消息,使用removeMessage()方法刪除屏幕上的消息,通過addActor()和remove()方法完成了向地圖中增添新的物體對象和清除已經不存在了的物體對象的操作。具體代碼如下:

public void createServer(){

  addMessage("正在建立主機(端口9999)");

  try {

serverSocket = new ServerSocket(9999);

         serverCreated = true;

        } catch (Exception e) {

addMessage("無法建立主機,請確認端口9999沒有被別的程序使用");

System.out.println(e);

t.stop();

return;

        }

addMessage("建立完成,等待玩家連接");

        try {

   clientSocket = serverSocket.accept();

       clientConnected = true;

     out = new PrintWriter(clientSocket.getOutputStream(), true);

    in = new BufferedReader(new InputStreamReader(

clientSocket.getInputStream()));

    } catch (Exception e) {

addMessage("連接中出現錯誤,請重新建立主機");

serverCreated = false;

clientConnected = false;

t.stop();

try{

serverSocket.close();

clientSocket.close();

out.close();

in.close();

}catch(Exception ex){}

return;

        }

view.messageField.setEnabled(true);

addMessage("玩家已連接上,開始載入遊戲");

 out.println("L1;");

textures = new Image[88];

for(int i = 1; i < textures.length+1; i++)

textures[i-1] = Toolkit.getDefaultToolkit().getImage("image\\" + i + ".jpg");

actors = new Actor[400];

level.loadLevel(this);

P1 = new player("1P", this);

addActor(P1);

P2 = new player("2P", this);

addActor(P2);

gameStarted = true;

view.mainPanel.actors = actors;

view.mainPanel.gameStarted = true;

addMessage("載入完畢,遊戲開始了!");

}

public void removeActor(Actor actor){

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

if(actors[i] == actor){

actors[i] = null;

break;

}

}

public void addMessage(String message){

if(messageIndex < 8){

messageQueue[messageIndex] = message;

messageIndex++;

}

else{

for(int  i = 0; i < 7; i++)

messageQueue[i] = messageQueue[i+1];

messageQueue[7] = message;

}

public void removeMessage(){

if(messageIndex == 0)

return;

messageIndex--;

for(int  i = 0; i < messageIndex; i++)

messageQueue[i] = messageQueue[i+1];

messageQueue[messageIndex] = null;

if(!gameStarted)

view.mainPanel.repaint();

}

4.4.2 feedbackHandler類

feedbackHandler類從客戶端程序解碼指令字符串,然後將字符串轉換爲真正的指令。通過while(!instruction.substring(i, i+1).equals("?")){}語句來判斷其指令,並根據其指令來完成相對性的操作。

4.4.3 其他各類設計

Lever類設置了不同的關卡,通過if(1+ (currentLevel-1)%8 == num){}判斷語句來加入關卡,在進入下一關卡時,上一個關卡的所有東西都會被系統清理,並且增加了遊戲難度。同時還設置了勝利場景。

Player類通過構造器設置了玩家坦克的生命數量,生成時的方向和無敵時間,以及健康狀態,子彈數量等。通過if(type.equals( "1P")){}elae{}來判斷兩個玩家並設置其坦克的初始位置,用drawImage()方法繪製玩家坦克,當玩家敲擊開火鍵時,會用if()語句判斷是否慢如條件,若滿足就會生成一個子彈,並且子彈的位置、速度等屬性參數都會被設置好,再通過add()方法添加子彈。在坦克的下一個移動有效的前提下根據玩家坦克的移動定義玩家坦克的下一個邊界,並判斷是否與地圖邊界和其他物體對象相交,設置相交時坦克與物體對象會發生的變化情況。當玩家坦克被擊毀時,其生命減少,使用reset()方法將玩家坦克路徑重置爲空,遺棄所有座標和點類型,設置其位置爲遊戲開始時的位置。

在powerUp類中實現了對玩家坦克子彈火力的增加。

在Ticker類運用構造器建立了時間發生器,實現了runnable接口,並調用了其run()方法。

在ServerControler類處理來自服務器端視圖框架的輸入,實現了玩家消息互通功能。使用了構造器view.buttonName.addActionListener()方法完成了按鈕功能的設計。使用addKeyListener(new KeyAdapter()){}方法增加了鍵盤輸入的操作,再通過keyPressed(KeyEvent e)方法來實現,通過if(e.getKeyCode() == KeyEvent.VK_UP)語句來判斷並執行相應的方向移動操作,通過if(e.getKeyChar() == 's')判斷並執行”s”鍵的操作,if(e.getKeyCode()==e.VK_ENTER)判斷是否點擊Enter鍵,再通過if(e.getKeyChar() ==?)來判斷輸入什麼鍵並執行相應的操作。通過keyReleased(KeyEvent e)方法來釋放給定的鍵。具體代碼如下:

if(!model.gameStarted){

model.addMessage("還沒有和別的玩家聯上, 無法發送對話");

return;

}

if(!view.messageField.getText().equals("")){

model.addMessage("主機端玩家說:" + view.messageField.getText());

model.playerTypedMessage += "m" + view.messageField.getText() + ";";

view.messageField.setText("");

}else{

model.addMessage("對話內容不能爲空");

}

4.5 客戶端設計

4.5.1 ClientModel類

在ServerModel類,實現了ActionListener接口,具備了監聽功能。創建了一些連接變量和遊戲變量,設置了布爾類型的客戶端狀態變量,使用構造器完成了消息隊列信息的設置,用try{}catch{}語句處理代碼執行時發生的異常,給出錯誤提示,使用add()方法向地圖中添加對象,客戶端程序實際上不執行任何邏輯計算,它只接受指令,將指令字符串做出的反饋告訴客戶端。具體代碼如下:

public void connectServer(){

addMessage("正在連接主機");

try{

  serverIP = view.IPfield.getText();

  InetAddress addr = InetAddress.getByName(serverIP);

clientSocket = new Socket(addr, 4321);

out = new PrintWriter(clientSocket.getOutputStream(), true);

     in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));}catch(Exceptione)

{t.stop();System.out.println(e);

addMessage("連接出現錯誤,請確認1.輸入的IP是否正確 2.主機端已存在");

return;}

4.5.2 instructionHandler類

instructionHandler類只有客戶端可讀,它對從服務器程序反饋的指令字符串進行解碼,然後將字符串轉換爲真正的指令,通過while循環語句和if判斷語句來判斷指令,並執行相應的指令動作,具體實現方法如下:

if(perInstruction.substring(0,1).equals("L")){

level.loadLevel(gameModel, Integer.parseInt(perInstruction.substring(1,2)));

return;}

if(perInstruction.substring(0,1).equals("w")){for(int k = 0; k < gameModel.drawingList.length; k++){

if(gameModel.drawingList[k] !=null){if(gameModel.drawingList[k].getxPos() == xPos && gameModel.drawingList[k].getyPos() == yPos){

wall tempWall = new wall(xPos, yPos, 4, gameModel);

tempWall.shape = shape;

gameModel.drawingList[k] = tempWall;

}

}

}

if(perInstruction.substring(0,1).equals("b")){gameModel.drawingList[4] = new normalObject(260, 498,  gameModel, "base", 1);}

if(perInstruction.substring(0,1).equals("t")){

gameModel.addActor(new bullet(xPos, yPos, gameModel, direction))}

if(perInstruction.substring(0,1).equals("o")){

gameModel.addActor(new bomb(xPos, yPos, size, gameModel)); }

if(perInstruction.substring(0,1).equals("i")){

gameModel.addActor(new shield(xPos, yPos, gameModel)); }

if(perInstruction.substring(0,1).equals("a")){

if(!gameModel.gameOver){

gameModel.addMessage("GAME OVER !  想再玩一次嗎 ( y / n ) ?");

gameModel.gameOver = true;

}

}

if(perInstruction.substring(0,1).equals("x")){

int temp = Integer.parseInt(perInstruction.substring(1,2));

if(temp == 0){

if(gameModel.gamePaused){

gameModel.addMessage("主機端玩家取消了暫停");

gameModel.gamePaused = false;}

}else{if(!gameModel.gamePaused){

gameModel.addMessage("主機端玩家暫停了遊戲");

gameModel.gamePaused = true;

}

}

4.5.3 其他各類的實現

在shield類中,使用了構造器,並實現了玩家坦克喫掉頭盔圖標後獲得的防護盾的功能,通過draw(Graphics g){}方法繪製防護盾,用方法setColor(Color c)設置其顏色,drawRect()設置防護盾的x,y座標和高度、寬度,當護盾時間結束時,通過removeActor()方法去除護盾。在level類中,定義了遊戲正在玩的關數,設置了不同的關卡,通過if(1+ (levelIndex-1)%8 == num){}判斷語句來加入關卡,在進入下一關卡時,上一個關卡的所有東西都會被系統清理,並且增加了遊戲難度。此類只有一層對象,所以是一個靜態變量。normalObject類代表所有其他對象。ClientControler類功能與ServerControler相同,都是實現按鈕的功能和處理鍵盤輸入操作。

5.效果圖展示

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章