java实现坦克大战
代碼總體上來說借鑒了尚學堂“手把手教你一小時寫出坦克大戰”(感謝),也從中加入了一些自己的想法(相對來說較少),子彈碰撞后消失,添加音效,隨機生成地形等;話不多說,直接上思維導圖(比較粗略)
目錄
?編輯
窗口初始化
準備工作
窗口初始化
游戲父類的編寫
方向類
?游戲父類
添加坦克類
Tank
四個方向的移動——玩家(鍵盤監聽)、人機(隨機移動)
射擊——玩家(鍵盤監聽)、人機(隨機移動)
總?
?Player
?鍵盤監聽器
?總
?人機
總
初始化子彈類
玩家子彈
?子彈射擊?
碰撞檢測
?總
?人機子彈
?擊中玩家
?總
添加圍墻、基地
Base
Wall
Grass
Fe
優化
爆炸
音樂
重寫GamePanel
?游戲最終成品
窗口初始化
準備工作
首先創建一個TankWar項目,在scr相同路徑下創建images、music文件夾,將需要使用的圖片、音樂分別放在images、music中。創建一個com.tankwar(包),注意命名規范
窗口初始化
在com.tankwar中創建GamePanel類
import javax.swing.JFrame; public class GamePanel extends JFrame{//窗口大小private int width=1260;private int height=800;//窗口初始化public void launch() {//標題setTitle("坦克大戰");//初始化窗口大小setSize(width,height);//使屏幕居中setLocationRelativeTo(null);//添加關閉事件setDefaultCloseOperation(3);//用戶不能調整setResizable(false);//使窗口可見setVisible(true);}public static void main(String[]args) {GamePanel gamePanel=new GamePanel();gamePanel.launch();} }?運行結果
?導入窗口圖片與屏幕刷新
程序在運行時屏幕的每,對象的位置以及圖像的每一次改變都需要屏幕的一次刷新,而屏幕的每一次刷新都需要重新繪制屏幕,所以會出現閃屏現象。如果想要解決這種問題,需要運用雙緩存技術
(2條消息) Java雙緩沖技術_kkvveeerer的博客-CSDN博客_java雙緩沖
import java.awt.Graphics; import java.awt.Image; import java.awt.Toolkit;import javax.swing.JFrame; public class GamePanel extends JFrame{//窗口大小private int width=1260;private int height=800;//定義雙緩存圖片Image offScreenImage=null;//臨時變量private int a=1;//游戲狀態 0 未開始,1 開始,2 暫停,3 失敗,4 勝利private int state=0;//游戲是否開始private boolean start=false;//窗口初始化public void launch() {//標題setTitle("坦克大戰");//初始化窗口大小setSize(width,height);//使屏幕居中setLocationRelativeTo(null);//添加關閉事件setDefaultCloseOperation(3);//用戶不能調整setResizable(false);//使窗口可見setVisible(true);/** 控制屏幕刷新時間*/while(true) {repaint();try {Thread.sleep(25);//刷新休眠時間} catch (Exception e) {e.printStackTrace();// TODO: handle exception}}}public void paint(Graphics g) {//創建和容器一樣大小的imageif(offScreenImage==null) {offScreenImage=this.createImage(width,height);}//獲得該圖片的畫布Graphics gImage=offScreenImage.getGraphics();//填充整個畫布gImage.fillRect(0,0,width,height);if(state==0) {//游戲未開始gImage.drawImage(Toolkit.getDefaultToolkit().getImage("images/interface.png"),0,0,this);}else if(state==1) {//游戲開始}else if(state==2) {//游戲暫停}else if(state==3) {//游戲失敗}else if(state==4) {//游戲勝利}g.drawImage(offScreenImage,0,0,null);}public static void main(String[]args) {GamePanel gamePanel=new GamePanel();gamePanel.launch();} }?程序運行結果
?添加鼠標監聽器
在游戲中點擊“PLAYER”方可進入游戲,需要加入鼠標監聽器
import java.awt.Graphics; import java.awt.Image; import java.awt.Point; import java.awt.Toolkit; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent;import javax.swing.JFrame; public class GamePanel extends JFrame{//窗口大小private int width=1260;private int height=800;//定義雙緩存圖片Image offScreenImage=null;//臨時變量private int a=1;//游戲狀態 0 未開始,1 開始,2 暫停,3 失敗,4 勝利private int state=0;//游戲是否開始private boolean start=false;//窗口初始化public void launch() {//標題setTitle("坦克大戰");//初始化窗口大小setSize(width,height);//使屏幕居中setLocationRelativeTo(null);//添加關閉事件setDefaultCloseOperation(3);//用戶不能調整setResizable(false);//使窗口可見setVisible(true);/** 控制屏幕刷新時間*/while(true) {repaint();try {Thread.sleep(25);} catch (Exception e) {e.printStackTrace();// TODO: handle exception}}}public void paint(Graphics g) {//創建和容器一樣大小的imageif(offScreenImage==null) {offScreenImage=this.createImage(width,height);}//獲得該圖片的畫布Graphics gImage=offScreenImage.getGraphics();//填充整個畫布gImage.fillRect(0,0,width,height);if(state==0) {//游戲未開始gImage.drawImage(Toolkit.getDefaultToolkit().getImage("images/interface.png"),0,0,this);//添加鼠標事件this.addMouseListener(new GamePanel.MouseMonitor());}else if(state==1) {//游戲開始}else if(state==2) {//游戲暫停}else if(state==3) {//游戲失敗}else if(state==4) {//游戲勝利}g.drawImage(offScreenImage,0,0,null);}/** 添加鼠標監聽*/private class MouseMonitor extends MouseAdapter{@Overridepublic void mouseClicked(MouseEvent e) {Point p=new Point(e.getX(),e.getY());if(!start&&state==0) {if(p.x>450&&p.x<750&&p.y>400&&p.y<480) {//“PLAYER X,Y坐標范圍”state=1;start=true;}}else if(state==3||state==4) {}}}public static void main(String[]args) {GamePanel gamePanel=new GamePanel();gamePanel.launch();} }游戲父類的編寫
方向類
游戲中坦克需要運用到“方向”,可以單獨創建一個枚舉類,或者在坦克類中定義“方向”成員變量。
/** 首先枚舉是一個特殊的class* 這個class相當于final static 修飾,不能被繼承* 他的構造方法強制被私有化* 所有的枚舉都繼承自java.lang.Enum類。由于java不支持多繼承,所以枚舉對象不能再繼承其他類*/ public enum Direction {//每個成員變量都是final static 修飾UP,LEFT,RIGHT,DOWN }?游戲父類
游戲中的坦克、子彈、基地、墻體、爆炸圖片等元素,在繪畫到面板上的過程中,需要運用到坐標,大小、移動速度、主界面畫板。將其抽取出來,創建游戲父類
import java.awt.Graphics; import java.awt.Image; import java.awt.Rectangle; import java.awt.Toolkit;public abstract class GameObject {//游戲元素圖片Image img;//游戲元素的橫縱坐標int x;int y;//游戲元素的寬,高int width;int height;//游戲元素的移動速度int speed;//游戲元素的移動方向Direction direction;//引入主界面GamePanel gamePanel;public GameObject() {}public GameObject(String img,int x,int y,GamePanel gamePanel) {this.img=Toolkit.getDefaultToolkit().getImage(img);this.x=x;this.y=y;this.gamePanel=gamePanel;}public Image getImag() {return img;}public void setImg(String img) {this.img=Toolkit.getDefaultToolkit().getImage(img);}public int getX() {return x;} public void setX(int x) {this.x=x;}public int getY() {return y;}public void setY(int y) {this.y = y;}public int getWidth() {return width;}public void setWidth(int width) {this.width = width;}public int getHeight() {return height;}public void setHeight(int height) {this.height = height;}public double getSpeed() {return speed;}public void setSpeed(int speed) {this.speed = speed;}public Direction getDirection() {return direction;}public void setDirection(Direction direction) {this.direction = direction;}public GamePanel getGamePanel() {return gamePanel;}public void setGamePanel(GamePanel gamepanel) {this.gamePanel = gamePanel;}//繼承元素繪制自己的方法public abstract void paintSelf(Graphics g);//獲取當前游戲元素的矩形,是為碰撞檢測而寫public abstract Rectangle getRec(); }添加坦克類
Tank
注:藍色字體的寫在子類中
坦克具有哪些特有屬性?
四個方向移動的圖片
//向上移動時的圖片private String upImage;//向下移動時的圖片private String downImage;//向右移動時的圖片private String rightImage;//向左移動時的圖片private String leftImage;四個方向的移動——玩家(鍵盤監聽)、人機(隨機移動)
1、墻體碰撞檢測
2、邊界碰撞檢測
3、人機碰撞檢測
4、移動
1、墻體碰撞檢測
/** 坦克與墻碰撞檢測*/public boolean hitWall(int x,int y) {//假設玩家坦克前進,下一個位置形成的矩形Rectangle next=new Rectangle(x,y,width,height);//地圖里所有的墻體List<Wall>walls=this.gamePanel.wallList;List<Fe>fes=this.gamePanel.feList;//判斷兩個矩形是否相交for(Wall w:walls) {if(w.getRec().intersects(next)) {return true;}}for(Fe f:fes) {if(f.getRec().intersects(next)) {return true;}}return false;}2、邊界碰撞檢測
/** 邊界與坦克碰撞檢測*/public boolean moveToBorder(int x,int y) {if(x<10) {return true;}else if(x>this.gamePanel.getWidth()-width) {return true;}if(y<30) {return true;}else if(y>this.gamePanel.getHeight()-height) {return true;}return false;}?3、人機碰撞檢測
/** 人機碰撞檢測*/public boolean hitTank(int x,int y) {int a=0;//假設人機坦克前進,下一個位置形成的矩形Rectangle next=new Rectangle(x,y,width,height);//地圖里所有的人機List<Bot>bots=this.gamePanel.botList;//判斷兩個矩形是否相交for(Bot b:bots) {if(b.getRec().intersects(next)) {a++;if(a==2) {return true;}}}return false;}?4、移動
/** 坦克移動*/public void leftWard() {direction=Direction.LEFT;setImg(leftImage);if(!hitWall(x-speed,y)&&!moveToBorder(x-speed,y)&&alive&&!hitTank(x-speed,y)) {this.x-=speed;}}public void rightWard() {direction=Direction.RIGHT;setImg(rightImage);if(!hitWall(x+speed,y)&&!moveToBorder(x+speed,y)&&alive&&!hitTank(x+speed,y)) {this.x+=speed;}}public void upWard() {direction=Direction.UP;setImg(upImage);if(!hitWall(x,y-speed)&&!moveToBorder(x,y-speed)&&alive&&!hitTank(x,y-speed)) {this.y-=speed;}}public void downWard() {direction=Direction.DOWN;setImg(downImage);if(!hitWall(x,y+speed)&&!moveToBorder(x,y+speed)&&alive&&!hitTank(x-speed,y+speed)) {this.y+=speed;}}射擊——玩家(鍵盤監聽)、人機(隨機移動)
1、子彈射擊方向應與坦克移動方向一致
2、射擊子彈CD
3、射擊
?1、子彈射擊方向應與坦克移動方向一致
坦克坐標點為坦克圖片左上角,所以子彈初始坐標應該為坦克的坐標加上坦克高度或寬度的一半。
/** 根據方向確定頭部位置,x和y是左上角的點*/public Point getHeadPoint() {switch(direction) {case UP:return new Point(x+width/2,y);case LEFT:return new Point(x,y+height/2);case DOWN:return new Point(x+width/2,y+height);case RIGHT:return new Point(x+width,y+height/2);default:return null;}}?2、射擊子彈CD
/** 坦克射擊cd*/public class AttackCD extends Thread{public void run() {attackCoolDown=false;try {//休眠1秒Thread.sleep(attackCoolDownTime);//attackCoolDownTime為定義的成員變量單位為ms}catch (InterruptedException e) {e.printStackTrace();}//將攻擊功能解除冷卻狀態attackCoolDown=true;this.stop();//不是很理解}}?3、射擊
/** 射擊*/public void attack() {Point p=getHeadPoint();if(attackCoolDown&&alive) {Bullet bullet=new Bullet("images/bullet/bulletGreen.gif",p.x-10,p.y-10, direction, this.gamePanel);this.gamePanel.bulletList.add(bullet);//將子彈添加至子彈集合attackCoolDown=false;new AttackCD().start();}}總?
這里由于還未創建其他類所以會報錯,在后續會添加上的(博主偷個懶直接把源碼粘貼過來了)
import java.awt.Graphics; import java.awt.Point; import java.awt.Rectangle; import java.util.List;public class Tank extends GameObject{//向上移動時的圖片private String upImage;//向下移動時的圖片private String downImage;//向右移動時的圖片private String rightImage;//向左移動時的圖片private String leftImage;//坦克sizeint width=54;int height=54;//坦克初始方向Direction direction=Direction.UP;//坦克速度private int speed=3;//攻擊冷卻private boolean attackCoolDown=true;//攻擊冷卻事件毫秒間隔1000ms發射子彈private int attackCoolDownTime=100;//坦克是否活著public boolean alive=true;/** 坦克坐標,方向,圖片,方向,面板*/public Tank(String img,int x,int y,String upImage,String downImage,String leftImage,String rightImage,GamePanel gamePanel) {super(img,x,y,gamePanel);this.upImage=upImage;this.leftImage=leftImage;this.downImage=downImage;this.rightImage=rightImage; }/** 坦克移動*/public void leftWard() {direction=Direction.LEFT;setImg(leftImage);if(!hitWall(x-speed,y)&&!moveToBorder(x-speed,y)&&alive&&!hitTank(x-speed,y)) {this.x-=speed;}}public void rightWard() {direction=Direction.RIGHT;setImg(rightImage);if(!hitWall(x+speed,y)&&!moveToBorder(x+speed,y)&&alive&&!hitTank(x+speed,y)) {this.x+=speed;}}public void upWard() {direction=Direction.UP;setImg(upImage);if(!hitWall(x,y-speed)&&!moveToBorder(x,y-speed)&&alive&&!hitTank(x,y-speed)) {this.y-=speed;}}public void downWard() {direction=Direction.DOWN;setImg(downImage);if(!hitWall(x,y+speed)&&!moveToBorder(x,y+speed)&&alive&&!hitTank(x-speed,y+speed)) {this.y+=speed;}}/** 射擊*/public void attack() {Point p=getHeadPoint();if(attackCoolDown&&alive) {Bullet bullet=new Bullet("images/bullet/bulletGreen.gif",p.x-10,p.y-10, direction, this.gamePanel);this.gamePanel.bulletList.add(bullet);//將子彈添加至子彈集合attackCoolDown=false;new AttackCD().start();}}/** 坦克射擊cd*/public class AttackCD extends Thread{public void run() {attackCoolDown=false;try {//休眠1秒Thread.sleep(attackCoolDownTime);}catch (InterruptedException e) {e.printStackTrace();}//將攻擊功能解除冷卻狀態attackCoolDown=true;this.stop();//不是很理解}}/** 根據方向確定頭部位置,x和y是左上角的點*/public Point getHeadPoint() {switch(direction) {case UP:return new Point(x+width/2,y);case LEFT:return new Point(x,y+height/2);case DOWN:return new Point(x+width/2,y+height);case RIGHT:return new Point(x+width,y+height/2);default:return null;}}/** 坦克與墻碰撞檢測*/public boolean hitWall(int x,int y) {//假設玩家坦克前進,下一個位置形成的矩形Rectangle next=new Rectangle(x,y,width,height);//地圖里所有的墻體List<Wall>walls=this.gamePanel.wallList;List<Fe>fes=this.gamePanel.feList;//判斷兩個矩形是否相交for(Wall w:walls) {if(w.getRec().intersects(next)) {return true;}}for(Fe f:fes) {if(f.getRec().intersects(next)) {return true;}}return false;}/** 人機碰撞檢測*/public boolean hitTank(int x,int y) {int a=0;//假設人機坦克前進,下一個位置形成的矩形Rectangle next=new Rectangle(x,y,width,height);//地圖里所有的人機List<Bot>bots=this.gamePanel.botList;//判斷兩個矩形是否相交for(Bot b:bots) {if(b.getRec().intersects(next)) {a++;if(a==2) {return true;}}}return false;}/** 邊界與坦克碰撞檢測*/public boolean moveToBorder(int x,int y) {if(x<10) {return true;}else if(x>this.gamePanel.getWidth()-width) {return true;}if(y<30) {return true;}else if(y>this.gamePanel.getHeight()-height) {return true;}return false;}@Overridepublic Rectangle getRec(){return new Rectangle(x,y,width,height);}@Overridepublic void paintSelf(Graphics g) {g.drawImage(img, x, y, null);} }?Player
玩家類繼承坦克類,在父類的基礎上只需要添加鍵盤監聽器即可
?鍵盤監聽器
/** 按下鍵盤時坦克持續運動*/public void keyPressed(KeyEvent e) {int key=e.getKeyCode();switch(key) {case KeyEvent.VK_A:left=true;Music.playBackground();break;case KeyEvent.VK_D:right=true;Music.playBackground();break;case KeyEvent.VK_W:up=true;Music.playBackground();break;case KeyEvent.VK_S:down=true;Music.playBackground();break;case KeyEvent.VK_SPACE:Music.attackPlay();this.attack();break;default:break;} }/** 松開鍵盤時,坦克停止運動*/public void keyReleased(KeyEvent e) {int key = e.getKeyCode();switch (key){case KeyEvent.VK_A:left = false;Music.moveStop();break;case KeyEvent.VK_S:down = false;Music.moveStop();break;case KeyEvent.VK_D:right = false;Music.moveStop();break;case KeyEvent.VK_W:up = false;Music.moveStop();break;default:break;} }?總
import java.awt.Graphics; import java.awt.Rectangle; import java.awt.event.KeyEvent;public class PlayerOne extends Tank{private boolean up=false;private boolean down=false;private boolean left=false;private boolean right=false;public PlayerOne(String img, int x, int y, String upImage, String downImage, String leftImage, String rightImage,GamePanel gamePanel) {super(img, x, y, upImage, downImage, leftImage, rightImage, gamePanel);// TODO Auto-generated constructor stub}/** 按下鍵盤時坦克持續運動*/public void keyPressed(KeyEvent e) {int key=e.getKeyCode();switch(key) {case KeyEvent.VK_A:left=true;Music.playBackground();break;case KeyEvent.VK_D:right=true;Music.playBackground();break;case KeyEvent.VK_W:up=true;Music.playBackground();break;case KeyEvent.VK_S:down=true;Music.playBackground();break;case KeyEvent.VK_SPACE:Music.attackPlay();this.attack();break;default:break;} }/** 松開鍵盤時,坦克停止運動*/public void keyReleased(KeyEvent e) {int key = e.getKeyCode();switch (key){case KeyEvent.VK_A:left = false;Music.moveStop();break;case KeyEvent.VK_S:down = false;Music.moveStop();break;case KeyEvent.VK_D:right = false;Music.moveStop();break;case KeyEvent.VK_W:up = false;Music.moveStop();break;default:break;} }/** 坦克移動*/public void move() {if(left) {leftWard();}else if(right) {rightWard();}else if (up) {upWard();}else if (down) {downWard();}else {return;}}@Overridepublic void paintSelf(Graphics g) {g.drawImage(img,x,y,null);move();}public Rectangle getRec() {return new Rectangle(x,y,width,height);}}?人機
人機具有哪些屬性呢?
隨機、隨機、隨機還是隨機!
1、隨機移動?
2、隨機射擊
1、隨機移動?
/** 人機移動*/public void go() {attack();if(moveTime>=20) {direction=randomDirection();moveTime=0;}else{moveTime+=1;}switch(direction) {case UP:upWard();break;case DOWN:downWard();break;case RIGHT:rightWard();break;case LEFT:leftWard();break;}}/** 人機移動隨機方向*/public Direction randomDirection() {Random r=new Random();int rnum=r.nextInt(4);switch(rnum) {case 0:return Direction.UP;case 1:return Direction.RIGHT;case 2:return Direction.LEFT;default:return Direction.DOWN;}}2、隨機射擊
隨機射擊寫在人機子彈類里
總
import java.awt.Graphics; import java.awt.Point; import java.awt.Rectangle; import java.util.Random;public class Bot extends Tank{//人機朝一個方向運動時間int moveTime=0;public Bot(String img, int x, int y, String upImage, String downImage, String leftImage, String rightImage,GamePanel gamePanel) {super(img, x, y, upImage, downImage, leftImage, rightImage, gamePanel);} /** 人機移動*/public void go() {attack();if(moveTime>=20) {direction=randomDirection();moveTime=0;}else{moveTime+=1;}switch(direction) {case UP:upWard();break;case DOWN:downWard();break;case RIGHT:rightWard();break;case LEFT:leftWard();break;}}/** 人機移動隨機方向*/public Direction randomDirection() {Random r=new Random();int rnum=r.nextInt(4);switch(rnum) {case 0:return Direction.UP;case 1:return Direction.RIGHT;case 2:return Direction.LEFT;default:return Direction.DOWN;}}/** 隨機攻擊*/public void attack() {Point p=getHeadPoint();Random r=new Random();int rnum=r.nextInt(100);if(rnum<2) {EnemyBullet enemyBullet=new EnemyBullet("images/bullet/bulletYellow.gif",p.x,p.y,direction,gamePanel);this.gamePanel.enemyBulletsList.add(enemyBullet);}}/** 繪制人機*/@Overridepublic void paintSelf(Graphics g) {g.drawImage(img,x,y,null);go();}@Overridepublic Rectangle getRec() {return new Rectangle(x,y,width,height);}}初始化子彈類
玩家子彈
?子彈射擊?
/** 子彈運動方向*/public void go() {switch(direction) {case UP:upWard();break;case DOWN:downWard();break;case LEFT:leftWard();break;case RIGHT:rightWard();break;}} /** 子彈運動坐標改變*/private void rightWard() {// TODO Auto-generated method stubx+=speed;}private void downWard() {// TODO Auto-generated method stuby+=speed;}private void leftWard() {// TODO Auto-generated method stubx-=speed;}private void upWard() {// TODO Auto-generated method stuby-=speed;}
碰撞檢測
子彈與土墻
子彈與鐵墻
子彈與基地
子彈與邊界
子彈與子彈
?1、子彈與土墻
/** 子彈和土墻碰撞*/public void hitWall() {Rectangle next=this.getRec();List<Wall>walls=this.gamePanel.wallList;for(Wall w:walls) {if(w.getRec().intersects(next)) {Music.wallPlay();this.gamePanel.wallList.remove(w);this.gamePanel.removeList.add(this);break;}}}?2、子彈與鐵墻
/** 子彈與Fe*/public void hitFe() {Rectangle next=this.getRec();List<Fe>fes=this.gamePanel.feList;for(Fe f:fes) {if(f.getRec().intersects(next)) {Music.wallPlay();this.gamePanel.removeList.add(this);break;}}}?3、子彈與基地
/** 擊中基地*/public void hitBase() {Rectangle next=this.getRec();for(Base base:gamePanel.baseList) {if(base.getRec().intersects(next)) {this.gamePanel.baseList.remove(base);this.gamePanel.removeList.add(this);this.gamePanel.state=3;break;}}}?4、子彈與邊界
/** 移動到邊界*/public void moveToBorder() {if(x<0||x>this.gamePanel.getWidth()) {this.gamePanel.removeList.add(this);}if(y<0||y>this.gamePanel.getHeight()) {this.gamePanel.removeList.add(this);}}?5、子彈與子彈
/** 子彈與子彈碰撞檢測*/public void hitEnemyBullet() {Rectangle next=this.getRec();List<EnemyBullet>enemyBullets=this.gamePanel.enemyBulletsList;for(EnemyBullet enemyBullet:enemyBullets) {if(enemyBullet.getRec().intersects(next)) {Music.wallPlay();this.gamePanel.removeList2.add(enemyBullet);this.gamePanel.removeList.add(this);break;}}}?總
import java.awt.Graphics; import java.awt.Rectangle; import java.util.List;public class Bullet extends GameObject{//長寬private int width=10;private int height=10;//速度private int speed=7;//方向Direction direction;//初始化子彈public Bullet(String img,int x,int y,Direction direction,GamePanel gamePanel) {super(img,x,y,gamePanel);this.direction=direction; }/** 子彈運動方向*/public void go() {switch(direction) {case UP:upWard();break;case DOWN:downWard();break;case LEFT:leftWard();break;case RIGHT:rightWard();break;}}/** 子彈運動坐標改變*/private void rightWard() {// TODO Auto-generated method stubx+=speed;}private void downWard() {// TODO Auto-generated method stuby+=speed;}private void leftWard() {// TODO Auto-generated method stubx-=speed;}private void upWard() {// TODO Auto-generated method stuby-=speed;}/** 子彈與坦克碰撞檢測*/public void hitBot() {//矩形類Rectangle next=this.getRec();List<Bot>bots=this.gamePanel.botList;//子彈和人機for(Bot bot:bots) {if(bot.getRec().intersects(next)) {Explode[]arr=new Explode[7];for(int i=0;i<7;i++) {Explode explode=new Explode("images/explode/"+(i+1)+".gif", x, y, this.gamePanel);this.gamePanel.explodeList.add(explode);}Music.explodePlay();this.gamePanel.botList.remove(bot);this.gamePanel.removeList.add(this);break;}}}/** 子彈與子彈碰撞檢測*/public void hitEnemyBullet() {Rectangle next=this.getRec();List<EnemyBullet>enemyBullets=this.gamePanel.enemyBulletsList;for(EnemyBullet enemyBullet:enemyBullets) {if(enemyBullet.getRec().intersects(next)) {Music.wallPlay();this.gamePanel.removeList2.add(enemyBullet);this.gamePanel.removeList.add(this);break;}}}/** 子彈和土墻碰撞*/public void hitWall() {Rectangle next=this.getRec();List<Wall>walls=this.gamePanel.wallList;for(Wall w:walls) {if(w.getRec().intersects(next)) {Music.wallPlay();this.gamePanel.wallList.remove(w);this.gamePanel.removeList.add(this);break;}}}/** 子彈與Fe*/public void hitFe() {Rectangle next=this.getRec();List<Fe>fes=this.gamePanel.feList;for(Fe f:fes) {if(f.getRec().intersects(next)) {Music.wallPlay();this.gamePanel.removeList.add(this);break;}}}/** 移動到邊界*/public void moveToBorder() {if(x<0||x>this.gamePanel.getWidth()) {this.gamePanel.removeList.add(this);}if(y<0||y>this.gamePanel.getHeight()) {this.gamePanel.removeList.add(this);}}/** 擊中基地*/public void hitBase() {Rectangle next=this.getRec();for(Base base:gamePanel.baseList) {if(base.getRec().intersects(next)) {this.gamePanel.baseList.remove(base);this.gamePanel.removeList.add(this);this.gamePanel.state=3;break;}}}@Overridepublic void paintSelf(Graphics g) {// TODO Auto-generated method stubg.drawImage(img,x,y,null);go();//碰撞檢測hitBot();hitWall();hitBase();hitFe();hitEnemyBullet();}@Overridepublic Rectangle getRec() {return new Rectangle(x,y,width,height);}}?人機子彈
人機與玩家的子彈有什么差別呢??
?擊中玩家
/** 擊中玩家*/public void hitPlayer() {Rectangle next=this.getRec();List<Tank>tanks=this.gamePanel.tankList;//子彈和坦克for(Tank tank:tanks) {if(tank.getRec().intersects(next)) {tank.alive=false;this.gamePanel.tankList.remove(tank);this.gamePanel.removeList.add(this);break;}}}?總
import java.awt.Graphics; import java.awt.Rectangle; import java.util.List; /** 人機子彈*/ public class EnemyBullet extends Bullet{public EnemyBullet(String img, int x, int y, Direction direction, GamePanel gamePanel) {super(img, x, y, direction, gamePanel);}public void hitPlayer() {//攻擊到玩家,玩家死亡Rectangle next=this.getRec();List<Tank>tanks=this.gamePanel.tankList;//子彈和坦克for(Tank tank:tanks) {if(tank.getRec().intersects(next)) {tank.alive=false;this.gamePanel.tankList.remove(tank);this.gamePanel.removeList.add(this);break;}}}@Overridepublic void hitBase() {//攻擊到基地,游戲結束Rectangle next=this.getRec();for(Base base:gamePanel.baseList) {if(base.getRec().intersects(next)) {this.gamePanel.baseList.remove(base);this.gamePanel.removeList2.add(this);this.gamePanel.state=3;break;}}}public void hitWall() {//攻擊到土墻,子彈與土均消失Rectangle next=this.getRec();List<Wall>walls=this.gamePanel.wallList;for(Wall w:walls) {if(w.getRec().intersects(next)) {this.gamePanel.wallList.remove(w);this.gamePanel.removeList2.add(this);break;}}}public void hitFe() {//攻擊到鐵墻,墻不變,子彈消失Rectangle next=this.getRec();List<Fe>fes=this.gamePanel.feList;for(Fe f:fes) {if(f.getRec().intersects(next)) {this.gamePanel.removeList2.add(this);break;}}}public void paintSelf(Graphics g) {g.drawImage(img,x,y,null);go();hitBase();hitWall();hitFe();hitPlayer();} }添加圍墻、基地
剩下的就是間的添加圍墻、基地等對象了。
Base
import java.awt.Graphics; import java.awt.Rectangle;public class Base extends GameObject{public int width=60;public int height=60;public Base(String img,int x,int y,GamePanel gamePanel) {super(img,x,y,gamePanel);}@Overridepublic void paintSelf(Graphics g) {g.drawImage(img,x,y,null);// TODO Auto-generated method stub}@Overridepublic Rectangle getRec() {return new Rectangle(x,y,width,height);} }Wall
import java.awt.Graphics; import java.awt.Rectangle;public class Wall extends GameObject{private int width=60;private int height=60;public Wall(String img,int x,int y,GamePanel gamePanel) {super(img,x,y,gamePanel);}@Overridepublic void paintSelf(Graphics g) {g.drawImage(img,x,y,null);}@Overridepublic Rectangle getRec() { return new Rectangle(x,y,width,height);} }Grass
import java.awt.Graphics; import java.awt.Rectangle;public class Grass extends GameObject{public Grass(String img,int x,int y,GamePanel gamePanel) {super(img,x,y,gamePanel);}@Overridepublic void paintSelf(Graphics g) {g.drawImage(img,x,y,null);}@Overridepublic Rectangle getRec() {return null;}}Fe
import java.awt.Graphics; import java.awt.Rectangle;public class Fe extends GameObject{private int width=60;private int height=60;public Fe(String img,int x,int y,GamePanel gamePanel) {super(img,x,y,gamePanel);}@Overridepublic void paintSelf(Graphics g) {g.drawImage(img,x,y,null);}@Overridepublic Rectangle getRec() {return new Rectangle(x,y,width,height);}}優化
爆炸
import java.awt.Graphics; import java.awt.Rectangle;public class Explode extends GameObject{public Explode(String img,int x,int y,GamePanel gamePanel) {super(img,x,y,gamePanel);}@Overridepublic void paintSelf(Graphics g) {g.drawImage(img,x-25,y-30,null);//x,y為圖片左上角的坐標,調整圖片位置,使圖片居中}@Overridepublic Rectangle getRec() {// TODO Auto-generated method stubreturn null;} }音樂
import java.io.File;import javax.sound.sampled.AudioInputStream; import javax.sound.sampled.AudioSystem; import javax.sound.sampled.Clip;public class Music{private static Clip start;//剛進入游戲的音樂private static Clip move;//玩家移動音樂private static Clip attack;//玩家射擊音樂private static Clip explode;//爆炸音效private static Clip wall;//擊中墻體音效static {File bgMusicStartFile = new File("D:\\JAVA\\eclipse\\TankWar\\musics\\bgm.wav");File bgMusicAttackFile = new File("D:\\JAVA\\eclipse\\TankWar\\musics\\attack.wav");File bgMusicMoveFile = new File("D:\\JAVA\\eclipse\\TankWar\\musics\\move.wav");File bgMusicExplodeFile = new File("D:\\JAVA\\eclipse\\TankWar\\musics\\explode.wav");File bgMusicWallFile = new File("D:\\JAVA\\eclipse\\TankWar\\musics\\wall.wav");try {AudioInputStream audioInputStreamStart = AudioSystem.getAudioInputStream(bgMusicStartFile);start = AudioSystem.getClip();start.open(audioInputStreamStart);AudioInputStream audioInputStreamAttack = AudioSystem.getAudioInputStream(bgMusicAttackFile);attack = AudioSystem.getClip();attack.open(audioInputStreamAttack);AudioInputStream audioInputStreamStartMove = AudioSystem.getAudioInputStream(bgMusicMoveFile);move = AudioSystem.getClip();move.open(audioInputStreamStartMove);AudioInputStream audioInputStreamStartExplode = AudioSystem.getAudioInputStream(bgMusicExplodeFile);explode = AudioSystem.getClip();explode.open(audioInputStreamStartExplode); AudioInputStream audioInputStreamStartWall = AudioSystem.getAudioInputStream(bgMusicWallFile);wall = AudioSystem.getClip();wall.open(audioInputStreamStartWall); } catch (Exception e) {e.printStackTrace();}}public static void playBackground(){//循環播放move.setFramePosition(0);move.loop(Clip.LOOP_CONTINUOUSLY); }public static void startPlay(){start.start();start.setFramePosition(0);}public static void attackPlay(){attack.start();//將進度條調為0attack.setFramePosition(0);}public static void movePlay(){move.start();move.setFramePosition(0);}public static void moveStop(){move.stop();}public static void explodePlay(){explode.start();explode.setFramePosition(0);}public static void wallPlay() {wall.start();wall.setFramePosition(0);} }重寫GamePanel
import java.awt.Graphics; import java.awt.Image; import java.awt.Point; import java.awt.Toolkit; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.util.ArrayList; import java.util.List; import java.util.Random;import javax.swing.JFrame;public class GamePanel extends JFrame{boolean one=true;boolean run=true;//關卡private int level=1;//定義雙緩存圖片Image offScreenImage=null;/** //游戲狀態* 0 未開始,1 單人模式,* 2 游戲暫停,3 游戲失敗,4 游戲勝利*/public int state =0;//游戲是否開始private boolean start=false;//臨時變量private int a=1;//窗口長寬private int width=1260;private int height=800;//指針初始縱坐標private int y=260;//基地private Base base=new Base("images/base.gif",660,740,this);//重繪次數public int count=0;//敵人數量private int enemyCount=0;///隨機生成的墻體數量private int wallCount=100;private boolean d=true;private int[]xrr=new int[wallCount];private int[]yrr=new int[wallCount];//物體集合public List<Bullet>bulletList=new ArrayList<>();public List<Tank>tankList=new ArrayList<>();public List<Bot>botList=new ArrayList<>();public List<Bullet>removeList=new ArrayList<>();public List<Wall>wallList=new ArrayList<>();public List<Grass>grassList=new ArrayList<>();public List<Fe>feList=new ArrayList<>();public List<Base> baseList = new ArrayList<>();public List<EnemyBullet>enemyBulletsList=new ArrayList<>();public List<EnemyBullet>removeList2=new ArrayList<>();public List<Explode>explodeList=new ArrayList<>();//玩家private PlayerOne playerOne = new PlayerOne("images/player1/p1tankU.gif", 500, 700,"images/player1/p1tankU.gif","images/player1/p1tankD.gif","images/player1/p1tankL.gif","images/player1/p1tankR.gif", this);public void random() {Random r=new Random(); for(int i=0;i<wallCount;) {int x=r.nextInt(20);int y=r.nextInt(8)+3;if(i>0) {boolean repeat=false;for(int j=0;j<i;j++) {if(xrr[j]==x*60&&yrr[j]==y*60) {repeat=true;}}if(!repeat) {xrr[i]=x*60;yrr[i]=y*60;i++;}else {continue;}}else {xrr[i]=x*60;yrr[i]=y*60;i++;}}}/** 重置*/public void reset() {count=0;enemyCount=0;playerOne = new PlayerOne("images/player1/p1tankU.gif", 500, 700,"images/player1/p1tankU.gif","images/player1/p1tankD.gif","images/player1/p1tankL.gif","images/player1/p1tankR.gif", this);feList.clear();bulletList.clear();tankList.clear();botList.clear();removeList.clear();wallList.clear();grassList.clear();baseList.clear();enemyBulletsList.clear();removeList2.clear();explodeList.clear();}/** 添加墻,基地*/public void add() {random();//添加圍墻for(int i=0;i<21;i++) {wallList.add(new Wall("images/walls.gif",i*60,120,this));}wallList.add(new Wall("images/walls.gif",600,740,this));wallList.add(new Wall("images/walls.gif",600,680,this));wallList.add(new Wall("images/walls.gif",660,680,this));wallList.add(new Wall("images/walls.gif",720,680,this));wallList.add(new Wall("images/walls.gif",720,740,this));for(int i=0;i<wallCount;i++) {Random a=new Random();int num=a.nextInt(4);if(num<2) {Wall wall=new Wall("images/walls.gif",xrr[i], yrr[i], null);wallList.add(wall);}else if(num<3){Grass g=new Grass("images/cao.gif",xrr[i], yrr[i], null);grassList.add(g);}else {Fe f=new Fe("images/fe.gif",xrr[i], yrr[i], null);feList.add(f);}}//添加基地baseList.add(base);}/** 窗口的啟動方法*/public void launch() {//標題setTitle("坦克大戰無盡版");//窗口初始化大小setSize(width,height);//使屏幕居中setLocationRelativeTo(null);//添加關閉事件setDefaultCloseOperation(3);//用戶不能調整大小setResizable(false);//使窗口可見setVisible(true);//初始化基地圍墻;add();//添加鍵盤事件this.addKeyListener(new GamePanel.KeyMonitor());while(true) {if(botList.size()==0&&enemyCount==10) {state=4;}if(tankList.size()==0&&(state==1)) {state=3;}if(state==1) {if(count%50==1&&enemyCount<10) {boolean a=true;Random r=new Random();int rnum=r.nextInt(19)+1;if(enemyCount>0) {for(Bot b:botList) {if(Math.abs(rnum*60-b.getX())<60) {a=false;}}if(a) {botList.add(new Bot("images/enemy/enemy1U.gif", rnum*60, 60,"images/enemy/enemy1U.gif","images/enemy/enemy1D.gif","images/enemy/enemy1L.gif","images/enemy/enemy1R.gif", this));enemyCount++;}}else {botList.add(new Bot("images/enemy/enemy1U.gif", rnum*60, 60,"images/enemy/enemy1U.gif","images/enemy/enemy1D.gif","images/enemy/enemy1L.gif","images/enemy/enemy1R.gif", this));enemyCount++;}}if(count%2==1) {if(!explodeList.isEmpty()) {explodeList.remove(0);}}}if(run) {repaint();}try {Thread.sleep(25);}catch (Exception e) {e.printStackTrace();// TODO: handle exception}}}@Overridepublic void paint(Graphics g) {//創建和容器一樣大小的Image圖片if(offScreenImage==null) {offScreenImage=this.createImage(width,height);}//獲得該圖片的畫布Graphics gImage=offScreenImage.getGraphics();//填充整個畫布gImage.fillRect(0,0,width,height);if(state==0) {//添加圖片gImage.drawImage(Toolkit.getDefaultToolkit().getImage("images/interface.png"),0,0,this);//添加鼠標事件this.addMouseListener(new GamePanel.MouseMonitor());}else if(state==1) {//paint重繪游戲元素for(Tank player:tankList) {player.paintSelf(gImage);}for(Bullet bullet:bulletList) {bullet.paintSelf(gImage);}bulletList.removeAll(removeList);for(EnemyBullet enemyBullet:enemyBulletsList) {enemyBullet.paintSelf(gImage);}enemyBulletsList.removeAll(removeList2);for(Explode explode:explodeList) {explode.paintSelf(gImage);}for(Bot bot:botList) {bot.paintSelf(gImage);}for(Wall wall:wallList) {wall.paintSelf(gImage);}for(Fe fe:feList) {fe.paintSelf(gImage);}for(Grass grass:grassList) {grass.paintSelf(gImage);}for(Base base:baseList) {base.paintSelf(gImage);}//重繪次數+1count++;}else if(state==2) {}else if(state==3) {gImage.drawImage(Toolkit.getDefaultToolkit().getImage("images/shibai.png"),315,200,this);//添加鼠標事件this.addMouseListener(new GamePanel.MouseMonitor());}else if(state==4) {gImage.drawImage(Toolkit.getDefaultToolkit().getImage("images/win.png"),(width-322)/2,(height-84)/2,this);this.addMouseListener(new GamePanel.MouseMonitor());}//將緩沖區繪制好的圖形整個繪制到容器的畫布中g.drawImage(offScreenImage,0,0,null);}/** 添加鍵盤監聽*/private class KeyMonitor extends KeyAdapter{@Overridepublic void keyPressed(KeyEvent e) {int key=e.getKeyCode();switch(key) {case KeyEvent.VK_ENTER:if(!start) {tankList.add(playerOne);//將坦克添加至坦克集合state=a;start=true;}break;case KeyEvent.VK_P:if(state!=2) {a=state;state=2;run=false;}else {state=a;run=true;if(a==0) {a=1;}}break; default:playerOne.keyPressed(e);break;}}@Overridepublic void keyReleased(KeyEvent e) {playerOne.keyReleased(e);}}//添加鼠標監聽private class MouseMonitor extends MouseAdapter{@Overridepublic void mouseClicked(MouseEvent e) {Point p=new Point(e.getX(),e.getY());if(!start&&state==0) {if(p.x>450&&p.x<750&&p.y>400&&p.y<480) {tankList.add(playerOne);state=1;start=true;Music.startPlay();}}else if(state==3||state==4) {reset();start=false;state=0;add();}}} public static void main(String[]args) {GamePanel gamePanel=new GamePanel();gamePanel.launch();} }?游戲最終成品
?
?
?
總結
以上是生活随笔為你收集整理的java实现坦克大战的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: CPU缓存侧信道攻击
- 下一篇: ps制作2寸照片教程蓝底,ps怎么p二寸