Java基础练习项目【飞机大战】

  • Post author:
  • Post category:java




飞机大战



游戏需求

  • 用户通过鼠标操作一架英雄机,英雄机自动发射子弹,攻击自上而下飞行的敌机,击落敌机获得奖励,不同敌机奖励不同,英雄机生命归零则死亡,游戏结束。
  • 界面信息:

    • 得分信息、英雄机剩余生命信息、英雄机、敌机、子弹、天空图
    • 初始界面,用户点击界面,游戏开始,鼠标移至窗口外面,游戏暂停,英雄机死亡后,显示Game Over界面,再次点击鼠标,恢复初始界面
  • 敌机及奖励类型:

    • 小敌机:击落得1分
    • 大敌机:击落得3分
    • 小蜜蜂:击落奖励(英雄机获得40火力值或者1条生命)
    • 敌机被击落后,显示爆炸效果后消失
  • 英雄机:

    • 初始生命值:3
    • 初始火力值:1
    • 攻击模式:单发/双发,默认单发,击落小蜜蜂后,切换为双发攻击模式
  • 其它:



开发文档



需求分析

fields/method World Sky Hero Bullet BigAirplane Airplane Bee
WIDTH
HEIGTH
START
RUNNNING
PAUSE
GAME_OVER
score
maxScore
LIFE
DEAD
REMOVE
width
heigth
x
y
speed
y1
life
fire
xspeed
awardType
getImage()
生成对象
移动
得分
奖励
碰撞



超纲代码



主窗口

	/**
	 * 飞机大战,世界窗口
	 */
	private static final long serialVersionUID = 1L;

	public static final int WIDTH = 400;
	public static final int HEIDHT = 800;

	public static void main(String[] args) {
		JFrame frame = new JFrame();
		World world = new World();
		frame.add(world);

		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.setSize(WIDTH, HEIDHT);
		frame.setLocationRelativeTo(null);
		frame.setVisible(true);

		world.action();// 运行游戏入口
	}

	private void action() {
		// TODO Auto-generated method stub

	}



画界面

	@Override
  public void paint(Graphics g) {
  	g.drawImage(sky.getImages(), sky.x, sky.y, null);// 将天空图片画到界面上
  	}
  }



获取图片文件

public static BufferedImage readImage(String fileName) {
		try {
			BufferedImage img = ImageIO.read(FlyingObject.class.getResource(fileName));
			return img;
		} catch (Exception e) {
			e.printStackTrace();
			throw new RuntimeException();
		}
	}



游戏入口(监听器、定时器)

  /**
   * 游戏入口
   */
  public void action() {
  	// 监听器
  	MouseAdapter msAdapter = new MouseAdapter() {
  	};
  	this.addMouseListener(msAdapter);
  	this.addMouseMotionListener(msAdapter);

  	// 定时器
  	Timer timer = new Timer();
  	int intervel = 10;// 定时周期,单位毫秒
  	timer.schedule(new TimerTask() {
  		@Override
  		public void run() {// 要运行的程序
  		}
  	}, intervel, intervel);
  }



开发步骤



创建对象类

  1. 创建World类,画窗口(复制超纲代码)

    1. import JFrame+JPanel
    2. 设计World类继承JPanel
    3. 复制粘贴main()方法中的所有代码
    4. 修改frame.setSize()中的参数为常量WIDTH,HEIGHT
  2. 创建了6个对象类,设计FlyingObject超类,6个对象类继承超类
  3. FlyingObject定义共用属性,6个对象定义特定属性



基础数据初始化

  1. 给FlyingObject设计两个构造方法,6个派生类分别调用
对象 x y speed
Sky 400 800 0 0 1
Hero 97 139 140 400
Bullet 8 20 x y 3
BigAirplane 66 89 随机 -高 2
Bee 60 51 随机 -高 2
Airplane 48 50 随机 -高 2



设计Images图片工具类

  1. 静态块



画对象:

  1. 想画对象需要去获取对象的图片,每个对象都得获取图片, 意味着获取图片行为为共有行为,所以设计在超类FlyingObject中, 每个对象获取图片的行为都是不一样的,所以设计为抽象方法 —-在FlyingObject中设计抽象方法getImage()用于获取对象的图片
  2. 获取图片时需要考虑对象的状态,因为在不同状态下获取的图片是不同的, 每个对象都有状态,意味着状态为共有属性,所以设计在FlyingObject超类中, 状态一般都设计为常量,同时设计变量state来表示当前状态 —-在FlyingObject中设计LIFE、DEAD、REMOVE常量,state变量表示当前状态 有了状态常量还不够,还需要去判断对象的状态,每个对象都得判断, 意味着判断状态为共有行为,所以设计在超类FlyingObject中, 每个对象判断状态的行为都是一样的,所以设计为普通方法 —-在FlyingObject中设计isLife()、isDead()、isRemove()来判断对象的状态
  3. 重写getImage()获取对象图片:

    1. 天空Sky: 返回sky图片即可
    2. 子弹Bullet:

      1. 若活着的,直接返回bullet图片即可
      2. 若死了的,直接删除(不返回图片)
    3. 英雄机Hero:

      1. 若活着的,返回heros[0]和heros[1]来回切换
    4. 小敌机Airplane:

      1. 若活着的,返回airs[0]即可
      2. 若死了的,依次返回airs[1]到airs[4],4后删除
    5. 大敌机BigAirplane:

      1. 若活着的,返回bairs[0]即可
      2. 若死了的,依次返回bairs[1]到bairs[4],4后删除
    6. 小蜜蜂Bee:

      1. 若活着的,返回bees[0]即可
      2. 若死了的,依次返回bees[1]到bees[4],4后删除
  4. 图片有了,就可以开画了,在World类中重写paint()画方法



英雄机随鼠标移动

  1. 英雄机随着鼠标移动为英雄机的行为,所以在Hero中设计moveTo()来实现英雄机随着鼠标移动
  2. 英雄机随着鼠标动为事件触发的,所以在侦听器中重写mouseMoved()鼠标移动事件 在mouseMoved()中: 获取鼠标的x和y坐标,调用Hero的moveTo()实现英雄机随着鼠标移动



敌机/子弹入场:enterAction()

  1. 随机生成一个敌机,构建getEnemy()方法,用于生成敌机,进行延时生成处理,0.4秒生成一个
  2. 对敌人数组进行扩容,并将生成的敌机插入数组中

  3. 构建getBullet()方法,用于生成子弹,根据英雄机的火力值,确认单双发,火力值>0,说明击落过小蜜蜂,获得双发火力,延时处理,0.3秒生成一个

  4. 对子弹数组进行扩容,并将子弹插入数组中



敌机和子弹移动:stepAction()

  1. 飞行物移动为派生类所共有的行为,所以在FlyingObject类中设计step()实现飞行物移动,默认自上而下移动,派生类不同的自行重写
  2. 飞行物移动为定时发生的,所以在run()中调用stepAction()实现飞行物移动 在stepAction()中:天空动,遍历敌人敌人动,遍历子弹子弹动



画分和画命:

  1. 在Hero中设计getLife()获取英雄机的命数
  2. 在World类的paint()中: 画分和画命



碰撞检测:checkHitAction()

  1. 设计EnemyScore得分接口,Airplane和BigAirplane实现接口 设计EnemyAward奖励接口,Bee实现接口
  2. 在FlyingObject中设计isHit()检测碰撞、goDead()飞行物去死,在Hero中设计addLife()增命、addFire()增火力,在Hero中设计subtractLife()英雄机减命、clearFire()清空火力值
  3. 子弹与敌人的碰撞:

    1. 遍历子弹得子弹,遍历敌人得敌人,判断若都活着并且撞上了:敌人去死、子弹去死 判断若敌人能得分,则强转为得分接口, 则玩家得分 判断若敌人为奖励,则强转为奖励接口, 则获取奖励类型,最后根据不同的奖励类型来获取不同的奖励
  4. 英雄机与敌人的碰撞

    1. 遍历敌人得敌人,判断若都活着并且撞上了:敌人去死、英雄机减命、英雄机清空火力值



删除越界和remove对象:deleteAction()

  1. 在FlyingObject中设计isOutside()检测敌机是否越界 在Bullet中重写isOutside()检测子弹是否越界
  2. 遍历所有敌人/子弹,判断若敌人/子弹越界了或者处于remove状态,则将最后一个元素赋值到越界位置,缩容



检测游戏结束:checkGameOverAction()

  1. 判断若英雄机的命数<=0,则表示游戏结束,…



画游戏状态控制

  1. 在World中设计START、RUNNING、PAUSE、GAME_OVER状态常量,usestatus变量表示当前状态 在Images中设计start、pause、gameover状态图片,静态块中初始化 在World的paint()中,设置在不同的状态下画不同的状态图
  2. 设置那一堆action为仅在运行状态下执行 设置英雄机随着鼠标移动为仅在运行状态下执行
  3. 重写mouseClicked()鼠标点击事件: 启动时变运行,游戏结束时先清理现场再变启动 重写mouseExited()鼠标移出事件: 运行变暂停 重写mouseEntered()鼠标移入事件: 暂停变运行



扩展需求列表

更多需求改动,详见

https://gitee.com/qiaobilong/shoot

(内附源码哦)



版权声明:本文为QBL_user原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。