Java之飞机大战。

项目解析

飞机大战  玩过的朋友应该对这个游戏不陌生

游戏由背景、子弹、敌机、英雄机、小蜜蜂等主要组成;

其中子弹、敌机、英雄机、小蜜蜂拥有共同的特性,如贴图,图片宽高,XY坐标,移动方法,飞出屏幕等。

故抽取一个抽象类

package com.tarena.shott;
import java.awt.image.BufferedImage;

/**
 * 飞行物类
 * @author yaerpi
 *
 */
public abstract class FlyingObject {
	protected BufferedImage image;
	protected int width;
	protected int height;
	protected int x;
	protected int y;
	/**
	 * 飞行物移动
	 */
	public abstract void step(); 
	/**
	 * 飞行物越界
	 * @return yaerpi 
	 */
	public abstract boolean outOfBounds();
	/**
	 * 子弹碰撞敌机
	 * @param b  子弹对象
	 * @return yaerpi
	 */
	public boolean shootBy(Bullet b){
		int x1 = this.x;
		int x2 = this.x + this.width;
		int y1 = this.y;
		int y2 = this.y+this.height;
		int x  = b.x ;
		int y = b.y ;
		return x>x1 && x<x2 && y>y1 &&y<y2;
		
	}
}

接下来是敌机类型

为了后期的扩展性,新定义一个接口,写上敌机特有的得分行为

package com.tarena.shott;
/**
 * 敌人
 * @author yaerpi
 *
 */
public interface Enemy {
	/**
	 * 得分
	 * @return yaerpi
	 */
	public int getScore();
}
新建一个Airplane.java,继承飞行物类实现敌机接口,并重写方法
package com.tarena.shott;
import java.util.Random;
/**
 * 敌机类型  
 * @author xin
 *
 */
public class Airplane extends FlyingObject implements Enemy{
	private int speed = 2;
	
	public Airplane(){
		image = ShootGame.airplane;//图片
		width = image.getWidth();
		height = image.getHeight();
		Random rand = new Random();
		x = rand.nextInt(ShootGame.WIDTH-this.width);//敌机随机出现的坐标
		y = -this.height;

	}
	/**
	 * 重写得分方法
	 */
	public int getScore() {
		return 5;
	}

	/**
	 * 重写走步方法
	 */
	public void step() {
		y+=speed;
		
	}
        
	@Override
	public boolean outOfBounds() {
		
		return this.y>=ShootGame.HEIGHT;
		
	}
	
	

}

接下来是小蜜蜂(带奖励的敌机),敌机特有的行为是奖励分数,而小蜜蜂则是奖励火力值或生命值。

先定义一个接口,写小蜜蜂特有的奖励类型

package com.tarena.shott;
/** 奖励 **/
public interface Award {
	/**
	 * 火力值
	 */
	public int DOUBLE_FIRE = 0 ;
	/**
	 * 生命值
	 */
	public int LIFE = 1;
	/**
	 * 获取奖励类型 
	 * @return yaerpi
	 */
	public int getType();
	
	
}

新建一个Bee.java,用于继承飞行物实现奖励接口

package com.tarena.shott;

import java.util.Random;
/**
 * 小蜜蜂
 * @author yaerpi
 *
 */
public class Bee extends FlyingObject implements Award{
	private int xSpeed = 1;
	private int ySpeed = 2;
	private int awardType;

	public Bee(){
		image = ShootGame.bee;
		width = image.getWidth();
		height = image.getHeight();
		Random rand = new Random();
		x = rand.nextInt(ShootGame.WIDTH-this.width);
		y = -this.height;
		awardType = rand.nextInt(2);//取0-1随机数,随机奖励类型
	}
	/**
	 * 获取到随机的奖励类型
	 */
	public int getType() {
		
		return awardType;
	}

	/**
	 * 小蜜蜂特有的走步方法,从右到左向下
	 */
	public void step() {
		x+=xSpeed;
		y+=ySpeed;
		if(x>ShootGame.WIDTH-this.width){
			xSpeed=-1;
		}
		if(x<=0){
			xSpeed = 1;
		}
	}
	/**
	 * 小蜜蜂越界
	 */
	public boolean outOfBounds() {
		
		return this.y>=ShootGame.HEIGHT;
		
	}
}

英雄机

package com.tarena.shott;
import java.awt.image.BufferedImage;
import java.util.Random;
public class Hero extends FlyingObject {
	private int life;//生命值
	private int doubleFire;//火力值
	private BufferedImage[] images;//图片数组,存储英雄机飞行形态
	private int index;//图片数字下标索引
	
	public Hero (){
		image = ShootGame.hero0;
		width = image.getWidth();
		height = image.getHeight();
		Random rand = new Random();
		x = 150;//初始化英雄机坐标
		y = 400;
		life = 3;//初始化生命值
		doubleFire = 0;//初始化火力值
		images = new BufferedImage[]{ShootGame.hero0,ShootGame.hero1 };
		index = 0;
	}

	
	public void step() {
		image = images[index++/10%images.length];
	}
	
	/**
	 * 英雄机子弹类型,火力值大于0则一次发射两发制子弹
	 * @return yaerpi 
	 */
	public Bullet[] shoot(){
		int xStep = this.width/4;
		int yStep = 20;
		if(doubleFire>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);
			doubleFire-=2;
			return bs;
		}else{
			Bullet[] bs = new Bullet[1];
			bs[0] = new Bullet(this.x+2*xStep,this.y - yStep);
			return bs;
		}
	}
	/**
	 * 鼠标位置,于英雄机中心点
	 * @param x
	 * @param y
	 */
	public void moveTo(int x,int y){
		this.x = x - this.width/2;
		this.y = y - this.height/2;
	}
	
	/**
	 * 英雄机永不越界,重写防报错
	 */
	public boolean outOfBounds() {
		
		return false;
		
	}
	/**
	 * 增加生命值
	 */
	public void addLife(){
		life++;
	}
	/**
	 * 增加火力值
	 */
	public void addFoubleFire(){
		doubleFire +=40;
	}
	/**
	 * 获取当前生命值
	 * @return
	 */
	public int getLife(){
		return life;
	}
	/**
	 * 获取当前火力值
	 * @return
	 */
	public int getDoubleFire(){
		return doubleFire;
	}
	/**
	 * 英雄机与飞行物碰撞
	 * @param f 飞行物
	 * @return
	 */
	public boolean hit(FlyingObject f){
		int x1 = f.x - this.x/2 ;
		int x2 = f.x + f.width+this.width;
		int y1 = f.x - this.height/2;
		int y2 = f.y +f.height+ this.height/2 ;
		int x = this.x+this.width/2 ;
		int y = this.y+this.height/2 ;
		
		
		return x > x1 && x<x2 && y>y1 && y<y2;
	}
	/**
	 * 减少生命值
	 */
	public void subtractLife(){
		life--;
	}
	/**
	 * 火力值归0
	 */
	public void clearDoubleFire(){
		doubleFire = 0;
	}
}

子弹

package com.tarena.shott;
/**
 * 子弹类型
 * @author yaerpi
 *
 */
public class Bullet extends FlyingObject {
	private int speed = 3 ;
	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-=speed;
		
	}
			
	public boolean outOfBounds() {
		
		return this.y<=-this.height;
		
	}
}

新建一个ShootGame.java

package com.tarena.shott;
import java.awt.image.BufferedImage;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import java.awt.Graphics;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.Random;//随机数生成

import java.util.Timer;//定时器
import java.util.TimerTask;
import java.util.Arrays;

import java.awt.Color;
import java.awt.Font;
/**
 * 游戏实现
 * @author yaerpi
 *
 */
public class ShootGame extends JPanel{
	
	public static final int WIDTH = 400;
	public static final int HEIGHT = 654;
	
	public static BufferedImage background;
	public static BufferedImage start;
	public static BufferedImage pause;
	public static BufferedImage gameover;
	public static BufferedImage airplane;
	public static BufferedImage bee;
	public static BufferedImage bullet;
	public static BufferedImage hero0;
	public static BufferedImage hero1;
	//游戏运行状态 ↓
	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;
	public int state = START; 
	
	//初始化对象
	private Hero hero = new Hero();
	private FlyingObject[] flyings = {};
	private Bullet[] bullets = {};
	
/*	ShootGame(){
		flyings = new FlyingObject[2];
		flyings[0] = new Airplane();
		flyings[1] = new Bee();
		bullets = new Bullet[1];
		bullets[0] = new Bullet(100,200);
	}*/
	/**
	 * 静态加载图片资源
	 */
	static{
		try{
			background = ImageIO.read(ShootGame.class.getResource("background.png"));
			start = ImageIO.read(ShootGame.class.getResource("start.png"));
			pause = ImageIO.read(ShootGame.class.getResource("pause.png"));
			gameover = ImageIO.read(ShootGame.class.getResource("gameover.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"));
			hero0 = ImageIO.read(ShootGame.class.getResource("hero0.png"));
			hero1 = ImageIO.read(ShootGame.class.getResource("hero1.png"));
		}catch(Exception e){
			e.printStackTrace();
		}
	}
	/** 
	 * 生成敌人对象
	 * @return
	 */
	public FlyingObject nextOne(){
		Random rand = new Random();
		int type = rand.nextInt(20);
		if (type == 0){
			return new Bee();
		}else{
			return new Airplane();
		}
	}
	int flyEnteredIndex = 0;
	/**
	 * flyEnteredIndex控制敌人出现的间隔时间
	 * 敌人数组扩容,增加新敌人,敌人类型随机(敌机,小蜜蜂)
	 */
	public void enterAction(){
		flyEnteredIndex++;
		if(flyEnteredIndex%40==0){
			FlyingObject one = nextOne();
			flyings = Arrays.copyOf(flyings, flyings.length+1);//敌人数组扩容
			flyings[flyings.length-1] = one ;
		}
	}
	/**
	 * 所有对象走步
	 */
	public void stepAction(){
		hero.step();
		for(int i = 0;i<flyings.length;i++){
			flyings[i].step();
		}
		for(int i = 0;i<bullets.length;i++){
			bullets[i].step();
		}
	}
	int shootIndex = 0;
	/**
	 * shootIndex 控制发射子弹间隔时间
	 * 发射子弹
	 */
	public void shootAction(){
		shootIndex++;
		if(shootIndex%30==0){
			Bullet[] bs = hero.shoot();
			bullets = Arrays.copyOf(bullets, bullets.length+bs.length);
			System.arraycopy(bs, 0, bullets, bullets.length-bs.length, bs.length);
		}
		
		
	}
	/**
	 * 删除越界的飞行物
	 */
	public void outOfBoundsAction(){
		int index = 0;
		FlyingObject[] flyingLives = new FlyingObject[flyings.length];//存储未越界的飞行物数组
		for(int i = 0 ;i< flyings.length ;i++){//遍历飞行物
			FlyingObject f = flyings[i];
			if(!f.outOfBounds()){//判断飞行物是否越界
				flyingLives[index] = f;//保存未越界的飞行物对象
				index++;
			}
		}
		flyings = Arrays.copyOf(flyingLives, index);//数组缩容,只存储未越界的飞行物
		
		index = 0;
		Bullet[] bulle = new Bullet[bullets.length];//存储未越界的子弹数组
		for(int i = 0; i < bullets.length;i++){//遍历子弹
			Bullet b = bullets[i];
			if(!b.outOfBounds()){//判断子弹是否越界
				bulle[index] = bullets[i];
				index++;
			}
			
		}
		bullets = Arrays.copyOf(bulle, index);//数组缩容,只存储未越界的子弹
		
	}
	/**
	 * 遍历子弹
	 */
	public void bangAction(){
		for(int i = 0; i < bullets.length;i++){
			Bullet b = bullets[i];
			bang(b);
		}
	}
	private int score = 0;
	/**
	 * 判断子弹是否撞击飞行物,是则判断飞行物类型,敌机则奖励分数,小蜜蜂则奖励生命值或火力值
	 * @param b 子弹对象
	 */
	public void bang(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 Enemy){
				Enemy e = (Enemy)one;
				score +=e.getScore();
			}
			if(one instanceof Award){
				Award a = (Award)one;
				int type = a.getType();//获取随机奖励制类型
				switch(type){
				case Award.DOUBLE_FIRE:
					hero.addFoubleFire();
					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);//数组缩容,删除碰撞后的飞行物
			
		}
		
	}
	/**
	 * 检查游戏是否结束,英雄机生命值小于等于0时游戏结束
	 */
	public void checkGameOverAction(){
		if(isGameOver()){
			state = GAME_OVER;
			
		}
	}
	/**
	 * 检查英雄机是否碰撞敌人,是则减少生命值
	 * @return 英雄机存活状态
	 */
	public boolean isGameOver(){
		int index = -1;
		for(int i = 0 ; i<flyings.length;i++){
			FlyingObject f = flyings[i];
			if(hero.hit(f)){//判断是否撞击到飞行物
				index = i;
				break;
			}
		}
		if(index != -1){//撞击到飞行物
			FlyingObject t = flyings[index];
			flyings[index] = flyings[flyings.length-1];
			flyings[flyings.length-1] = t;
			flyings = Arrays.copyOf(flyings, flyings.length-1);//删除飞行物
			hero.subtractLife();//减少生命值
			hero.clearDoubleFire();//重置火力值
		}
		
		return hero.getLife()<=0;
	}
	/**
	 * 启动任务执行  主程序体
	 */
	public void action(){
		MouseAdapter l = new MouseAdapter(){//鼠标事件
			/**
			 * 鼠标移动事件,鼠标始终处于英雄机中心
			 */
			public void mouseMoved(MouseEvent e){
				if(state == RUNNING){
					int x = e.getX();
					int y = e.getY();
					hero.moveTo(x, y);
				}
			}
			/**
			 * 鼠标单击事件,判断当前游戏状态,选择相应流程
			 */
			public void mouseClicked(MouseEvent e){
				switch(state){
				case START:
					state = RUNNING;
					break;
				case GAME_OVER:
					score = 0;
					hero = new Hero();
					flyings = new FlyingObject[0];
					bullets = new Bullet[0];
					state = START;
					break;
				}
				
				
			}
			/**
			 * 鼠标移出事件
			 * 鼠标移出窗口则游戏暂停
			 */
			public void mouseExited(MouseEvent e){
				if(state ==RUNNING){
					state = PAUSE;
				}
				
			}
			/**
			 * 鼠标移入事件
			 * 鼠标回到窗口则游戏继续
			 */
			public void mouseEntered(MouseEvent e){
				if(state == PAUSE){
					state = RUNNING;
				}
				
			}
		};
		//设置鼠标事件监听
		this.addMouseListener(l);
		this.addMouseMotionListener(l);
		Timer timer = new Timer();//定时发生器
		int intervel = 10;//定时发生时间间隔,毫秒
		timer.schedule( new TimerTask(){
			/**
			 * 定时发生器定时运行事件
			 */
			public void run(){
				if(state == RUNNING){
				enterAction();//出现敌人
				stepAction();//敌人移动
				shootAction();//英雄机射击
				outOfBoundsAction();//删除越界飞行物
				bangAction();//判断子弹撞击飞行物
				checkGameOverAction();//检查游戏是否结束
				}
				repaint();//重画 - 调用的paint方法;
			}
		},intervel,intervel);
		}
	/**
	 * 画窗口对象
	 */
	public void paint(Graphics g){
		g.drawImage(background,0,0,null);
		paintHero(g);
		paintFlyingObjects(g);
		paintBullets(g);
		paintScoreAndLife(g);
		paintState(g);
	}
	/**
	 * 画英雄机
	 * @param g
	 */
	public void paintHero(Graphics g){
		g.drawImage(hero.image,hero.x,hero.y,null);
	}
	/**
	 * 画飞行物
	 * @param g
	 */
	public void paintFlyingObjects(Graphics g){
		for(int i = 0;i<flyings.length;i++){
			FlyingObject f = flyings[i];
			g.drawImage(f.image,f.x, f.y, null);
		}
		
	}
	/**
	 * 画子弹
	 * @param g
	 */
	public void paintBullets(Graphics g){
		for(int i = 0;i<bullets.length;i++){
			Bullet b = bullets[i];
			g.drawImage(b.image, b.x, b.y, null);
		}
		
	}
	/**
	 * 画当前游戏分数
	 * @param g
	 */
	public void paintScoreAndLife(Graphics g){
		g.setColor(new Color(0xff0000));
		g.setFont(new Font(Font.SANS_SERIF,Font.BOLD,24));
		g.drawString("Score: "+ score, 10, 25);
		g.drawString("Life: "+ hero.getLife(), 10, 45);
		g.drawString("DoubleFire: "+hero.getDoubleFire(), 10, 65);
	}
	/**
	 * 画游戏状态
	 * @param g
	 */
	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 GAME_OVER:
			g.drawImage(gameover, 0, 0, null);
			break;
		
		}
	}
	
	public static void main(String[] args) {
		JFrame frame = new JFrame("Fly");
		ShootGame game = new ShootGame();
		frame.add(game);
		frame.setSize(WIDTH, HEIGHT);
		frame.setAlwaysOnTop(true);
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.setLocationRelativeTo(null);
		frame.setVisible(true);
		
		game.action();
	}

}

  • 12
    点赞
  • 41
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值