飛機大戰

知惑發表於2019-10-16

專案需求:

        實現一個簡單的飛機大戰程式,當消滅掉一個小飛機的時候的5分,當消滅掉一個小蜜蜂的時候有可能火力值增加24也有可能生命值增加1,如果打飛機也就是英雄機和敵人(蜜蜂+小飛機)碰撞之後,英雄機的火力值清零,生命值減去1。當英雄機的生命值為0的時候遊戲結束。

具體思路:

       1.首先進行類的設計(明確本專案中有哪些物件,物件的屬性和行為),為了提高程式的可擴張性,本專案中總共設計了8個(類和介面)分別為:飛機類(Airplane),獎勵的介面(Award),蜜蜂類(Bee),子彈類(Bullet),敵人的介面用來獲取得分(Enemy),飛行物類(FlyingObject),英雄機類(Hero),主程式類(ShootGame)。

       2.明確不同物件屬性和行為:其中蜜蜂,敵機,英雄機,子彈公共屬性為:圖片,圖片的高度,圖片的寬度,位置座標x和y。

除此之外英雄機還有得分,生命值,火力值等屬性。

       3.畫視窗,和物件,調動java中的paint(Graphics g)方法將物件畫在視窗中。

       4.為了讓物件動起來,需要設定一個定時器。

       5.子彈和飛行物的碰撞(蜜蜂+小飛機)。

       6.英雄機和飛行物的碰撞。

       7.畫狀態(狀態分為:啟動狀態,執行狀態,暫停狀態,結束狀態),得分,火力值,生命值。

具體的程式碼實現:

1.小飛機類:

package com.feijidazhan.shaodong;
//敵機類
import java.util.Random;

public class Airplane extends FlyingObject implements Ememy{
	 private int score=5;
	 private int xSteep=1;
	 private int ySteep=2;
     public  Airplane(){
    	  image=ShootGame.airplane;//敵機的圖片
    	  height=image.getHeight();//圖片的高度
    	  width=image.getWidth();//圖片的寬度
    	  Random rand=new Random();//定義一個隨機數物件
    	  x=rand.nextInt(ShootGame.WIDTH-this.width);//敵機的橫座標x的範圍
    	  y=-this.height;//敵機縱座標y的範圍
     }
     //敵機的走步
	  public void step() {
		  y+=ySteep;

       }
	  //敵機快速走步
	  public void ShiftStep() {
		  y+=ySteep+1;
		  //讓英雄機碰到左邊的時候彈回來
//		  x-=xSteep;
//		  if(x>ShootGame.WIDTH-this.width) {
//			  xSteep=1;
//		  }
//		  if(x<0) {
//			  xSteep=-1;
//		  }
	  }
	  //打掉一個敵機獲得的分數
	  public int getScore() {
		  return score;
	  }
	  //重寫outOfBounds方法//true表示越界.false表示沒有越界
	  public   boolean outOfBounds() {
		  return this.y>ShootGame.HEIGHT;//當敵機的高大於視窗的高的時候表示越界
	  }
}

2.獎勵的藉口:

package com.feijidazhan.shaodong;
//獲取獎勵的型別,其中0表示增加火力,1表示增加生命
public interface Award {
	public   int DOUBLE_FIRE=0;//表示剛開始的火力值是0
	public   int LIFE=1;
	public int getType();//表示獲取獎勵的型別
	

}

3.蜜蜂類:

package com.feijidazhan.shaodong;
//蜜蜂類
import java.util.Random;

public class Bee extends FlyingObject implements Award{
	private int xSpeed=1;
	private int ySpeed=2;
	public int awardType;
	public Bee() {
		image=ShootGame.bee;//蜜蜂的圖片
		height=image.getHeight();//蜜蜂的高度
		width=image.getWidth();//蜜蜂的寬度
		Random rand=new Random();
		x=rand.nextInt(ShootGame.WIDTH-image.getWidth());
		y=-image.getHeight();
		awardType=rand.nextInt(2);
		
	}
	//蜜蜂的走步
	public void step() {
		x+=xSpeed;
		y+=ySpeed;
		if(x>=ShootGame.WIDTH-this.width) {
			//當蜜蜂的座標大於視窗的寬度減去蜜蜂的寬度的時候蜜蜂應該往左邊移動
			xSpeed=-1;
		}
		if(x<0) {
			xSpeed=1;
		}
		
	}
	//蜜蜂的快速走步
	public void ShiftStep() {
		x+=xSpeed;
		y+=ySpeed;
		if(x>=ShootGame.WIDTH-this.width) {
			//當蜜蜂的座標大於視窗的寬度減去蜜蜂的寬度的時候蜜蜂應該往左邊移動
			xSpeed=-2;
		}
		if(x<0) {
			xSpeed=1;
		}
	}
	//蜜蜂的獎勵
	public int getType() {
		return awardType;
	}
	//判斷蜜蜂是否越界重寫outOfBounds方法
	public   boolean outOfBounds() {
		return this.y>ShootGame.HEIGHT;//當蜜蜂的座標大於視窗的高的時候表示越界
	}
     
}

4.子彈類:

package com.feijidazhan.shaodong;
//子彈類
public class Bullet extends FlyingObject {
	private int ySpeed=2;
	public Bullet(int x,int y) {
		image=ShootGame.bullet;
		width=image.getWidth();//獲取子彈的圖片的寬度
		height=image.getHeight();//獲取子彈圖片的高度
		this.x=x;//由於子彈的座標隨著英雄機的座標的變化而變化
		this.y=y;
		
	}
	//子彈的走步
	public void step() {
		y-=ySpeed;
	}
	//重寫outOfBounds方法
	public   boolean outOfBounds() {
		return this.y+image.getHeight()<0;
	}
	//
	public void ShiftStep() {
		
	}

}

5.敵人的介面(主要獲取得分):

package com.feijidazhan.shaodong;
//該介面為獲取得分
public interface Ememy {
	public int  getScore();//表示擊敗一個敵機所得到的到分數

}

6.飛行物類(父類):

package com.feijidazhan.shaodong;
//表示飛行物類

import java.awt.image.BufferedImage;
public  abstract class FlyingObject {
	protected int x;//表示x座標
	protected int y;//表示y座標
	protected int height;//表示相應圖片的高度
	protected int width;//表示相應圖片的寬度
	protected BufferedImage image;//表示相應的圖片
	public abstract void step();//飛行物的走步
	public  abstract boolean outOfBounds();//飛行物的越界
	//子彈和敵人的碰撞
	public boolean shootBy(Bullet bullet) {
			int x1=this.x;
			int y1=this.y;
			int x2=x+this.width;
			int y2=y+this.height;
			int x=bullet.x;
			int y=bullet.y;
			return x>x1&&x<x2
					&&
					y>y1&&y<y2;
	}
	public abstract  void ShiftStep();
      
}

7.英雄機類:

package com.feijidazhan.shaodong;
//英雄機
import java.awt.image.BufferedImage;


public class Hero extends FlyingObject{
	private int Fire;//英雄機的火力值
	private int Life;//英雄機的生命值
	private BufferedImage []images;//
	private int index;
	
	public Hero() {
		image=ShootGame.hero0;
		width=image.getWidth();//英雄機的寬度
		height=image.getHeight();//英雄機的高度
		x=150;
		y=300;
		Fire=0;
		Life=3;
		images=new BufferedImage[] {ShootGame.hero0,ShootGame.hero1};
		index=0;
	}
	//英雄機的走步即使英雄機圖片的切換
	public  void step() {
		index++;
		int a=index/10;
		int b=a%images.length;
		image=images[b];
	}
	//重寫outOfBounds,用來判斷是否越界
	public   boolean outOfBounds() {
		return false;
	}
	//產生子彈物件
	public Bullet[] shoot(){
		int xStep=(this.width)/4;//子彈的x座標
		int yStep=20;//子彈的縱座標
		if(Fire>0) {
			Bullet []bs=new Bullet[2];
			bs[0]= new Bullet(this.x+1*xStep,this.y-yStep);
			bs[1]=new Bullet(this.x+3*xStep,this.y-yStep);
			Fire-=2;
			return bs;

		}else {
			Bullet bs[]=new Bullet[1];
			bs[0]=new Bullet(this.x+2*xStep,this.y-yStep);
			return bs;
		}
	}
	//英雄機的移動
	public void moveTo(int x,int y) {
		this.x=x-this.width/2;
		this.y=y-this.height/2;

	}
	//增加英雄機的火力值
	public void addFire() {
		 Fire+=24;
	}
	//英雄機火力值清零
	public void subFire() {
		 Fire=0;//將英雄機的火力值置0
	}
	//增加英雄機的生命值
	public void  addLife() {
		 Life++;
	}
	//英雄機與飛行物的碰撞
	public boolean shootFy(FlyingObject f) {
		int x1=f.x-this.width/2;//邊界座標
		int y1=f.y-this.height/2;//邊界座標
		int x2=f.x+this.width/2+f.width;
		int y2=f.y+f.height+this.height/2;
		int x=this.x+this.width/2;//英雄機的中心x座標
		int y=this.y+this.height/2;//英雄機的中心y座標		
		return x>x1&&x<x2
				&&
				y>y1&&y<y2;
	}
	//英雄機減命
	public void subLife() {
		  Life--;
	}
	//返回生命值
	public int Life() {
		return Life;
	}
	//返回英雄機的火力值
	public int Fire() {
		return Fire;
	}
	public void ShiftStep() {
		
	}


}

8.主程式類:

package com.feijidazhan.shaodong;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
//測試類
import java.awt.image.BufferedImage;
import java.util.Arrays;
import java.util.Random;
import java.util.Timer;
import java.util.TimerTask;

import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class ShootGame extends JPanel{
	public static final int WIDTH=400;
	public static final int HEIGHT=654;
	public static BufferedImage background;//定義背景圖片
	public static BufferedImage airplane;
	public static BufferedImage bee;
	public static BufferedImage bullet;
	public static BufferedImage gameover;
	public static BufferedImage hero0;
	public static BufferedImage hero1;
	public static BufferedImage pause;
	public static BufferedImage start;
	public Hero hero=new Hero();
	public static final int START=0;//程式的啟動
	public static final int RUNNING=1;//程式的執行
	public static final int PAUSE=2;
	public static final int GAMEOVER=3;
	private  int state=START;//表示當前的狀態
	private FlyingObject[]flyings= {};
	private Bullet[] bullets= {};
	static {
		try {
			background=ImageIO.read(ShootGame.class.getResource("background.png"));
			airplane=ImageIO.read(ShootGame.class.getResource("airplane.png"));
			bee=ImageIO.read(ShootGame.class.getResource("bee.png"));
			bullet=ImageIO.read(ShootGame.class.getResource("bullet.png"));
			gameover=ImageIO.read(ShootGame.class.getResource("gameover.png"));
			hero0=ImageIO.read(ShootGame.class.getResource("hero0.png"));
			hero1=ImageIO.read(ShootGame.class.getResource("hero1.png"));
			pause=ImageIO.read(ShootGame.class.getResource("pause.png"));
			start=ImageIO.read(ShootGame.class.getResource("start.png"));
			
		}catch(Exception e) {
			e.printStackTrace();
		}
		
	}
	//飛行物入場(敵人+小蜜蜂)
	public FlyingObject nextOne() {
		int type;
		Random rand=new Random();
		type=rand.nextInt(20);
		if(type>=5) {
			return new Airplane();
		}else {
			return new Bee();
		}
	}
	int flyEnterIndex=0;//敵人入場計數器為了避免產生的敵人太多需要對其數量進行限制
	//敵人入場的方法
	public void enterAction() {
		flyEnterIndex++;
		if(flyEnterIndex%20==0) {
			FlyingObject obj=nextOne();//獲取敵人物件
			flyings=Arrays.copyOf(flyings, flyings.length+1);//陣列的擴容
			flyings[flyings.length-1]=obj;//將剛剛產生的敵人新增到陣列的末端
		}
		
	}
	int bulletIndex=0;//子彈入場計數器
	//子彈的入場
	public void bulletAction() {
		bulletIndex++;
		if(bulletIndex%30==0) {
			Bullet bs[]=hero.shoot();//獲取子彈物件
			bullets=Arrays.copyOf(bullets, bullets.length+bs.length);//子彈陣列的擴容
			//其中System.arraycopy中引數依次表示:原始陣列,原始陣列的下標,目標陣列,目標陣列的起始位置,需要賦值的陣列的長度)
			//其中表示的是將陣列bs複製到陣列bullets中
			System.arraycopy(bs, 0, bullets, bullets.length-bs.length, bs.length);//陣列的擴容
		}
	}
	
	//敵人,英雄機,子彈的走步
	public void stepAction() {
		hero.step();//英雄機的走步
		for(int i=0;i<flyings.length;i++) {//敵人的走步
			if(hero.Life()<=9) {
			flyings[i].step();
			}
			if(hero.Life()>=10) {
				flyings[i].ShiftStep();
			}
		}
		for (int i = 0; i < bullets.length; i++) {//子彈的移動
			bullets[i].step();//子彈的走步
		}
		
	}
	//刪除越界的飛行物(敵人和子彈)
	public void outOfBoundsAction() {
		int index=0;//飛行物的下標數值
		int bulletIndex=0;//子彈的下標數值
		Bullet bulletlives[]=new Bullet[bullets.length];
		FlyingObject flyingslives[]=new FlyingObject[flyings.length];
		//刪除越界的飛行物
		for(int i=0;i<flyings.length;i++) {
			FlyingObject f=flyings[i];
			if(!f.outOfBounds()) {
				flyingslives[index]=flyings[i];
				index++;
			}
		}
		//刪除越界的子彈
		for(int i=0;i<bullets.length;i++) {
			Bullet bs=bullets[i];
			if(!bs.outOfBounds()) {
				bulletlives[bulletIndex]=bullets[i];
				bulletIndex++;
			}
		}
		flyings=Arrays.copyOf(flyingslives, index);
		bullets=Arrays.copyOf(bulletlives, bulletIndex);
		
	}
	
    //子彈和敵人的碰撞
	public void shootByAction() {
		for(int i=0;i<bullets.length;i++) {
			Bullet b=bullets[i];//獲取子彈
			bullet(b);//
		}
		
	}
	//子彈碰撞結果
	int score =0;//表示得分
	public void bullet(Bullet b) {
		//遍歷飛行物陣列
	 	int index=-1;//記錄碰撞敵人的下標
		for(int i=0;i<flyings.length;i++) {
			FlyingObject f=flyings[i];//獲取敵人
			if(f.shootBy(b)) {
				index=i;
				break;
			}
		}
		if(index!=-1) {
			FlyingObject one=flyings[index];
			if(one instanceof Ememy) {
				Ememy ememy=(Ememy)one;
				score+=ememy.getScore();//分數加
			}
			if(one instanceof Award) {
				Award award=(Award)one;
				int type=award.getType();
				switch(type) {
				case Award.DOUBLE_FIRE:
					hero.addFire();
					break;
				case Award.LIFE:
					hero.addLife();
					break;
				}
				
			}
			FlyingObject t=flyings[index];
			flyings[index]=flyings[flyings.length-1];
			flyings[flyings.length-1]=t;
			flyings=Arrays.copyOf(flyings,flyings.length-1);
			
		}
		
}
	//檢查遊戲是否結束 
	public void CheckGameOverAction() {
		 if(isGameOverAction()) {
			 state=GAMEOVER;
		 }
	 }
	//判斷遊戲是否結束
	public boolean isGameOverAction() {
		for (int i = 0; i < flyings.length; i++) {
			FlyingObject f=flyings[i];
			if(hero.shootFy(f)) {//撞上l
				hero.subLife();
				hero.subFire();
				//利用陣列的擴容,刪除碰撞
				FlyingObject t=flyings[i];
				flyings[i]=flyings[flyings.length-1];
				flyings[flyings.length-1]=t;
				flyings=Arrays.copyOf(flyings,flyings.length-1);
			}
			
		}
		return hero.Life()<=0;
		
	}
	//程式的啟動的方法
	public void action() {
		//為了監視飛行物隨著滑鼠的移動建立一個監聽器
		MouseAdapter l=new MouseAdapter() {
			public void mouseMoved(MouseEvent e){
				int x=e.getX();//獲取滑鼠的x座標
				int y=e.getY();//獲取滑鼠的y座標
				hero.moveTo(x, y);//英雄機移動
			}
			//重寫滑鼠點選事件
			public void mouseClicked(MouseEvent e) {
				switch(state) {
				case START:
					state=RUNNING;
					break;
				case GAMEOVER:
					score=0;
					hero=new Hero();
					flyings=new FlyingObject[0];
					bullets=new Bullet[0];
					state=START;
					break;
				}
			}
			//重寫滑鼠進入事件
			 public void mouseEntered(MouseEvent e) {
				 if(state==PAUSE) {
					 state=RUNNING;
				 }
			 }
			 //重寫滑鼠離開事件
			 public void mouseExited(MouseEvent e) {
				 if(state==RUNNING) {
					 state=PAUSE;
				 }
			 }
			 
			 
			
			
		};
		this.addMouseListener(l);
		this.addMouseMotionListener(l);//處理滑鼠滑動事件
		Timer time=new Timer();
		time.schedule(new TimerTask() {
			public void run() {
				if(state==RUNNING) {
				nextOne();//產生飛行物物件
				enterAction();//飛行物的入場
				stepAction();//走步
				bulletAction();//子彈的入場
				outOfBoundsAction();//刪除越界的飛行物
				shootByAction();//子彈和敵人的碰撞
				CheckGameOverAction();//檢查遊戲是否結束
				}
				repaint();
				
			}
		}, 10,10);
		
		
	}
	//繪製圖
	public void paint(Graphics g) {
		g.drawImage(background, 0,0,null);
		paintHero(g);//畫英雄機物件
		paintFlyingObject(g);//畫敵機物件
		paintFlyingObjectAndBulletLength(g);//繪製飛行物陣列和子彈陣列的長度
		paintBullet(g);//畫子彈
		paintState(g);//畫狀態
	}
	//畫英雄機物件
	public void paintHero(Graphics g) {
		g.drawImage(hero.image,hero.x,hero.y,null);
		
	}
	//畫敵人物件
	public void paintFlyingObject(Graphics g) {
		for(int i=0;i<flyings.length;i++) {
			g.drawImage(flyings[i].image,flyings[i].x,flyings[i].y,null);
		}
	}
	//畫子彈物件
	public void paintBullet(Graphics g) {
		for(int i=0;i<bullets.length;i++) {
			g.drawImage(bullets[i].image,bullets[i].x,bullets[i].y,null);
		}
		
	}
	//畫敵人陣列和子彈陣列的長度
	public void paintFlyingObjectAndBulletLength(Graphics g) {
		g.setColor(Color.red);
		g.setFont(new Font(Font.SANS_SERIF,Font.BOLD,24));
		g.drawString("score:"+score, 20, 20);
		g.drawString("Fire:"+hero.Fire(), 20, 40);
		g.drawString("Life:"+hero.Life(), 20, 60);
	}
	//畫狀態
	public void paintState(Graphics g) {
		switch(state) {
		case START:
			g.drawImage(start, 0,0,null);
			break;
		case PAUSE:
			g.drawImage(pause,0,0,null);
			break;
		case GAMEOVER:
			g.drawImage(gameover, 0, 0, null);
			break;
	
		}
		
	}

	public static void main(String[] args) {
		JFrame frame=new JFrame("飛機大戰");
		ShootGame game=new ShootGame();
		frame.add(game);
		frame.setSize(ShootGame.WIDTH, ShootGame.HEIGHT);
		frame.setAlwaysOnTop(true);//該視窗位於所有皮膚之上
		frame.setLocationRelativeTo(null);
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//設定視窗的可關閉性
		frame.setVisible(true);//設定視窗的可見性此方法的功能1.使得視窗可見。2.儘快的呼叫repaint()方法
		game.action();//程式的啟動方法

	}

}

9.最終效果:

 

 

 

 

 

相關文章