飞机大战,老版飞机大战


项目需求:

        实现一个简单的飞机大战程序,当消灭掉一个小飞机的时候的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.最终效果:

 

 

 

 

 

文章最后发布于: 2019-10-16 14:12:30

相关内容

    暂无相关文章