游戲說明:
玩家可以操縱自己的坦克,通過發射子彈擊毀敵機,敵機用同樣的方式擊毀玩家的坦克。
基於java版的坦克大戰實現思路:
1.0:游戲界面設計
--游戲的界面采用JPanel 游戲的主要活動區在這個JPanel上進行
--游戲的界面素材采用java代碼的paint方法繪制坦克 炸彈效果導入外部圖片素材
首先常見一個JPanel,繪制出坦克和子彈,主意,坦克的繪制必須確定一個基准點,此后坦克的位置依賴與此坐標。
因此,現在需要一個MyPanel類來承載游戲的界面可視化區域。該類繼承自JPanel類。
MyPanel類的paint()方法可以很有效的繪制出坦克和子彈,注意到repaint()方法可以很方便的執行paint()方法,游戲的核心就是讓顯示器不停的刷新當前頁面。通過repaint()很方便能做到這點。
而讓MyPanel是很有必要的,游戲開始之后,我們讓repaint()可以自動的運行,而不是通過響應某種事件。
現在,有了坦克和子彈之后,下一步就是讓JFrame能監聽到玩家按下空格鍵,這個很容易可以實現,當監聽到玩家的事件之后,監視器馬上執行發射子彈行為。這個行為是由坦克自身發出的,並且考慮到所有的坦克都有發射子彈的功能,為此,需要先寫我們的Tank類。這個類是敵人坦克和我方坦克共有的,其余兩者均繼承自(Class) Tank類。
這個類的設計思路如下
該類定義的坦克的初始速度,方向,子彈的速度,並且具有發射子彈的功能。代碼如下:
public class Tank {
int positionX; //坦克的初始位置x
int positionY; //坦克的初始位置y
int direct; //坦克的方向
int speed; //坦克速度
int bulletSpeed=10; //子彈速度
public int getPositionX() {
return positionX;
}
public void setPositionX(int positionX) {
this.positionX = positionX;
}
public int getPositionY() {
return positionY;
}
public void setPositionY(int positionY) {
this.positionY = positionY;
}
public int getDirect() {
return direct;
}
public void setDirect(int direct) {
this.direct = direct;
}
public int getSpeed() {
return speed;
}
public void setSpeed(int speed) {
this.speed = speed;
}
//坦克上移
public void moveUp()
{
}
//坦克向右
public void moveRight(){
}
//坦克下移
public void moveDown(){
}
//坦克左移
public void moveLeft(){
}
//坦克射擊子彈行為
public void shout()
{
}
注意到shout這個方法,在用戶按下空格鍵之后,通過監視器調用而發射子彈,但注意,子彈發射出去之后便不再受控制,為此,需要將每一個子彈都做成一個線程。出於這個緣故,並且考慮到子彈仍舊有屬於自己的特性,比如速度、方向、初始位置等,需要將子彈單獨做成一個類,這個類實現Runnable接口(為了后面產生其他武器,這里通過接口實現線程而不是繼承而來)。當一個子彈杯創建之后,應當馬上啟動子彈的線程。
現在可以讓我方的子彈在按下空格之后實現發射一個子彈,下一步是讓玩家可以通過上下左右鍵控制坦克的方向。當玩家敲下相應的鍵之后,監視器馬上調用繼承自Tank的MTank(我方坦克)。這點很容易就試下,代碼類似地:
//坦克上移
public void moveUp()
{
if(this.positionY>0) //保證用戶不出界
this.positionY-=this.speed;
}
下面的任務是讓敵人也可以發射子彈,注意,敵人的子彈是不受玩家控制的,並且要求敵人子彈不能連發,也就是說,敵人的一個子彈在死亡之前,是不容許在產生新的子彈的,為了讓敵人自動發射子彈,我們改變思路,找一個容器來存放敵人的子彈,在paint里面,通過遍歷容器里面的子彈來模擬自動發射,注意:一旦程序執行,paint總是在不停的調用,因為JPanel已經是個線程,在它的run()函數中,用while循環來保證paint永遠運轉。
考慮到線程的安全問題,采用Vector 向量來存放子彈,
Vector<Bullet> bullets=new Vector<Bullet>();
注意,每輛坦克都有自己的子彈容器,它是Tank類的一個屬性。下一步,讓坦克動起來,理所當然地,將敵方坦克做成一個線程,該線程讓坦克自動運行,類似地在線程run中這樣做:
while(true){
try{
Thread.sleep(30);
}
catch(Exception e){
}
this.aotoMove();
}
到目前為止:我方的坦克可以通過控制自由移動並發射子彈,敵人的坦克也實現了自由移動並自動發射子彈。
下面要做的就是,當我方坦克擊中敵人坦克之后,敵人坦克消失,反之亦然。
實現這一切比想象中的還要容易,只需要在paint中加入碰撞檢測。
hitTest()函數將提供檢測機制。當我方的坦克發射的子彈落在敵人坦克所在的區域,我們應該讓敵方的坦克消失。
為了統一並實現該要求,需要定義一個Vector存放這個游戲中所有的敵方坦克,這樣在paint繪制的時候,只需要讀取Vector向量來動態的產生坦克。
下面,開始具體碰撞檢測:
注意:
一旦檢測到我方的坦克的子彈落在敵方坦克的區域,執行某操作,產生擊毀效果。
一旦檢測道敵方坦克的子彈落在我方坦克的區域,執行某操作,產生擊毀效果。
一旦檢測到子彈飛出游戲區域,執行某操作,從向量中移除該子彈
一旦檢測到敵人的坦克互相碰撞或者遇到牆壁,執行某操作,改變方向
碰撞檢測的過程必須要注意的是,由於碰撞檢測放在paint類,執行速度過快,在檢測完畢改變方向之后,一定要有一個延遲,不能馬上判斷,否則會出現“無頭坦克”,到處亂撞。
解決的方法有:在坦克移動的時候,用for循環+Thread.sleep來控制坦克在一次移動中必須走完指定的路線。
2:在改變方向后,有一個小小的延遲,保證在此期間,坦克有一個微小的掙脫力來掙脫碰撞帶來的困擾。
最后,在增加游戲開始的畫面:新建一個JPanel,當游戲開始的時候顯示這個界面,通過times%2的方法讓這個界面的字符串有個閃的過程。
將MyPanel的創建放到一個合適的邏輯中。而不是一開始就。當執行MyPanel的時候,記得先移除新建的JPanel。
截止目前:游戲的基本功能已經完結。V_1.0
