Java开发《飞机大战》

《飞机大战》是一款由腾讯开发的经典射击类游戏。
下面介绍用Java开发《飞机大战》的步骤。
源码:https://download.csdn.net/download/weixin_44360895/18271800?spm=1001.2014.3001.5503
创建一个普通的Java项目,编写好类以及导入相关贴图:
在这里插入图片描述
主要代码如下:

1、奖励类

package com.bzyd.shoot;
/**表示奖励,提供奖励类型属性及获取奖励类型的方法,蜜蜂实现此方法*/
public interface Award {
	int DOUBLE_FIRE = 0;//0表示双倍火力
	int LIFE = 1;//1表示1条命
	/**获取奖励类型,0或1*/
	int getType();
}

2、敌人类

package com.bzyd.shoot;
/**敌人类,提供获取分数的方法,敌飞机实现此接口。*/
public interface Enemy {
	/**获取分数*/
	int getSroce();
}

3、飞行物类

package com.bzyd.shoot;

import java.awt.image.BufferedImage;

/**飞行物类,英雄机、敌飞机、蜜蜂、子弹都继承此类*/
public abstract class FlyingObject {
	protected int x;//x坐标
	protected int y;//y坐标
	protected int width;//宽度
	protected int height;//高度
	protected BufferedImage image;//图片,表示贴图

	public int getX() {
		return x;
	}
	public void setX(int x) {
		this.x = x;
	}
	public int getY() {
		return y;
	}
	public void setY(int y) {
		this.y = y;
	}
	public int getWidth() {
		return width;
	}
	public void setWidth(int width) {
		this.width = width;
	}
	public int getHeight() {
		return height;
	}
	public void setHeight(int height) {
		this.height = height;
	}
	public BufferedImage getImage() {
		return image;
	}
	public void setImage(BufferedImage image) {
		this.image = image;
	}

	/**
	 * 飞行物移动一步(体现多态性)
	 */
	public abstract void step();

	/**
	 * 检查飞行物(敌机、蜜蜂)是否被子弹击中
	 * bee.x < bullet.x < bee.x + width
	 * &&
	 * bee.y < bullet.y < bee.y + height
	 * @param bullet 子弹对象
	 * @return true 表示被击中了
	 */
	public boolean shootBy(Bullet bullet) {
		int x = bullet.x;//子弹x坐标
		int y = bullet.y;//子弹y坐标
		return x > this.x && x < this.x + width && y > this.y && y < this.y + height;
	}

	/**
	 * 检查是否越界(体现多态性)
	 * @return true 出界与否
	 */
	public abstract boolean outOfBounds();
}

4、敌飞机类

package com.bzyd.shoot;

import java.util.Random;

/**敌飞机类,继承FlyingObject类,实现Enemy接口*/
public class Airplane extends FlyingObject implements Enemy {
	private int speed = 2;
	/**实现获取分数的方法*/
	@Override
	public int getSroce() {
		return 5;
	}

	public Airplane() {
		image = ShootGame.airplane;
		width = image.getWidth();
		height = image.getHeight();
		Random r = new Random();
		y = -height;
		x = r.nextInt(ShootGame.WIDTH-width);
	}
	@Override
	public void step() {//移动
		y += speed;
	}
	@Override
	public boolean outOfBounds() {
		return y>ShootGame.HEIGHT;
	}
}

5、蜜蜂类

package com.bzyd.shoot;

import java.util.Random;

/**蜜蜂类,继承FlyingObject,实现Award接口*/
public class Bee extends FlyingObject implements Award {
	private int xSpeed = 1;//x方向移动速度
	private int ySpeed = 2;//y方向移动速度
	private int awardType;//奖励类型

	@Override
	public int getType() {
		return awardType;
	}

	public Bee() {
		image = ShootGame.bee;//继承来的image属性就是ShootGame类中加载得到的静态Bee的图片
		width = image.getWidth();//蜜蜂的宽度
		height = image.getHeight();//蜜蜂的高度
		Random r = new Random();
		y = -height;//y坐标赋值
		x = r.nextInt(ShootGame.WIDTH - width);//x坐标赋值
		awardType = r.nextInt(2);//给奖励类型赋值
	}

	@Override
	public void step() {
		x += xSpeed;//x方向移动
		y += ySpeed;//y方向移动
		if (x > ShootGame.WIDTH - width) {//如果到达右边界就向左移动
			xSpeed = -1;
		}
		if (x < 0) {//如果到达左边界就向右移动
			xSpeed = 1;
		}
		
	}
	@Override
	public boolean outOfBounds() {
		return y > ShootGame.HEIGHT;
	}
}

6、英雄机类

package com.bzyd.shoot;

import java.awt.image.BufferedImage;
/**英雄机类,是飞行物,继承FlyingObject类*/
public class Hero extends FlyingObject {
	protected BufferedImage[] images = {};//表示Hero的贴图,有两张组成
	protected int index = 0;//两张图片进行交替显示的计数
	
	private int doubleFire;//双倍火力子弹数量
	private int life;//增命的数量
	
	public Hero() {
		life = 3;
		doubleFire = 0;
		image = ShootGame.hero0;
		width = image.getWidth();
		height = image.getHeight();
		images = new BufferedImage[] {ShootGame.hero0,ShootGame.hero1};
		x = 150;
		y = 400;
	}

	@Override
	public void step() {
		if (images.length > 0) {
			image = images[index++/10%images.length];
		}
	}

	/**射击(产生子弹)*/
	public Bullet[] shoot() {
		int xStep = width/4;
		int yStep = 20;//子弹到飞机的位置
		if (doubleFire > 0) {//双倍火力
			Bullet[] bullets = new Bullet[2];//双倍火力一次发射2颗子弹
			bullets[0] = new Bullet(x+xStep, y-yStep);//子弹发射点1
			bullets[1] = new Bullet(x+3*xStep,y-yStep);//子弹发射点2
			doubleFire -= 2;//子弹数量不断减少
			return bullets;
		}else {//单倍火力
			Bullet[] bullets = new Bullet[1];//单倍火力一次发射1颗子弹
			bullets[0] = new Bullet(x+2*xStep, y-yStep);
			return bullets;
		}
	}

	/**鼠标移动(设定鼠标点为英雄的中心位置)*/
	public void moveTo(int x,int y) {
		this.x = x-width/2;//英雄机的x=鼠标的x-width/2
		this.y = y-height/2;//英雄机的y=鼠标的y-height/2
	}

	/**获取双倍火力*/
	public void addDoubleFire() {
		doubleFire += 40;
	}

	/**增命*/
	public void addLife() {
		life++;
	}

	/**获取英雄机的命数*/
	public int getLife() {
		return life;
	}
	
	@Override
	public boolean outOfBounds() {
		return false;
	}

	/**减命*/
	public void subtractLife() {
		life--;
	}

	/**重置双倍火力*/
	public void setDoubleFire(int doubleFire) {
		this.doubleFire = doubleFire;
	}

	/**检测英雄机是否与飞行物碰撞*/
	public boolean hit(FlyingObject other) {
		int x1 = other.x - this.width/2;
		int x2 = other.x + other.width + this.width/2;
		int y1 = other.y - this.height/2;
		int y2 = other.y + other.height + this.height/2;
		return this.x + this.width/2 > x1 && this.x + this.width/2 < x2
				&& this.y + this.height/2 > y1
				&& this.y + this.height/2 < y2;
	}
}

7、子弹类

package com.bzyd.shoot;
/**子弹类,属于飞行物,继承FlyingObject类*/
public class Bullet extends FlyingObject {
	private int speed = 3;//子弹速度
	public Bullet(int x,int y) {
		this.x = x;
		this.y = y;
		image = ShootGame.bullet;
	}
	@Override
	public void step() {
		y -= speed;//子弹向上移动
	}
	@Override
	public boolean outOfBounds() {
		return y < -height;
	}
}

8、主类

package com.bzyd.shoot;
import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Arrays;
import java.util.Random;
import java.util.Timer;
import java.util.TimerTask;

/**
 * 飞机大战
 */
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;
	
	public static BufferedImage background;//背景图片
	public static BufferedImage start;//游戏开始图片
	public static BufferedImage airplane;//敌飞机图片
	public static BufferedImage bee;//蜜蜂图片
	public static BufferedImage bullet;//子弹图片
	public static BufferedImage hero0;//英雄机图片1
	public static BufferedImage hero1;//英雄机图片2
	public static BufferedImage pause;//暂停图片
	public static BufferedImage gameover;//游戏结束图片
	
	private FlyingObject[] flyings = {};//敌机蜜蜂数组
	private Bullet[] bullets = {};//子弹数组
	private Hero hero = new Hero();//英雄机
	private Timer timer;//定时器
	private int intervel = 10;//时间间隔10毫秒
	private int score = 0;//计分
	private int state;//游戏状态

	/**加载图片*/
	static {
		try {
			//ImageIO.read(URL input),得到BufferedImage对象
			//类对象.getResource("文件名"),在当前类的包下查找文件,得到URL对象
			background = ImageIO.read(ShootGame.class.getResource("/background.png"));
			start = ImageIO.read(ShootGame.class.getResource("/start.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"));
			pause = ImageIO.read(ShootGame.class.getResource("/pause.png"));
			gameover = ImageIO.read(ShootGame.class.getResource("/gameover.png"));
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	/**
	 * 随机生成飞行物
	 * @return 飞行物对象
	 */
	public static FlyingObject nextOne() {
		Random r = new Random();
		int type = r.nextInt(20);//[0,20)
		if (type == 0) {
			return new Bee();
		}else {
			return new Airplane();
		}
	}


	/**重构paint方法(绘画组件,是Jpanel的父类JComponent中的方法)*/
	@Override
	public void paint(Graphics g) {
		g.drawImage(background,0,0,null);//画背景图
		paintHero(g);//画英雄机
		paintBullets(g);//画子弹
		paintFlyingObjects(g);//画飞行物(敌机和蜜蜂)
		paintScore(g);//画分数和命
		paintState(g);//画游戏状态
	}

	/**画英雄机*/
	public void paintHero(Graphics g) {
		g.drawImage(hero.getImage(),hero.getX(),hero.getY(),null);
	}

	/**画子弹*/
	public void paintBullets(Graphics g) {
		for (int i = 0; i < bullets.length; i++) {
			Bullet b = bullets[i];
			g.drawImage(b.getImage(),b.getX(),b.getY(),null);
		}
	}

	/**画飞行物*/
	public void paintFlyingObjects(Graphics g) {
		for (int i = 0; i < flyings.length; i++) {
			FlyingObject f = flyings[i];
			g.drawImage(f.getImage(),f.getX(),f.getY(),null);
		}
	}

	/**画分数和命数*/
	public void paintScore(Graphics g) {
		int x = 10;
		int y = 25;
		Font font = new Font(Font.SANS_SERIF, Font.BOLD, 14);
		g.setColor(new Color(0x3A3B3B));//设置画笔颜色
		g.setFont(font);//设置字体
		g.drawString("SCORE: "+score,x,y);//画分数
		y += 20;
		g.drawString("LIFE: "+hero.getLife(), x, y);//画命
	}

	/**画游戏状态*/
	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;
		}
	}

	/**实现飞行物入场:即每调用该方法40次就随机生成一个飞行物放入flyings数组中*/
	int flyEnterIndex = 0;//飞行物入场计数
	public void enterAction() {
		flyEnterIndex++;
		if (flyEnterIndex%40 == 0) {//400毫秒=10*40
			FlyingObject obj = nextOne();//随机生成一个飞行物
			flyings = Arrays.copyOf(flyings,flyings.length+1);//扩容
			flyings[flyings.length-1] = obj;//放在最后
		}
	}

	/**所有飞行物:敌机、蜜蜂、子弹、英雄机的移动*/
	public void stepAction() {
		/**飞行物移动*/
		for (int i = 0; i < flyings.length; i++) {
			FlyingObject f = flyings[i];
			f.step();
		}
		/**子弹移动*/
		for (int i = 0; i < bullets.length; i++) {
			Bullet b = bullets[i];
			b.step();
		}
		/**英雄机移动*/
		hero.step();
	}

	/**实现英雄机射击,即每调用该方法30次就发射一次子弹,并将发射的子弹存储到bullets数组中*/
	int shootIndex = 0;//射击计数
	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 bangAction() {
		for (int i = 0; i < bullets.length; i++) {
			bang(bullets[i]);//所有子弹逐个检测
		}
	}
	private void bang(Bullet bullet) {
		int index = -1;//击中的飞行物的索引
		for (int i = 0; i < flyings.length; i++) {//逐个飞行物检测
			FlyingObject obj = flyings[i];
			if (obj.shootBy(bullet)) {//判断是否击中
				index = i;//记录被击中的飞行物的索引
				break;//如果当前子弹击中了,就结束循环,外循环判断下一枚子弹
			}
		}
		if (index != -1) {//如果与击中的飞行物
			FlyingObject one = flyings[index];//记录被击中的飞行物
			FlyingObject temp = flyings[index];//与最后一个交换
			flyings[index] = flyings[flyings.length-1];
			flyings[flyings.length-1] = temp;
			flyings = Arrays.copyOf(flyings,flyings.length-1);//缩容,删除最后一个被击中的
			//检测被击中的飞行物的类型,如果是敌机就算分,如果是蜜蜂就给予奖励(增命或者双倍火力)
			if (one instanceof Enemy) {
				Enemy e = (Enemy)one;
				score += e.getSroce();
			}
			if (one instanceof Award) {
				Award a = (Award)one;
				int type = a.getType();
				switch (type) {
				case Award.DOUBLE_FIRE:
					hero.addDoubleFire();
					break;
				case Award.LIFE:
					hero.addLife();
					break;
				}
			}
		}
	}

	/**删除越界飞行物及子弹*/
	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;//重置为0
		Bullet[] bulletLives = new Bullet[bullets.length];
		//用来存储活着的子弹
		for (int i = 0; i < bullets.length; i++) {
			Bullet b = bullets[i];
			if (! b.outOfBounds()) {
				bulletLives[index] = b;//不越界的留着
				index++;
			}
		}
		bullets = Arrays.copyOf(bulletLives, index);//将不越界的子弹留着
	}

	/**判断游戏是否结束*/
	public boolean isGameOver() {
		for (int i = 0; i < flyings.length; i++) {
			FlyingObject obj = flyings[i];
			int index = -1;
			if (hero.hit(obj)) {//检测英雄机与飞行物是否碰撞
				hero.subtractLife();
				hero.setDoubleFire(0);
				index = i;
			}
			if (index != -1) {
				FlyingObject temp = flyings[index];
				flyings[index] = flyings[flyings.length-1];
				flyings[flyings.length-1] = temp;
				flyings = Arrays.copyOf(flyings,flyings.length-1);
			}
		}
		return hero.getLife() <= 0;
	}

	/**检查游戏是否已经结束*/
	public void checkGameOverAction() {
		if (isGameOver()) {
			state = GAME_OVER;
		}
	}

	/**实现10毫秒入场一个飞机或者蜜蜂,并使所有飞行物移动一步,最后重画页面*/
	public void action() {//启动执行代码
		//鼠标监听事件
		MouseAdapter event = new MouseAdapter() {
			@Override
			public void mouseMoved(MouseEvent e) {//鼠标移动事件
				if (state == RUNNING) {//运行时移动英雄机
					int x = e.getX();
					int y = e.getY();
					hero.moveTo(x, y);
				}
			}
			@Override
			public void mouseEntered(MouseEvent e) {//鼠标进入事件
				if (state == PAUSE) {//暂停时运行
					state = RUNNING;
				}
			}
			@Override
			public void mouseExited(MouseEvent e) {//鼠标退出事件
				if (state != GAME_OVER) {
					state = PAUSE;//游戏未结束,则设置为暂停
				}
			}
			@Override
			public void mouseClicked(MouseEvent e) {//鼠标点击事件
				switch (state) {
				case START:
					state = RUNNING;
					break;
				case GAME_OVER://游戏结束,重新开始
					flyings = new FlyingObject[0];
					bullets = new Bullet[0];
					hero = new Hero();
					score = 0;
					state = START;
					break;
				}
			}
		};
		this.addMouseListener(event);//处理鼠标点击操作
		this.addMouseMotionListener(event);//处理鼠标滑动操作
		
		timer = new Timer();
		timer.schedule(new TimerTask() {//使用匿名内部类创建一个任务TimerTask
			@Override
			public void run() {
				if (state == RUNNING) {
					enterAction();//飞行物入场(实例方法可以直接调用实例方法)
					stepAction();//走一步
					shootAction();//射击
					bangAction();//检测击中
					outOfBoundsAction();//删除越界飞行物与子弹
					checkGameOverAction();//检查游戏是否结束
				}
				repaint();//重画页面,调用paint()方法
			}
		}, intervel, intervel);//安排指定的任务从指定的延迟后开始进行重复的固定延迟执行。
	}


	/**主方法*/
	public static void main(String[] args) {
		JFrame frame = new JFrame("飞机大战");//创建游戏窗口实例
		ShootGame shootGame = new ShootGame();//面板对象
		frame.add(shootGame);//添加面板到窗口
		frame.setSize(WIDTH, HEIGHT);//设置窗口初始大小
		frame.setAlwaysOnTop(true);//初始位置总是在最上面
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//设置关闭窗口就结束进程(必须)
		frame.setLocationRelativeTo(null);//设置窗口初始位置
		frame.setVisible(true);//设置窗体是否显示
		shootGame.action();//启动执行
	}
}

编译后:
在这里插入图片描述
运行主类ShootGame的main()方法即可启动游戏:
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Alex·Guangzhou

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值