'Java小遊戲:童年經典遊戲坦克大戰是這麼實現的'

Java 坦克大戰 小遊戲 算法 坦克 FLAG BigDataKer 2019-07-21
"

一. 程序基本結構

基本結構

"

一. 程序基本結構

基本結構

Java小遊戲:童年經典遊戲坦克大戰是這麼實現的

二. 實現的功能

1、單人模式

2、雙人模式

3、通過廣度優先算法實現坦克尋路功能

三. 運行效果

主界面

"

一. 程序基本結構

基本結構

Java小遊戲:童年經典遊戲坦克大戰是這麼實現的

二. 實現的功能

1、單人模式

2、雙人模式

3、通過廣度優先算法實現坦克尋路功能

三. 運行效果

主界面

Java小遊戲:童年經典遊戲坦克大戰是這麼實現的

運行

"

一. 程序基本結構

基本結構

Java小遊戲:童年經典遊戲坦克大戰是這麼實現的

二. 實現的功能

1、單人模式

2、雙人模式

3、通過廣度優先算法實現坦克尋路功能

三. 運行效果

主界面

Java小遊戲:童年經典遊戲坦克大戰是這麼實現的

運行

Java小遊戲:童年經典遊戲坦克大戰是這麼實現的

四. 實現思路

數據存儲表示: 在JPanel繪製圖像,統一規定各個方塊的大小為同一大小(如牆壁,坦克之類,子彈除外),從而方便使用二維數組存儲地圖的各個元素。

關於檢測物體碰撞,這裡使用了一個MyImage的父類,將坦克,牆壁

定義為繼承這個父類的一個類。

class MyImage {

int width = Game.width;

int height = Game.height;

//二維地圖的座標

Coord coord;

//屏幕上的像素座標

int x;

int y;

MyImage(Coord coord) {

x = coord.x * width;

y = coord.y * height;

this.coord = coord;

}

private Rectangle getRect() {

return new Rectangle(x, y, width, height);

}

//碰撞檢測

boolean isIntersects(MyImage other) {

return other.getRect().intersects(getRect());

}

}

圖像打印則藉助遍歷兩個ConcurrentHashMap分別儲存坦克和其他類型的方塊。將這些方塊使用Map而不是使用數組是因為管理起來比較方便,而二維數組則是為了尋路算法而準備的,防止了頻繁使用上面的兩個Map而導致線程鎖的問題。

五. 遇到的問題

java的按鍵監聽在響應按鍵長按時會有1-2秒的延遲,導致操作手感極差

解決方法:在坦克類中設置一個布爾屬性move以及整形變量key儲存鍵入的按鍵值,創建一個線程來響應按鍵。

實現代碼:

//按鍵響應的線程類

class MyTankMove implements Runnable{

public void run(){

while(flag){

GetKey(key);

while(move){//決定是否移動

try {

e.printStackTrace();

Thread.sleep(100);

} catch (InterruptedException e) {

e.printStackTrace();

}

try {

Thread.sleep(10);//防止無按鍵時陷入死循環導致線程堵塞

} catch (InterruptedException e) {

}

}

}

按鍵監聽事件,即給key和move賦值

//按鍵監聽接口

private class KeyBoradListener extends KeyAdapter{

public void keyPressed(KeyEvent e){

super.keyPressed(e);

int key = e.getKeyCode();

if(key<65){//為了實現雙人對戰而設置的。。。

if(key!=KeyEvent.VK_SHIFT&&!MyTank.isEmpty()){

MyTank.getFirst().key=key;

MyTank.getFirst().move=true;

}

}

else{

if(key!=KeyEvent.VK_G&&!MyTank.isEmpty()){

switch (key){

case KeyEvent.VK_W:key = KeyEvent.VK_UP;break;

case KeyEvent.VK_A:key = KeyEvent.VK_LEFT;break;

case KeyEvent.VK_S:key = KeyEvent.VK_DOWN;break;

case KeyEvent.VK_D:key = KeyEvent.VK_RIGHT;break;

}

MyTank.getLast().key=key;

MyTank.getLast().move=true;

}

}

}

public void keyReleased(KeyEvent e){

super.keyReleased(e);

int key = e.getKeyCode();

if(key<65){

if(!MyTank.isEmpty()){

if(key!=KeyEvent.VK_SHIFT&&key==MyTank.getFirst().key){//避免了同時按兩個以上按鍵後會卡住

MyTank.getFirst().move=false;

}

else{

MyTank.getFirst().GetKey(key);

}

}

}

else{

switch (key){

case KeyEvent.VK_W:key = KeyEvent.VK_UP;break;

case KeyEvent.VK_A:key = KeyEvent.VK_LEFT;break;

case KeyEvent.VK_S:key = KeyEvent.VK_DOWN;break;

case KeyEvent.VK_D:key = KeyEvent.VK_RIGHT;break;

case KeyEvent.VK_G:key = KeyEvent.VK_SHIFT;break;

}

if(!MyTank.isEmpty()){

if(key!=KeyEvent.VK_SHIFT&&key==MyTank.getLast().key){

MyTank.getLast().move=false;

}

else{

MyTank.getLast().GetKey(key);

}

}

}

}

}

項目內的圖片資源如何在項目導出後也能使用

解決方法:假設在項目的scr文件夾中建立img文件夾,在項目的.classpath中加一句<classpathentry kind="src" path="src/img"/>(Eclipse),也可以通過設置項目的Modules,將圖像文件夾設置為resources(IDEA),並使用當前類的名.class.getResource("/(文件名)")).getImage()獲得圖像對象。

尋路的實現

實現思路:通過使用一個存儲了地圖內各個元素的二維數組Game.map,使用廣度優先算法遍歷出一條路線,將結果存放於棧之中。

實現代碼:

/**

* 使用廣度遍歷算法,使用隊列存儲遍歷的節點

*

* @return 移動的路徑

*/

private Stack<Coord> GetPath() {

Coord target = Game.tanks.get(Game.P1_TAG).coord;

Queue<Coord> d_q = new LinkedBlockingQueue<>();

ArrayList<Coord> IsMove = new ArrayList<>();

d_q.offer(coord);

IsMove.add(coord);

Coord last = null;

boolean flag;

while (!d_q.isEmpty()) {

Coord t = d_q.poll();

int tx = t.x;

int ty = t.y;

int i;

//遍歷所有的方向

for (i = 0; i < 4; ++i) {

switch (i) {

case Game.UP:

ty -= 1;

break;

case Game.LEFT:

tx -= 1;

break;

case Game.RIGHT:

tx += 1;

break;

case Game.DOWN:

ty += 1;

break;

}

//判斷該點是否可行

flag = true;

Coord z = new Coord(tx, ty);

//檢查是否為目標終點

if (z.equals(target)) {

z.per = t;

last = z;

break;

}

//檢查該座標是否已經遍歷了

for (Coord c : IsMove) {

if (c.equals(z)) {

flag = false;

break;

}

}

if (flag) {

//檢查下一格是否可以抵達

flag = !(Game.map[ty][tx] == Game.BLANK || Game.map[ty][tx] == Game.WALLS);

}

//該點可以用

if (flag) {

//將座標納入已經遍歷的隊列中

d_q.offer(z);

IsMove.add(z);

z.per = t;

last = z;

}

IsMove.add(z);

//重新選擇方向遍歷

tx = t.x;

ty = t.y;

}

//如果沒有四個方向都遍歷完就跳出,說明已經找到了終點

if (i != 4) {

break;

}

}

Stack<Coord> coords = new Stack<>();

while (null != last && last.per != null) {

coords.push(last);

last = last.per;

}

return coords;

}

關注小編,回覆坦克大戰即可獲得源碼;

本文來源:CSDN-madongyu-的博客

"

相關推薦

推薦中...