java實現飛機大戰案例詳解

前言

飛機大戰是一個非常經典的案例,因為它包含瞭多種新手需要掌握的概念,是一個非常契合面向對象思想的入門練習案例

程序分析:

在此遊戲中共有六個對象:
小敵機Airplane,大敵機BigAirplane,小蜜蜂Bee,天空Sky,英雄機Hero,子彈Bullet

其次我們還需要三個類:

超類Flyer,圖片類Images,測試類World

還需:

英雄機2張,小敵機,大敵機,小蜜蜂,子彈,天空各1張,爆炸圖4張,遊戲開始,暫停,遊戲結束各1張,共14張圖片放入與圖片類Images同包中

超類Flyer:

此類是用來封裝所有對象共有的行為及屬性的
不管是寫什麼程序,都建議遵循兩點:數據私有化,行為公開化

import java.util.Random;
import java.awt.image.BufferedImage;

public abstract class Flyer {
 //所有對象都有三種狀態:活著的,死瞭的,及刪除的
 //這裡之所以選擇用常量表示狀態是因為首先狀態是一個不需要去修改的值
 //其次狀態需要反復使用所以結合這兩個特點,我選擇瞭使用常量表示
 //state是用來表示當前狀態的,每個對象都有一個實時的狀態,此狀態是會改變的,且初始狀態都是活著的
 public static final int LIVE = 0;//活著的
 public static final int DEAD = 1;//死瞭的
 public static final int REMOVE = 2;//刪除的
 protected int state = LIVE;//當前狀態(默認狀態為活著的)

 每個對象都是一張圖片,既然是圖片那麼就一定有寬高,其次因為每個對象都是會隨時移動的 即為都有x,y坐標
 protected int width;//寬
 protected int height;//高
 protected int x;//左右移動(x坐標)
 protected int y;//上下移動(y坐標)

 /**
 * 飛行物移動(抽象)
 * 每個飛行物都是會移動的,但是移動方式不同
 * 所以這裡就將共有的行為抽到瞭超類中
 * 但是設置成瞭抽象方法,實現瞭多態的效果
 */
 public abstract void step();

 /**
 * 獲取圖片(抽象)
 * 所有對象都是圖片但圖片不相同所以抽象化瞭
 */
 public abstract BufferedImage getImage();

 /**
 * 判斷對象是否是活著的
 */
 public boolean isLive(){
 return state == LIVE;
 }
 /**
 * 判斷對象是否是死瞭的
 */
 public boolean isDead(){
 return state == DEAD;
 }
 /**
 * 判斷對象是否刪除瞭
 */
 public boolean isRemove(){
 return state == REMOVE;
 }

 /**
 * 判斷對象(大敵機,小敵機,小蜜蜂)是否越界
 * 當敵人越界我們就需要刪除它否則程序越執行越卡,會出現內存泄露的問題,此方法就是為後續刪除越界對象做鋪墊的
 * @return
 */
 public boolean isOutOfBounds(){
 return y >= World.HEIGHT;
 }
 /**
 * 給小/大敵機,小蜜蜂提供的
 * 因為三種飛行物的寬,高不同所以不能寫死。
 * 若三種飛行物的寬,高相同,那麼就可以將寬,高寫死
 */
 public Flyer(int width,int height){
 Random rand = new Random();
 this.width = width;
 this.height = height;
 x = rand.nextInt(World.WIDTH-width);//x:0到負的width長度的之間的隨機數
 y = -height;//y:負的height高度
 }

 /**
 * 給天空,子彈,英雄機提供的
 * 因為英雄機,子彈,天空的寬,高,x,y都是不同的,所以數據不能寫死,需要傳參
 */
 public Flyer(int width,int height,int x,int y){
 this.width = width;
 this.height = height;
 this.x = x;
 this.y = y;
 }

 /**
 *檢測碰撞
 * this:敵人(小敵機/小蜜蜂/大敵機)
 * other:子彈/英雄機
 *@return
 */
 public boolean isHit(Flyer other){
 int x1 = this.x - other.width;//x1:敵人的x-英雄機/子彈的寬
 int x2 = this.x + this.width;//x2:敵人的x加上敵人的寬
 int y1 = this.y - other.height;//y1:敵人的y-英雄機/子彈的高
 int y2 = this.y + this.height;//y2:敵人的y加上敵人的高
 int x = other.x;//x:英雄機/子彈的x
 int y = other.y;//y:英雄機/子彈的y
 /*
 x在x1與x2之間 並且 y在y1與y2之間,即為撞上瞭
 */
 return x>x1 && x<=x2 && y>=y1 && y<=y2;
 }

 /**
 * 飛行物死亡
 */
 public void goDead(){
 state = DEAD;//將當前狀態修改為死瞭的
 }
}

圖片工具類Images:

此類用來獲取每個對象對應的圖片

import java.awt.image.BufferedImage;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
/**
 * 圖片工具類
 */
public class Images {
// 公開的 靜態的 圖片數據類型 變量名
 /**
 * 對象圖片
 */
 public static BufferedImage sky;//天空
 public static BufferedImage bullet;//子彈
 public static BufferedImage[] heros;//英雄機
 public static BufferedImage[] airs;//小敵機
 public static BufferedImage[] bairs;//大敵機
 public static BufferedImage[] bees;//小蜜蜂

 /**
 * 狀態圖片
 */
 public static BufferedImage start;//啟動狀態圖
 public static BufferedImage pause;//暫停狀態圖
 public static BufferedImage gameover;//遊戲結束狀態圖

 static {//初始化靜態圖片
 sky = readImage("background01.png");//天空
 bullet = readImage("bullet.png");//子彈
 heros = new BufferedImage[2];//英雄機圖片數組
 heros[0] = readImage("hero0.png");//英雄機圖片1
 heros[1] = readImage("hero1.png");//英雄機圖片2
 airs = new BufferedImage[5];//小敵機圖片數組
 bairs = new BufferedImage[5];//大敵機圖片數組
 bees = new BufferedImage[5];//小蜜蜂圖片數組
 airs[0] = readImage("airplane.png");//小敵機圖片讀取
 bairs[0] = readImage("bigairplane.png");//大敵機圖片讀取
 bees[0] = readImage("bee01.png");//小蜜蜂圖片讀取

 /**爆炸圖迭代讀取*/
 for (int i=1;i<5;i++){//遍歷/迭代賦值
 airs[i] = readImage("bom"+i+".png");//小敵機圖片數組其餘元素賦值爆炸圖
 bairs[i] = readImage("bom"+i+".png");//大敵機圖片數組其餘元素賦值爆炸圖
 bees[i] = readImage("bom"+i+".png");//小蜜蜂圖片數組其餘元素賦值爆炸圖
 }
 start = readImage("start.png");//啟動狀態圖
 pause = readImage("pause.png");//暫停狀態圖
 gameover = readImage("gameover.png");//遊戲結束狀態圖
 }

 /**
 * 讀取圖片
 * 此處的fileName:圖片文件名
 *
 * try.....catch:異常的一種處理方法
 */
 public static BufferedImage readImage(String fileName){
 try{
 BufferedImage img = ImageIO.read(Flyer.class.getResource(fileName)); //讀取與Flyer在同一個包中的圖片
 return img;
 }catch(Exception e){
 e.printStackTrace();
 throw new RuntimeException();
 }
 }
}

世界窗口類/測試類 World:

此類用來集合所有類進行排序及具體的操作,和程序的最終運行

import javax.swing.JFrame;
import javax.swing.JPanel;
import java.awt.Graphics;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.nio.Buffer;
//定時器
import java.util.Timer;
//定時器任務
import java.util.TimerTask;
//打開隨機類
import java.util.Random;
//擴容類
import java.util.Arrays;
/**
 * 世界測試類(整個遊戲窗口)
 */
public class World extends JPanel{
 public static final int WIDTH = 400;//窗口寬
 public static final int HEIGHT = 700;//窗口高

 public static final int START = 0;//啟動狀態
 public static final int RUNNING = 1;//運行狀態
 public static final int PAUSE = 2;//暫停狀態
 public static final int GAME_OVER = 3;//遊戲結束狀態
 private int state = START;//當前狀態默認是啟動狀態

 /**
 * 聲明每個類具體的對象
 * 如下為:窗口中所看到的對象
 */
 private Sky s = new Sky();//天空對象
 private Hero h = new Hero();//英雄機對象
 private Flyer[] enemies ={};//敵人對象,分別是大敵機,小敵機,小蜜蜂所以寫成瞭數組
 private Bullet[] bt ={};//子彈也是有很多的所以寫成瞭數組

 /**
 * 生成敵人對象(小敵機,大敵機,小蜜蜂)
 */
 public Flyer nextOne(){
 Random rand = new Random();
 int type = rand.nextInt(20);//0-19之間的隨機數
 if (type < 5){//當隨機數小於5
 return new Bee();//返回小蜜蜂
 }else if (type < 13){//當隨機數小於13
 return new Airplane();//返回小敵機
 }else{//大於十三則
 return new BigAirplane();//返回大敵機
 }
 }

 private int enterIndex = 0;
 /**
 * 敵人(大敵機,小敵機,小蜜蜂)入場
 */
 public void enterAction() {//每10毫秒走一次
 enterIndex++;
 if (enterIndex%40 == 0 ){//四百毫秒走一次
 Flyer fl = nextOne();//獲取敵人對象
 enemies = Arrays.copyOf(enemies,enemies.length+1);//擴容(每產生一個敵人數組就擴容1)
 enemies[enemies.length-1] = fl;//將生成的敵人fl放置enemies數組的末尾
 }
 }

 int shootIndex = 0;
 /**
 * 子彈入場
 */
 public void shootAction(){//10毫秒走一次
 shootIndex++;
 if (shootIndex%30 == 0){//每300毫秒走一次
 Bullet[] bs = h.shoot();//獲取子彈數組對象
 bt = Arrays.copyOf(bt,bt.length+bs.length);//擴容子彈數組(每入場一個子彈就加一個元素)
 System.arraycopy(bs,0,bt,bt.length-bs.length,bs.length);//數組的追加
 }
 }

 /**
 * 讓除去英雄機外的所有對象(小敵機,大敵機,小蜜蜂,子彈,天空)移動
 */
 public void setpAction() {//每10毫秒走一次
 s.step();//天空移動
 for (int i=0;i<enemies.length;i++) {//遍歷所有敵人
 enemies[i].step();//敵人移動
 }
 for (int i=0;i<bt.length;i++){//遍歷所有子彈
 bt[i].step();//子彈移動
 }
 }

 /**
 * 重寫outOfBoundsAction(方法)
 */
 public void outOfBoundsAction() {//每10毫秒走一次
 for (int i=0;i<enemies.length;i++){//遍歷所有敵人
 if (enemies[i].isOutOfBounds() || enemies[i].isRemove()){
 enemies[i] = enemies[enemies.length-1];//最後一個敵人和越界敵人替換
 enemies = Arrays.copyOf(enemies,enemies.length-1);//縮容
 }
 }
 for (int i=0;i<bt.length;i++){//迭代所有子彈
 if (bt[i].isOutOfBounds() || bt[i].isRemove()){
 bt[i] = bt[bt.length-1];//用最後一個子彈替換出界的子彈
 bt = Arrays.copyOf(bt,bt.length-1);//縮容
 }
 }
 }
 private int score = 0;//玩傢的得分
 /**
 * 子彈與敵人的碰撞
 */
 public void bulletBangAction() {//每10毫秒走一次
 for (int i=0;i<bt.length;i++){//遍歷所有子彈
 Bullet b = bt[i];//獲取每一個子彈
 for (int j=0;j<enemies.length;j++){//迭代每一個敵人
 Flyer f = enemies[j];//獲取每一個敵人
 if (b.isLive() && f.isLive() && f.isHit(b)){//若子彈活著的,敵人活著的,並且兩個對象相撞
  b.goDead();//子彈當前狀態修改為死亡
  f.goDead();//敵人當前狀態修改為死亡
  if (f instanceof EnemyScore) {//判斷死亡的敵人類型能否強轉為得分接口類型
  EnemyScore es = (EnemyScore) f;//將死亡敵人向下造型
  score += es.getScore();//調用具體的敵人對象的得分接口的getScore()加分方法
  }
  if (f instanceof EnemyAward){//判斷死亡的敵人類型能否強轉為獎勵值接口類型
  EnemyAward ea = (EnemyAward) f;//將死亡敵人強轉為獎勵值接口類型
  int type = ea.getAwardType();//將具體的獎勵值賦值給type
  switch (type){
  case EnemyAward.FIRE://火力值
  h.addFier();//返回增加火力值
  break;
  case EnemyAward.LIFE://生命值
  h.addLife();//返回增加生命值
  break;
  }
  }
 }
 }
 }
 }

 /**
 * 英雄機與敵人的碰撞
 */
 private void heroBangAction() {//每10毫秒走一次
 for (int i=0;i<enemies.length;i++){//迭代所有敵人
 Flyer f = enemies[i];//獲取每個敵人
 if (f.isLive() && h.isLive() && f.isHit(h)){//判斷碰撞
 f.goDead();//敵人死亡
 h.subtractLife();//英雄機減生命值
 h.clearFier();//英雄機清空火力值
 }
 }
 }

 /**
 * 檢測遊戲結束
 */
 private void checkGameOverAction() {//每10毫秒走一次
 if (h.getLife() <= 0) {//若英雄機生命值為0或小於0
 state = GAME_OVER;//將狀態修改為GAME_OVER遊戲結束狀態
 }
 }
 /**
 * 啟動程序的執行
 */
 public void action() {//測試代碼
 MouseAdapter m = new MouseAdapter() {
 /**
 * 重寫mouseMoved()鼠標移動事件
 * @param e
 */
 @Override
 public void mouseMoved(MouseEvent e) {
 if (state == RUNNING){//僅在運行狀態下執行
  int x = e.getX();//獲取鼠標的x坐標
  int y = e.getY();//獲取鼠標的y坐標
  h.moveTo(x,y);//接收鼠標具體坐標
 }
 }

 /**
 * 重寫mouseClicked() 鼠標點擊事件
 * @param e
 */
 public void mouseClicked(MouseEvent e){
 switch (state){//根據當前狀態做不同的處理
  case START://啟動狀態時
  state = RUNNING;//鼠標點擊後改成運行狀態
  break;
  case GAME_OVER://遊戲結束狀態時
  /*清理戰場(將所有數據初始化)*/
  score = 0;//總分歸零
  s = new Sky();//天空初始化所有屬性
  h = new Hero();//英雄機初始化所有屬性
  enemies = new Flyer[0];//敵人初始化所有屬性
  bt = new Bullet[0];//子彈初始化所有屬性
  
  state = START;//鼠標點擊後修改為啟動狀態
  break;
 }
 }

 /**
 * 鼠標移出窗口事件
 * @param e
 */
 public void mouseExited(MouseEvent e){
  if (state == RUNNING){//若狀態為運行
  state = PAUSE;//則將當前狀態修改為暫停
  }
 }

 /**
 * 鼠標的進入窗口事件
 * @param e
 */
 public void mouseEntered(MouseEvent e){
 if (state == PAUSE){//若當前狀態為暫停
  state = RUNNING;//則將當前狀態修改為運行
 }
 }
 };
 this.addMouseListener(m);
 this.addMouseMotionListener(m);
 Timer timer = new Timer();//定時器對象
 int interval = 10;//定時的間隔(此間隔是以毫秒為單位)
 timer.schedule(new TimerTask() {
 @Override
 public void run() {//定時幹的事(每10毫秒自動執行此方法當中的所有方法)
 if (state == RUNNING){//隻在運行狀態下執行
  enterAction();//敵人(大敵機,小敵機,小蜜蜂)入場
  shootAction();//子彈入場
  setpAction();//飛行物移動
  outOfBoundsAction();//刪除越界的敵人
  bulletBangAction();//子彈與敵人的碰撞
  heroBangAction();//英雄機與敵人的碰撞
  checkGameOverAction();//檢測遊戲結束
 }
 repaint();//重新調用paint()方法(重畫)
 }
 }, interval, interval);//定時計劃表
 }

 /**
 * 重寫paint方法,在窗口中畫圖片
 * @param g:畫筆
 */
 public void paint(Graphics g){//每10毫秒走一次
 g.drawImage(s.getImage(), s.x, s.y, null);//畫天空
 g.drawImage(s.getImage(), s.x, s.getY1(), null);//畫第二張天空
 g.drawImage(h.getImage(),h.x,h.y,null);//畫英雄機
 for (int i=0;i<enemies.length;i++){//遍歷所有敵人
 Flyer f = enemies[i];//獲取每一個敵人
 g.drawImage(f.getImage(),f.x,f.y,null);//畫敵人
 }
 for (int i = 0; i<bt.length; i++){//遍歷所有子彈
 Bullet b = bt[i];//獲取所有子彈
 g.drawImage(b.getImage(),b.x,b.y,null);//畫子彈
 }
 g.drawString("SCORE:"+score,10,25);//在窗口右上角畫分數
 g.drawString("HP:"+h.getLife(),10,45);//在窗口右上角畫出英雄機的生命值
 switch (state){//畫狀態圖
 case START:
 g.drawImage(Images.start,0,0,null);//啟動狀態圖
 break;
 case PAUSE:
 g.drawImage(Images.pause,0,0,null);//暫停圖
 break;
 case GAME_OVER:
 g.drawImage(Images.gameover,0,0,null);//遊戲結束圖
 break;
 }
 }

 /**
 * 主執行方法
 * @param args
 */
 public static void main(String[] args) {
 JFrame frame = new JFrame();
 World world = new World();
 frame.add(world);
 frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
 frame.setSize(WIDTH,HEIGHT);
 frame.setLocationRelativeTo(null);
 frame.setVisible(true);//1)設置窗口可見 2)盡快調用paint()方法

 world.action();//啟動程序的執行
 }
}
/**
 * 1.問:為什麼要將引用設計再main方法的外面?
 * 答:因為若將引用設計在main中,則引用隻能在main中使用,其他方法都不能訪問,
 * 為瞭能在其他方法中也能訪問這些引用,所以將引用設計在main外
 *
 * 2.問:為什麼要單獨創建action方法來測試?
 * 答:因為main方法時static的,在main方法中是無法訪問引用的,
 * 所以需要單獨創建非static的方法來測試
 *
 * 3.問:為什麼在main中要先創建world對象,然後再調用action()方法?
 * 答:因為main方法是static的,再main中是無法調用action()方法的
 * 所以要先創建world對象,然後再調用action()方法
 */

小敵機類Airplane:

此類存儲小敵機特有的屬性及行為:
移動速度,分值,及圖片的切換
繼承超類,且實現得分接口

package cn.tedu.shoot;

import java.awt.image.BufferedImage;

/**
 * 小敵機
 */
public class Airplane extends Flyer implements EnemyScore{
 // 移動速度
 private int speed;

 public Airplane(){
 super(66,89);
 speed = 2;//小敵機的下落速度
 }
 /**重寫step方法(移動)*/
 public void step(){
 y += speed;//y+表示向下
 }
 int index = 1;
 /**
 * 重寫getImage()獲取對象圖片
 * @return
 */
 public BufferedImage getImage() {
 if (isLive()){//若活著 則返回airs[0]圖片
 return Images.airs[0];
 }else if (isDead()){//若死瞭 則返回airs[1~4]圖片
 BufferedImage img = Images.airs[index++];//獲取爆破圖
 if (index == Images.airs.length){//若index到瞭5 則表示到瞭最後一張
 state = REMOVE;//將當前狀態修改為REMOVE刪除的
 }
 return img;//返回爆炸圖
 /*
 index = 1
 10M isLive返回true 則 return返回airs[0]圖片
 20M isLive返回false 則 執行isDead返回true img = airs[1] index = 2  返回airs[1]圖片
 30M isLive返回false 則 執行isDead返回true img = airs[2] index = 3  返回airs[2]圖片
 40M isLive返回false 則 執行isDead返回true img = airs[3] index = 4  返回airs[3]圖片
 50M isLive返回false 則 執行isDead返回true img = airs[4] index = 5 state修改為REMOVE 返回airs[4]圖片
 60M isLive返回false 則 執行isDead返回false return返回null空值(不返回圖片)
 */
 }
 return null;
 }

 /**
 * 重寫getScore()方法
 * @return:分值
 */
 public int getScore(){
 return 1;
 }
}

大敵機類BigAirplane:

大敵機與小敵機幾乎無差別
同樣要繼承超類,且實現得分接口

package cn.tedu.shoot;

import java.awt.image.BufferedImage;
import java.util.Random;

/**
 * 大敵機
 */
public class BigAirplane extends Flyer implements EnemyScore{
// 移動速度
 private int speed;

 public BigAirplane(){//初始化默認屬性
 super(203,211);//圖片寬,高
 speed = 2;//移動速度
 }

 /**重寫step方法(移動)*/
 public void step(){
 y += speed;//y+表示直線向下移動
 }

 int index = 1;
 @Override
 public BufferedImage getImage() {
 if (isLive()){//若活著 則返回airs[0]圖片
 return Images.bairs[0];
 }else if (isDead()){//若死瞭 則返回airs[1~4]圖片
 BufferedImage img = Images.bairs[index++];//獲取爆破圖
 if (index == Images.bairs.length){//若index到瞭5 則表示到瞭最後一張
 state = REMOVE;//將當前狀態修改為REMOVE刪除的
 }
 return img;
 }
 return null;
 }

 /**
 * 重寫getScore()方法
 * @return:分值
 */
 public int getScore(){
 return 3;
 }
}

小蜜蜂類Bee:

此類雖也可以算作敵人類,但是與小/大敵機有所不同,它是實現獎勵值接口

package cn.tedu.shoot;

import java.awt.image.BufferedImage;
import java.util.Random;

/**
 * 小蜜蜂
 */
public class Bee extends Flyer implements EnemyAward{
 // x坐標移動速度,y坐標移動速度,
 private int xSpeed;//x坐標移動速度
 private int ySpeed;//y坐標移動速度
 private int awardType;//獎勵類型

 public Bee(){//初始化屬性
 super(48,50);//圖片寬,高
 Random rand = new Random();
 awardType = rand.nextInt(2);//隨機獎勵值類型0~2之間(不包括2)0表示火力值,1表示生命值
 xSpeed = 1;//平行移動
 ySpeed = 2;//垂直移動
 }
 /**重寫step方法(移動)*/
 public void step() {
 y += ySpeed;//y+:向下移動
 x += xSpeed;//x+:隨機向左或是向右移動
 if (x <= 0 || x >= World.WIDTH - width) {
 xSpeed *= -1;//到達邊界後反方向移動(正負為負,負負為正)
 }
 }

 int index = 1;
 public BufferedImage getImage() {
 if (isLive()){//若活著 則返回airs[0]圖片
 return Images.bees[0];//返回小蜜蜂圖
 }else if (isDead()){//若死瞭 則返回airs[1~4]圖片
 BufferedImage img = Images.bees[index++];//獲取爆破圖
 if (index == Images.bees.length){//若index到瞭5 則表示到瞭最後一張
 state = REMOVE;//將當前狀態修改為REMOVE刪除的
 }
 return img;//返回爆炸圖
 }
 return null;
 }

 /**
 * 重寫getAwardType()方法
 * @return
 */
 public int getAwardType(){
 return awardType;//返回獎勵類型
 }
}

天空類Sky:

這裡有一點需要強調,就是為瞭實現天空圖片向下移動後會出現移動過的位置出現圖片丟失的情況,就使用瞭兩張圖上下拼接起來,當第某張天空圖完全移出窗口的時候會讓它重新出現在窗口上方繼續向下移動

package cn.tedu.shoot;

import java.awt.image.BufferedImage;

/**
 * 天空
 */
public class Sky extends Flyer{
 // 移動速度,y1
 private int y1;//第二張圖片的y坐標
 private int speed;//移動速度

 public Sky(){//設置初始值(默認值)
 //此處的寬高用常量是因為天空的寬高和窗口是一致的,x軸和y軸為若不為0就和窗口不匹配瞭
 super(World.WIDTH,World.HEIGHT,0,0);//初始化圖片坐標及寬,高
 speed = 1;//初始化移動速度
 y1 = -World.HEIGHT;//第二張圖片設置在第一張圖片上方
 }
 /**重寫step方法(移動)*/
 public void step(){
 y += speed;//第一張圖向下移動
 y1 += speed;//第二張圖向下移動
 if (y >= World.HEIGHT){//若y>=窗口的高
 y = -World.HEIGHT;//將移動出去的第一張天空挪到窗口上方
 }
 if (y1 >= World.HEIGHT){//若第二張天空挪出窗口
 y1 = -World.HEIGHT;//將第二張天空挪到窗口上方
 }
 }
 /**重寫getImage()獲取對象圖片*/
 @Override
 public BufferedImage getImage() {//10毫秒走一次
 return Images.sky;//返回天空圖片即可
 }

 /**
 * 獲取y1坐標
 */
 public int getY1(){
 return y1;//返回y1
 }
}

英雄機類Hero:

package cn.tedu.shoot;

import java.awt.image.BufferedImage;
/**
 * 英雄機
 */
public class Hero extends Flyer {
 // 命數,火力值
 private int life;//命數
 private int fire;//火力

 /**
 * 初始化英雄機坐標機具體數據
 */
 public Hero() {
 super(97,139,140,400);//寬,高,及初始坐標
 fire = 0;//初始火力值 0:單倍火力
 life = 3;//初始生命值
 }
 /**重寫step方法(移動)*/
 public void step(){//每10毫秒走一次
 //因為英雄機是跟隨鼠標移動的,而鼠標是在窗口上的所以這裡就沒有寫具體的方法,而是在窗口類中去用鼠標的具體坐標計算出英雄機的移動位置
 }

 int index = 0;//下標
 /**重寫getImage()獲取對象圖片*/
 @Override
 public BufferedImage getImage() {//每10毫秒走一次
 return Images.heros[index++ % Images.heros.length];//heros[0]和heros[1]來回切換
 /*過程
  index = 0
 10M 返回heros[0] index = 1
 20M 返回heros[1] index = 2
 30M 返回heros[0] index = 3
 40M 返回heros[1] index = 4
 50M 返回heros[0] index = 5
 60M 返回heros[1] index = 6
 ...........
 */
 }
 /**
 * 英雄機發射子彈(生成子彈對象)
 */
 public Bullet[] shoot(){
 int xStep = this.width/4;//子彈x坐標
 int yStep = 5;//子彈y坐標
 System.out.println(this.x+"\t"+this.y);
 if (fire>0){//雙倍火力
 Bullet[] bs = new Bullet[3];//2發子彈
 bs[0] = new Bullet(this.x+1*xStep,this.y-yStep);//子彈坐標1
 bs[1] = new Bullet(this.x+3*xStep,this.y-yStep);//子彈坐標2
 bs[2] = new Bullet(this.x+2*xStep,this.y-yStep);
 fire -= 2;//發射一次雙倍活力,則火力值-2
 return bs;
 } else {//單倍火力
 Bullet[] bs = new Bullet[1];//1發子彈
 bs[0] = new Bullet(this.x+2*xStep,this.y-yStep);//x:英雄機的x+2/4英雄機的寬,y:英雄機的y-
 return bs;
 }
 }

 /**
 * 英雄機移動
 */
 public void moveTo(int x,int y){//形參列表:鼠標的x坐標,y坐標
 this.x = x - this.width/2;//英雄機的x = 鼠標的x減1/2英雄機的寬
 this.y = y - this.height/2;//英雄機的y = 鼠標的y減1/2英雄機的高
 }
 /**
 * 英雄機增生命值
 */
 public void addLife(){
 life++;//生命值+1
 }

 /**
 * 獲取英雄機生命值
 * @return
 */
 public int getLife(){
 return life;//返回生命值
 }

 /**
 * 英雄機減少生命值
 */
 public void subtractLife(){
 life--;//生命值減1
 }
 /**
 * 英雄機增火力值
 */
 public void addFier(){
 fire += 40;//火力值+40
 }

 /**
 * 清空火力值
 */
 public void clearFier(){
 fire = 0;//火力值歸零
 }
}

子彈類Bullet:

package cn.tedu.shoot;

import java.awt.image.BufferedImage;

/**
 * 子彈
 */
public class Bullet extends Flyer {
 // 移動速度
 private int speed;
 public Bullet(int x,int y) {//子彈有多個,每個子彈的初始坐標都不同,所以要寫活
 super(8,20,x,y);
 speed = 3;//初始移動速度
 }
 /**重寫step方法(移動)*/
 public void step(){
 y -= speed;//y-:表示直線向上移動
 }

 /**
 * 重寫getImage()獲取對象圖片
 * @return
 */
 @Override
 public BufferedImage getImage() {//10毫秒走一次
 if (isLive()){//若活著則返回bullet圖片
 return Images.bullet;
 }else if (isDead()){//若死瞭則將state修改為REMOVE
 state = REMOVE;
 }
 return null;//死瞭的和刪除的都返回null空值
 /**
 * 若活著 則返回bullet圖片
 * 若死瞭 則修改REMOVE 再返回空值
 * 若刪除 則返回空值
 */
 }

 /**
 * 判斷子彈是否越界
 * @return
 */
 public boolean isOutOfBounds(){
 return y <= -height;若子彈的y軸坐標小於自己的高則說明移動到瞭窗口外部
 }
}

獎勵值接口 EnemyAward:

package cn.tedu.shoot;

/**
 * 獎勵值接口
 */
public interface EnemyAward {
 public int FIRE = 0;//火力
 public int LIFE = 1;//生命值
 /**
 * 獲取獎勵值類型
 * @return
 */
 int getAwardType();
}

得分接口 EnemyScore:

package cn.tedu.shoot;
/*得分接口*/
public interface EnemyScore {
 /*得分*/
 public int getScore();
}

以上就是本文的全部內容,希望對大傢的學習有所幫助,也希望大傢多多支持WalkonNet。

推薦閱讀: