飞机大战项目

目录

飞机大战

抽象类FlyingObject

小飞机Airplane类

大飞机BigAirplane类

奖励机Bee类

奖励类型Award接口

获得分数Score接口

天空Sky类

英雄级Hero类

子弹Bullet类

游戏开始World类


飞机大战


抽象类FlyingObject

package cn.tedu.shoot;

import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Random;

import javax.imageio.ImageIO;

//飞机大战的父类飞行物
public abstract class FlyingObject {
	// 定义三种状态常量:活着、死了、消失
	public static final int LIFE = 0;
	public static final int DEAD = 1;
	public static final int REMOVE = 2;
	// 定义当前对象的状态属性
	protected int state = LIFE;// 初始默认活着

//所有子类共有的属性和方法、
	protected int width;
	protected int height;
	protected int x;
	protected int y;

	// 小敌机,大敌机,奖励机使用的构造
	public FlyingObject(int width, int height) {
		this.width = width;
		this.height = height;
		// 所有敌级的y轴都是负高度,因为出现在屏幕上方
		y = -height;
		Random ran = new Random();
		// x轴是从左侧开始到屏幕的宽度减去低级的宽度的随机数
		x = ran.nextInt(400 - this.width);
	}

	// 子弹,天空,英雄机的构造

	public FlyingObject(int width, int height, int x, int y) {
		this.width = width;
		this.height = height;
		this.x = x;
		this.y = y;
	}

	public void show() {
		System.out.println("宽:" + width + ",高" + height);
		System.out.println("x:" + x + ",y:" + y);
	}

	// 读取图片,将项目中保存的图片,转换成java内存的图片
	public static BufferedImage readImage(String fileName) {
		try {
			// 根据文件名将图片获取并赋值给img
			BufferedImage img = ImageIO.read(FlyingObject.class.getResource(fileName));
			return img;
		} catch (IOException e) {
			e.printStackTrace();
			throw new RuntimeException();
		}

	}

	// 定义一个单位移动的抽象方法
	public abstract void step();

	// 判断状态的方法
	// 判断是否活着
	public boolean isLife() {
		return state == LIFE;
	}

	// 判断是否死了
	public boolean isDead() {
		return state == DEAD;
	}

	// 判断是否消失
	public boolean isRemove() {
		return state == REMOVE;
	}

	// 获得图片的抽象方法
	public abstract BufferedImage getImage();

	// 绘制图片到窗体
	public void paintObject(Graphics g) {
		g.drawImage(getImage(), x, y, null);
	}

	// 判断出界的方法
	public boolean isOutOfBounds() {

		return y > World.HEIGHT;
	}

	// 判断碰撞的方法
	// 判断的是this(当前对象)是否和参数中的飞行物碰撞了
	public boolean hit(FlyingObject f) {
		// this.想象为子弹,f想象为一架敌机
		int x1 = f.x - this.width;// 左侧点
		int x2 = f.x + f.width;// 右侧点

		int y1 = f.y - this.height;// 上方点
		int y2 = f.y + f.height;// 下方点

		return this.x > x1 && this.x < x2 && this.y > y1 && this.y < y2;

	}

	// 改变飞行物状态为DEAD的方法
	public void goDead() {
		state = DEAD;
	}

}

小飞机Airplane类

package cn.tedu.shoot;

import java.awt.image.BufferedImage;

public class Airplane extends FlyingObject implements Score{
	// 保存小敌机相关图片的数组
	private static BufferedImage[] images;
	static {
		// 初始化图片数组
		images = new BufferedImage[5];
		// 第一张图是小敌机图
		images[0] = readImage("airplane0.png");
		// 循环加载4张爆炸图
		for (int i = 1; i < images.length; i++) {
			images[i] = readImage("bom" + i + ".png");
		}
	}

	// 速度
	private int step;

	public Airplane() {
		super(48, 50);
		step = 5;
	}

	public void show() {
		super.show();
		System.out.println("速度:" + step);
	}

	public void step() {
		// 小敌机向下移动
		y += step;
	}

	int index = 1;

	public BufferedImage getImage() {
		BufferedImage img = null;
		// 如果活着返回第一张图
		if (isLife()) {
			img = images[0];
		} else if (isDead()) {
			// 如果死了获得爆炸图片
			img = images[index];
			index++;
			//如果爆炸完毕,将小飞机设置为消失
			if(index==images.length) {
				state=REMOVE;
			}
		}
		return img;
	}

	public int getScore() {
		//击中小敌机得1分
		return 1;
	}
}

大飞机BigAirplane类

package cn.tedu.shoot;

import java.awt.image.BufferedImage;

public class BigAirplane extends FlyingObject implements Score{

	private static BufferedImage[] images;
	static {
		images = new BufferedImage[5];
		images[0] = readImage("bigairplane0.png");
		for (int i = 1; i < images.length; i++) {
			images[i] = readImage("bom" + i + ".png");
		}
	}

	// 速度
	private int step;

	public BigAirplane() {
		super(66, 89);
		step = 5;
	}

	public void show() {
		super.show();
		System.out.println("速度:" + step);
	}

	public void step() {
		y += step;
	}

	int index = 1;

	public BufferedImage getImage() {
		BufferedImage img = null;
		if (isLife()) {
			img = images[0];
		} else if (isDead()) {
			img = images[index];
			index++;
			if (index == images.length) {
				state = REMOVE;
			}

		}
		return img;
	}

	public int getScore() {
		//击中大敌机获得3分
		return 3;
	}
}

奖励机Bee类

package cn.tedu.shoot;

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

public class Bee extends FlyingObject implements Award{

	private static BufferedImage[] images;
	static {
		images = new BufferedImage[5];
		images[0] = readImage("bee0.png");
		for (int i = 1; i < images.length; i++) {
			images[i] = readImage("bom" + i + ".png");
		}
	}
	// 移动分方向
	private int xStep;// 左右移动
	private int yStep;// 上下移动

	// 奖励类型
	private int awardType;

	public Bee() {
		super(60, 51);
		xStep = 2;
		yStep = 2;
		Random ran = new Random();
		// 随机生成0和1存入奖励类型,用于击中敌机时获得不同奖励
		awardType = ran.nextInt(2);
	}

	public void show() {
		super.show();
		System.out.println("x速度:" + xStep + "\ny速度:" + yStep);
		System.out.println("奖励类型:" + awardType);
	}

	public void step() {
		x += xStep;
		y += yStep;
		// 如果奖励机碰撞了左右两侧的边界
		if (x <= 0 || x >= World.WIDTH - this.width) {
			// 修改它的移动方向
			xStep *= -1;
		}
	}
	int index = 1;

	public BufferedImage getImage() {
		BufferedImage img = null;
		if (isLife()) {
			img = images[0];
		} else if (isDead()) {
			img = images[index];
			index++;
			if (index == images.length) {
				state = REMOVE;
			}
		}
		return img;
	}

	public int awardType() {
		//返回当前奖励机的奖励类型值
		return this.awardType;
	}
}

奖励类型Award接口

package cn.tedu.shoot;

//击中获得奖励的接口
public interface Award {
//定义奖励常量
	int LIFE=0;
	int DOUBLE_FIRE=1;
//定义获得的奖励
	public int awardType();
	
}

获得分数Score接口

package cn.tedu.shoot;
//击中敌机后获得分数的接口
public interface Score {
	//返回一个分数
	public int getScore();
}

天空Sky类

package cn.tedu.shoot;

import java.awt.Graphics;
import java.awt.image.BufferedImage;

public class Sky extends FlyingObject {
	private static BufferedImage image;
	static {
		image = readImage("background.png");
	}

	private int step;

	// 第二张背景图y轴
	private int y1;

	public Sky() {
		super(400, 700, 0, 0);
		y1 = -700;
		step = 1;
	}

	public void show() {
		super.show();
		System.out.println("y1:" + y1 + "\nstep:" + step);
	}

	public void step() {
		// 两张图都要移动
		y += step;
		y1 += step;
		// 当任何一张图片移动出窗体时,都要重置到窗体上方
		if (y >= World.HEIGHT) {
			y = -World.HEIGHT;
		}
		if (y1 >= World.HEIGHT) {
			y1 = -World.HEIGHT;
		}
	}

	public BufferedImage getImage() {
		return image;
	}
	public void paintObject(Graphics g) {
		g.drawImage(getImage(),x,y,null);
		g.drawImage(getImage(),x,y1,null);
	}
}

英雄级Hero类

package cn.tedu.shoot;

import java.awt.image.BufferedImage;

public class Hero extends FlyingObject {

	private static BufferedImage[] images;
	static {
		images = new BufferedImage[2];
		images[0] = readImage("hero0.png");
		images[1] = readImage("hero1.png");
	}

	// 英雄机的生命值
	private int life;

	// 火力值
	private int doubleFire;

	public Hero() {
		super(97, 139, 152, 410);
		life = 3;
		doubleFire = 0;
	}

	public void show() {
		super.show();
		System.out.println("生命值:" + life + "\n火力值:" + doubleFire);
	}

	// 空实现
	public void step() {

	}

	int index = 0;

	public BufferedImage getImage() {
		BufferedImage img = null;
		// 任何数值取余2之后只可能得0或1
		img = images[index % 2];
		// index++后下次获得另一张图
		index++;
		return img;
	}

	// 英雄级开炮方法
	public Bullet[] shoot() {
		Bullet[] bs = null;
		// 为了方便我们使用英雄机宽度的1/4定义一个变量
		int len = this.width / 4;
		// 英雄机开炮分单排和双排
		if (doubleFire > 0) {
			// 双排
			bs = new Bullet[2];
			bs[0] = new Bullet(this.x + len, this.y - 20);
			bs[1] = new Bullet(this.x + 3 * len, this.y - 20);
			doubleFire--;
		} else {
			// 单排
			bs = new Bullet[1];
			bs[0] = new Bullet(this.x + 2 * len, this.y - 20);
		}
		return bs;
	}

	// 英雄机移动方法
	public void moveTo(int x, int y) {
		// 英雄机中心x轴到鼠标x轴
		this.x = x - this.width / 2;
		// 英雄机中心y轴到鼠标y轴
		this.y = y - this.height / 2;
	}

	// 获得英雄机的生命值
	public int getLife() {
		return this.life;
	}

	// 增加英雄机的生命值
	public void addLife() {
		this.life++;
	}

	// 增加英雄机的火力值
	public void addDoubleFire() {
		this.doubleFire += 20;
	}

	// 英雄机减命
	public void subLife() {
		this.life--;
	}

	// 清空火力值
	public void clearDoubleFire() {
		this.doubleFire = 0;
	}
}

子弹Bullet类

package cn.tedu.shoot;

import java.awt.image.BufferedImage;

public class Bullet extends FlyingObject {
	private static BufferedImage image;
	static {
		image = readImage("bullet.png");
	}

	private int step;

	// 子弹初始位置根据英雄机决定,编写代码时不知道英雄机的位置,
	// 所以只能使用参数代替
	public Bullet(int x, int y) {
		super(8, 20, x, y);
		step = 20;
	}

	public void show() {
		super.show();
		System.out.println("速度:" + step);
	}

	public void step() {
		// 子弹向上移动
		y -= step;
	}

	public BufferedImage getImage() {
		BufferedImage img = null;
		if (isLife()) {
			img = image;
		} else if (isDead()) {
			// 子弹不会爆炸,死了直接变为消失状态
			state = REMOVE;
		}
		return img;
	}

	// 子弹向上出界的判断,重写父类的方法
	public boolean isOutOfBounds() {
		return y < -this.height;
	}
}

游戏开始World类

package cn.tedu.shoot;

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.swing.JFrame;
import javax.swing.JPanel;

//继承JPanel表示World类是一个窗口
public class World extends JPanel {
	// 声明两个常量,窗口宽和高
	public static final int WIDTH = 400;
	public static final int HEIGHT = 700;
	// 定义游戏的分数
	private int score;
	// 定义游戏状态常量
	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 static BufferedImage startImg;
	private static BufferedImage pauseImg;
	private static BufferedImage gameOverImg;

	static {
		startImg = FlyingObject.readImage("start.png");
		pauseImg = FlyingObject.readImage("pause.png");
		gameOverImg = FlyingObject.readImage("gameover.png");
	}
	// 声明飞机大战中出现的对象
	// 将组建声明为成员变量
	// 所有方法均能访问
	Hero hero = new Hero();
	Sky sky = new Sky();
	FlyingObject[] enemy = {};
	Bullet[] bullets = {};

	public void start() {
		// 编写鼠标的监听器
		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:// 如果是结束状态
					state = START;// 点击进入开始状态
					// 重置游戏
					score = 0;
					hero = new Hero();
					sky = new Sky();
					bullets = new Bullet[0];
					enemy = new FlyingObject[0];
					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);

		// 定义计时器时间间隔
		int interval = 20;
		// 声明计时器
		Timer timer = new Timer();
		// 声明计时器任务
		TimerTask task = new TimerTask() {
			// 匿名内部类
			public void run() {
				if (state == RUNNING) {
					// 周期运行的内容
					// 调用飞行物移动方法
					moveAction();
					// 调用敌机进场方法
					enterAction();
					shootAction();
					outOfBoundsAction();
					bulletHitAction();
					heroHitAction();
					gameOverAction();
					// System.out.println(enemy.length);
					// System.out.println(bullets.length);
					// 重绘所有对象
				}
				repaint();
			}
		};
		// 启动计时器周期运行
		timer.schedule(task, interval, interval);
	}

	// 判断英雄机和敌机碰撞的方法
	public void heroHitAction() {
		// 遍历所有敌机
		for (int i = 0; i < enemy.length; i++) {
			FlyingObject f = enemy[i];
			// 判断是否和当前敌机相撞
			if (f.isLife() && hero.hit(f)) {
				// 撞死敌机
				f.goDead();
				// 英雄机减命,清活力
				hero.subLife();
				hero.clearDoubleFire();
			}
		}
	}

	// 判断游戏结束的方法
	public void gameOverAction() {
		// 如果生命值小于等于0,游戏结束
		if (hero.getLife() <= 0) {
			state = GAME_OVER;
		}
	}

	// 判断子弹和敌机碰撞的方法
	public void bulletHitAction() {
		// 遍历所有子弹
		for (int i = 0; i < bullets.length; i++) {
			Bullet b = bullets[i];// 提取子弹
			// 遍历所有敌机
			for (int j = 0; j < enemy.length; j++) {
				FlyingObject f = enemy[j];// 提取敌机
				// 判断子弹是否集中敌机
				if (b.isLife() && f.isLife() && b.hit(f)) {
					b.goDead();// 子弹死
					f.goDead();// 敌机死
					// 判断敌机是不是得分的
					if (f instanceof Score) {
						Score s = (Score) f;
						score += s.getScore();
					}
					// 判断敌机是不是有奖励
					if (f instanceof Award) {
						Award a = (Award) f;
						// 获得这架奖励机的奖励数值
						int num = a.awardType();
						switch (num) {
						case Award.LIFE:// 如果是0
							hero.addLife();// 加命
							break;
						case Award.DOUBLE_FIRE:// 如果是1
							hero.addDoubleFire();// 加火力值
							break;
						}
					}
				}

			}
		}
	}

	// 检测出界的方法
	public void outOfBoundsAction() {
		// 没有出界的元素下标,同时保存没出界元素的数量
		int index = 0;
		// 定义保存未出界元素的数组
		FlyingObject[] fs = new FlyingObject[enemy.length];
		// 遍历所有敌机,检测是否出界
		for (int i = 0; i < enemy.length; i++) {
			// 提取当前元素
			FlyingObject f = enemy[i];
			// 判断是否未出界并且没移除
			if (!f.isOutOfBounds() && !f.isRemove()) {
				fs[index] = f;// 放入新数组
				index++;// 下标加1
			}
		}
		// 数组缩容
		enemy = Arrays.copyOf(fs, index);
		index = 0;
		Bullet[] bs = new Bullet[bullets.length];
		for (int i = 0; i < bullets.length; i++) {
			Bullet b = bullets[i];
			if (!b.isOutOfBounds() && !b.isRemove()) {
				bs[index] = b;
				index++;
			}
		}
		bullets = Arrays.copyOf(bs, index);
	}

	// 子弹进场方法
	int shootIndex = 1;

	public void shootAction() {
		if (shootIndex % 5 == 0) {
			// 调用英雄机的开炮方法
			Bullet[] bs = hero.shoot();
			// 对bullets数组进行扩容
			bullets = Arrays.copyOf(bullets, bullets.length + bs.length);
			// 将英雄机发射的新炮弹放到扩容后的数组最后位置
			System.arraycopy(bs, 0, bullets, bullets.length - bs.length, bs.length);

		}
		shootIndex++;
	}

	// 敌机进场方法
	int enterIndex = 1;

	public void enterAction() {
		if (enterIndex % 20 == 0) {
			// 生成一架敌机
			FlyingObject fo = nextEnemy();
			// 扩容当前敌机数组
			enemy = Arrays.copyOf(enemy, enemy.length + 1);
			// 将生成的敌机放入扩容后数组的最后
			enemy[enemy.length - 1] = fo;
		}
		enterIndex++;
	}

	// 飞行物移动的方法
	public void moveAction() {
		sky.step();// 天空移动
		// 敌机移动
		for (int i = 0; i < enemy.length; i++) {
			enemy[i].step();
		}
		// 子弹移动
		for (int i = 0; i < bullets.length; i++) {
			bullets[i].step();
		}
	}

	// 随机产生敌机的方法
	public FlyingObject nextEnemy() {
		Random ran = new Random();
		FlyingObject fo = null;
		int num = ran.nextInt(100);
		if (num < 40) {// 40%几率小敌机
			fo = new Airplane();
		} else if (num < 80) {// 40%几率大敌机
			fo = new BigAirplane();
		} else {// 20%几率奖励机
			fo = new Bee();
		}
		return fo;

	}

	// 重写了父类JPanel中的paint方法,方法名不能错
	public void paint(Graphics g) {
		// 先画背景,再画其他的
		sky.paintObject(g);
		hero.paintObject(g);
		for (int i = 0; i < enemy.length; i++) {
			enemy[i].paintObject(g);
		}
		for (int i = 0; i < bullets.length; i++) {
			bullets[i].paintObject(g);
		}

		// 显示分数和生命值
		g.drawString("SCORE:" + score, 20, 20);
		g.drawString("LIFE:" + hero.getLife(), 20, 45);
		// 根据游戏状态绘制状态图片
		switch (state) {
		case START:
			g.drawImage(startImg, 0, 0, null);
			break;
		case PAUSE:
			g.drawImage(pauseImg, 0, 0, null);
			break;
		case GAME_OVER:
			g.drawImage(gameOverImg, 0, 0, null);
		}

	}

	public static void main(String[] args) {
		World w = new World();
		// 实例化一个窗口
		JFrame f = new JFrame("飞机大战");
		// 将World类设置到窗口中
		f.add(w);
		// 首先设置窗口的宽和高
		f.setSize(400, 700);
		// 设置窗口关闭时程序结束
		f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		// 设置窗口居中
		f.setLocationRelativeTo(null);
		// 显示窗口,自动调用上面的paint
		f.setVisible(true);

		w.start();

	}

}

需要图片告诉我!

你可能感兴趣的:(飞机大战,Java,OOP)