FlyingObject,作为飞行物的父类,这里的飞行物指的就是敌机,小蜜蜂,子弹,英雄机

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

//飞行物类
public abstract class FlyingObject {
	protected BufferedImage image; //图片
	protected int width;  		   //宽
	protected int height;		   //高
	protected int x;			   //坐标
	protected int y;
	
	// 飞行物走一步
	public abstract void step();
	
	//检查是否出界,,返回true表示已越界
	public abstract boolean outOfBounds();
	
	public boolean shootBy(Bullet b) {
		return false;
	};
}

敌机类,图片取自ShootGame的入口类(在下面),打掉一个敌机得五分,敌机只能向下走
图片在主类 ShootGame中静态引入了

package com.tarena.shoot;
import java.util.Random;

//敌机
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+1);
		y = -this.height;
	}
	public int getScore() {
		return 5;  //打掉一个敌机得5分
	}
	
	// 重写
	public void step() {
		y+=speed;
	}
	
	// 重写是否越界函数---越界删除该对象
	public boolean outOfBounds() {
		if(y>ShootGame.HEIGHT) {
			return true;
		}else {
			return false;
		}
	}
	
	// 敌人被子弹射击----也就是检测图片与图片之间检测碰撞
	public boolean shootBy(Bullet bullet) {
		int x1 = this.x;
		int x2 = this.x + this.width;
		int y1 = this.y;
		int y2 = this.y + this.height;
		// x在 x1 和 x2 之间,y在y1和y2之间,既是碰撞了
		if(bullet.x<x2 && bullet.x>x1 && bullet.y<y2 && bullet.y>y1) {
			return true;
		}else {
			return false;
		}
	}
}

Bee,小蜜蜂类,也是敌人的一种,和上面敌机不同的是,小蜜蜂还会横着走,碰到边界反弹,打掉一个小蜜蜂还会获得奖励,也就是继承的接口 Award

package com.tarena.shoot;

import java.util.Random;

public class Bee extends FlyingObject implements Award{
	private int xSpeed = 1; //X坐标速度
	private int ySpeed = 2; //Y坐标速度
	private int awardType;  //奖励的类型 0/1
	
	public Bee() {
		image = ShootGame.bee;
		width = image.getWidth();
		height = image.getHeight();
		Random rand = new Random();
		x = rand.nextInt(ShootGame.WIDTH - this.width+1);
		y = -this.height;
		awardType = rand.nextInt(2); //0到1之间
		
		int xSymbol = rand.nextInt(2);
		if(xSymbol == 0) {
			xSpeed = -xSpeed;
		}
	}
	public int getType() {
		return awardType;   //返回奖励类型 0/1   在ShootGame 中根据0、1判断奖励的类型分别调用方法
	}
	
	// 重写
	public void step() {
		y+=ySpeed;
		x+=xSpeed;
		if(x>ShootGame.WIDTH-this.width || x<=0) {
			xSpeed = -xSpeed;
		}
	}
	
	// 重写是否越界函数
	public boolean outOfBounds() {
		if(y>ShootGame.HEIGHT) {
			return true;
		}else {
			return false;
		}
	}
	
	// 敌人被子弹射击
	public boolean shootBy(Bullet bullet) {
		int x1 = this.x;
		int x2 = this.x + this.width;
		int y1 = this.y;
		int y2 = this.y + this.height;
		// x在 x1 和 x2 之间,y在y1和y2之间,既是碰撞了
		if(bullet.x<x2 && bullet.x>x1 && bullet.y<y2 && bullet.y>y1) {
			return true;
		}else {
			return false;
		}
	}
	
}

Award,,奖励,被小蜜蜂继承

package com.tarena.shoot;

public interface Award {
	public int DOUBLE_FILE = 0; //火力值
	public int LIFE = 1;        //命
//	获取奖励
	public int getType();
}

Enemy类,作为敌人(敌机+小蜜蜂)的公共接口,得分

package com.tarena.shoot;

public interface Enemy {
//	得分
	public int getScore();
}

主角英雄机,Hero,有动态效果,两张图片来回切换

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

//英雄机
public class Hero extends FlyingObject {
	private int life;   //命
	private int doubleFire=0;   //火力值
	private BufferedImage[] images; //两张图片切换
	private int index; //协助图片切换
	
	public Hero() {
		image = ShootGame.hero0;
		width = image.getWidth();  //获取图片的宽
		height = image.getHeight(); //获取图片的高
		x = 150;  //x:初始值
		y = 400;  //y:初始值
		life = 3; //默认3条命
		images = new BufferedImage[] {ShootGame.hero0,ShootGame.hero1};
		// 初始化images,两张图片
		index = 0; //协助切换
	}
	
	// 重写
	public void step() {
		index++;
		image = images[index/10%images.length];  //每100个毫秒切换一次
	}
	// 英雄机发射子弹
	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; //发射一次双倍火力减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 boolean outOfBounds() {
		return false;  //永不越界
	}
	
	// 加命
	public void addLife() {
		life++;
	}
	// 返回命
	public int getLife() {
		return life;
	}
	
	public void reduceLife() {
		life--;
	}
	
	// 加火力
	public void addDoubleFire() {
		doubleFire += 40;
	}
	public void zeroDoubleFire() {
		doubleFire = 0;
	}
	
	// 英雄机撞敌人,,true表示碰撞
	public boolean hit(FlyingObject obj) {
		int x1 = this.x - this.width/2;
		int x2 = this.x + this.width/2;
		int y1 = this.y - this.height/2;
		int y2 = this.y + this.height/2;
		if(obj.x<x2 && obj.x>x1 && obj.y<y2 && obj.y>y1) {
			return true;
		}else {
			return false;
		}
	}
}

Bullet类,子弹类,也是飞行物的一种,它的x,y都是跟随英雄机

package com.tarena.shoot;

import java.util.Random;

public class Bullet extends FlyingObject{
	private int speed = 3;
	
	public Bullet(int x,int y) {
		image = ShootGame.bullet;
		width = image.getWidth();  //获取图片的宽
		height = image.getHeight(); //获取图片的高
		Random rand = new Random(); //随机数对象
		this.x = x;  //x跟随英雄机
		this.y = y;  //y跟随英雄机
	}
	
	// 重写
	public void step() {
		y-=speed;
	}
	
	// 重写是否越界函数
	public boolean outOfBounds() {
		if(y<-this.height) {
			return true;
		}else {
			return false;
		}
	}
}

主类ShootGame,整个入口类,在这其中引入了所有的静态资源(图片),整个程序是用JFrame和JPanel来写的
检测鼠标事件,设定了一个定时器,画面是由定时器不断调用repaint方法刷新重画的

package com.tarena.shoot;
import java.awt.Component;
import java.awt.image.BufferedImage;
import javax.imageio.ImageIO;
import java.util.Random;

import javax.swing.JFrame;
import javax.swing.JPanel;
import java.awt.Graphics;

import java.util.Timer;
import java.util.TimerTask;

import java.util.Arrays;

import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

import java.awt.Color;
import java.awt.Font;

//主程序类
public class ShootGame extends JPanel {
	public static final int WIDTH = 400;  //窗口宽
	public static final int HEIGHT = 654; //窗口高
	
	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;  //当前状态
	
	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;
	
	private Hero hero = new Hero();
	private FlyingObject[] flyings = {}; //敌人数组
	private Bullet[] bullets = {}; //子弹数组
	
	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();
		}
	}
	
	// 随机生成敌人对象
	public FlyingObject nextOne() {
		Random rand = new Random();
		int type = rand.nextInt(2);
		if(type == 0) {
			return new Bee();
		}else {
			return new Airplane();
		}
	}
	
	// 敌人入场
	int flyEnteredIndex = 0;
	public void enterAction() {
		//生成敌人对象,将对象添加到flyings数组中
		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;
	public void shootAction() {
		shootIndex++;
		if(shootIndex%30 == 0) {
			Bullet[] bs = hero.shoot();
//			System.arraycopy(bs,0, bullets, bullets.length-bs.length, bs.length);
			bullets = Arrays.copyOf(bullets, bullets.length+bs.length);
			for(int i=0; i<bs.length; i++) {
				bullets[bullets.length-bs.length+i] = bs[i];
			}
		}
	}
	
	// 删除越界的敌人,,敌机,小蜜蜂,子弹
	public void outOfBoundsAction() {
		// 删除越界的敌机,小蜜蜂
		int index = 0;
		FlyingObject[] flyingLives = new FlyingObject[flyings.length];
		for(int i=0; i<flyings.length; i++) {
			if(!flyings[i].outOfBounds()) {
				flyingLives[index] = flyings[i];
				index++;
			}
		}
		flyings = Arrays.copyOf(flyingLives, index);
		
		// 删除越界的子弹
		index = 0;
		Bullet[] bulletLives = new Bullet[bullets.length];
		for(int i=0; i<bullets.length; i++) {
			if(!bullets[i].outOfBounds()) {
				bulletLives[index] = bullets[i];
				index++;
			}
		}
		bullets = Arrays.copyOf(bulletLives, index);
	}
	
	// 所有子弹与所有敌人(敌机+小蜜蜂)的碰撞
	public void bangAction() {
		for(int a=0; a<bullets.length; a++) {
			bang(a);
		}
	}
	// 一个子弹与所有敌人的碰撞
	int score = 0;
	public void bang(int a) {
		Bullet b = bullets[a];
		int bangPoint = -1;
		for(int i=0; i<flyings.length; i++) {
			if(flyings[i].shootBy(b)) {
				bangPoint = i;
				break;
			}
		}
		if(bangPoint != -1) {
			FlyingObject obj = flyings[bangPoint];
			if(obj instanceof Enemy) {
				Enemy one = (Enemy)obj;
				score += one.getScore();
			}
			if(obj instanceof Award) {
				Award two = (Award)obj;
				int type = two.getType();
				switch(type) {
				case Award.DOUBLE_FILE:
					hero.addDoubleFire();
					break;
				case Award.LIFE:
					hero.addLife();
					break;
				}
			}
			FlyingObject l = flyings[flyings.length-1];  //最后一个敌人(敌机,小蜜蜂)
			flyings[bangPoint] = l;                      //放到被撞物体的位置上
			flyings = Arrays.copyOf(flyings, flyings.length-1); //直接缩容
			
			Bullet ll = bullets[bullets.length-1];  //最后一个子弹
			bullets[a] = ll;                        //放到被撞子弹的位置上
			bullets = Arrays.copyOf(bullets, bullets.length-1); //直接缩容
		}
	}
	
	// 检查游戏是否结束
	public void checkGameOverAction() {
		for(int i=0; i<flyings.length; i++) {
			if(hero.hit(flyings[i])) {
				//碰撞
				hero.reduceLife();
				hero.zeroDoubleFire();
				if(hero.getLife() <= 0) {
					state = GAME_OVER;
				}
				FlyingObject l = flyings[flyings.length-1];  //最后一个敌人(敌机,小蜜蜂)
				flyings[i] = l;                              //放到被撞物体的位置上
				flyings = Arrays.copyOf(flyings, flyings.length-1); //直接缩容
			}
		}
	}
	int num=0;
	public void action() {
		MouseAdapter l = new MouseAdapter() {
			// 鼠标移动事件
			public void mouseMoved(MouseEvent e) {
				if(state == RUNNING) {
					hero.moveTo(e.getX(), e.getY());
				}
			}
			// 鼠标点击事件
			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 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 timer = new Timer(); //创建定时器对象
		int interval = 10; //时间间隔 (以毫秒为单位)
		timer.schedule(new TimerTask() {
			public void run() {
				if(state == RUNNING) {
					enterAction();
					stepAction();
					shootAction();
					outOfBoundsAction(); //删除越界的敌人
					bangAction(); //子弹和敌人碰撞
				}
				checkGameOverAction();  //英雄机和敌人的碰撞
				repaint();
			}
		}, interval,interval);
	}

//	重写paint()  g:画笔
	public void paint(Graphics g) {
		g.drawImage(background,0, 0, null);
		paintHero(g);
		paintFlyingObjects(g);
		paintBullets(g);
		paintScoreandLife(g);
		paintState(g); //画状态
	}
	//画英雄机对象
	public void paintHero(Graphics g) {
		g.drawImage(hero.image, hero.x, hero.y,null);
	}
	//画敌人对象
	public void paintFlyingObjects(Graphics g) {
		for(int i=0; i<flyings.length; i++) {
			g.drawImage(flyings[i].image,flyings[i].x,flyings[i].y,null);			
		}
	}
	//画子弹对象
	public void paintBullets(Graphics g) {
		for(int i=0; i<bullets.length; i++) {
			g.drawImage(bullets[i].image, bullets[i].x, bullets[i].y, null);
		}
	}
	
	//画分和得命
	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);
	}
	
	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.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.setLocationRelativeTo(null);
		frame.setVisible(true); //1.设置窗口可见,2.尽快调用paint()方法
		
		game.action(); //启动程序的执行
	}
}

看看效果图啊,玩起来也是不错的。。。。

这个是开始界面,鼠标点击事件触发开始游戏。

Java飞机大战源码 java飞机大战素材_Image

游戏界面,计分,得命

Java飞机大战源码 java飞机大战素材_Image_02

鼠标移出框外时触发 mouseExited 事件,暂停

Java飞机大战源码 java飞机大战素材_Image_03

游戏结束

Java飞机大战源码 java飞机大战素材_java_04

编程经验:

先看功能是否是某个对象的行为
    若是对象的行为,则写在相应的类中
    若不是对象的行为,则写在ShooGame中

整个代码:github https://github.com/libai2017/Java-demo (JDK版本1.7,编辑器Eclipse)