简易版--Java飞机大战

目录

 

射击游戏需求:

所参与的角色: 英雄机、子弹、小敌机、大敌机、小蜜蜂、天空

角色间的关系:

设计规则:

设计类与游戏对象:

需求设计:

代码实现:


射击游戏需求:

所参与的角色: 英雄机、子弹、小敌机、大敌机、小蜜蜂、天空

角色间的关系:

1) 英雄机发射子弹,分单倍火力和双倍火力

2) 子弹射击敌人(小敌机、大敌机、小蜜蜂),若射击到了:

2.1) 子弹直接消失、敌人先爆破再消失

2.2) 子弹打掉小敌机----------玩家得1分

子弹打掉大敌机----------玩家得3分

子弹打掉小蜜蜂----------英雄机得奖励(1条命、40火力值)

3) 敌人(小敌机、大敌机、小蜜蜂)可以和英雄机撞,若撞上了:

3.1) 敌人先爆破再消失

3.2) 英雄机减1条命,同时,清空火力值---英雄机命数为0时,游戏结束

4) 英雄机、子弹、小敌机、大敌机、小蜜蜂都在天空上飞

设计规则:

1. 将所有派生类共有的属性和行为,抽到超类中-------------抽共性

2.派生类的行为都一样,设计为普通方法派生类的行为都不一样,设计为抽象方法

3.将部分派生类共有的行为,抽到接口中接口是对继承单根型的扩展-------------实现多继承

 

设计类与游戏对象:

对象: 英雄机、子弹、小敌机、大敌机、小蜜蜂、天空

对象类: Hero、Bullet、Airplane、BigAirplane、Bee、Sky

超类:FlyingObject超类,6个对象类继承超类

图片工具类:Images(封装与图片相关的操作/方法)

接口:Enemy(得分接口),Award( 奖励接口)

窗口:World类 

需求设计:

1.构造法:在FlyingObject中设计2个构造方法,6个对象类分别调用

2.移动方法:在6个对象类中重写step()移动

3.访问控制:给类中成员添加访问控制修饰符

4.画窗口:在World类中,测试,调用即可.

5.画对象:

1) 想画对象得需要获取对象的图片,每个对象都能获取图片,意味获取图片为对象共有的行为,

所以将获取图片行为设计在超类中,每个对象获取图片的行为都是不一样的,所以设计为抽象方法,

在FlyingObject中设计抽象方法getImage()用于获取对象的图片

2) 获取图片时需要去考虑对象的状态,因为在不同状态下获取的图片是不一样的,

每个对象都有状态,意味着状态为对象所共有的属性,所以设计在超类中,

状态一般都是固定的,所以都设计为常量,同时设计一个 state变量来表示当前的状态

,在FlyingObject 中设计LIFE、DEAD、REMOVE三个常量,设计state变量表示当前状态

状态有了,还需要去判断状态,每个对象都得判断,意味着判断状态为共有行为,

所以设计在超类中,每个对象判断状态是方式都是一样的,所以设计为普通方法

,在FlyingObject中设计isLife()、isDead()、isRemove()来判断对象的状态

3) 派生类重写getImage()获取图片:

3.1) 天空Sky,直接返回sky图片即可

3.2) 子弹Bullet:

3.2.1) 若活着的,直接返回bullet图片即可

3.2.2) 若死了的,直接删除(不返回图片)

3.3) 英雄机Hero:

3.3.1) 若活着的,直接返回heros[0]和heros[1]的来回切换

3.4) 小敌机Airplane:

3.4.1) 若活着的,直接返回airs[0]图片即可

3.4.2) 若死的了,返回airs[1]到airs[4]的爆破图,4后删除(不返回图片)

3.5) 大敌机BigAirplane:

3.4.1) 若活着的,直接返回bairs[0]图片即可

3.4.2) 若死的了,返回bairs[1]到bairs[4]的爆破图,4后删除(不返回图片)

3.4) 小蜜蜂Bee:

3.4.1) 若活着的,直接返回bees[0]图片即可

3.4.2) 若死的了,返回bees[1]到bees[4]的爆破图,4后删除(不返回图片)

4) 图片有了就可以开画了,因为是需要往窗口上画,所以在窗口World类中重写paint()方法实现画对象

6.敌人入场:

1) 敌人对象是由窗口产生的,所以在World中设计nextOne()生成敌人对象

2) 敌人入场为定时发生的,所以在 run()中调用enterAction()实现敌人入场

在enterAction中:

每400毫秒,获取敌人对象obj, enemies扩容,将obj添加到enemies的最后一个元素上

不要忘记: 在run()中调用enterAction()的下面调用repaint()方法重画

7.子弹入场:

1) 子弹是由英雄机发射出来的,所以在Hero中设计shoot()生成子弹对象

2) 子弹入场为定时发生的,所以在run()中调用shootAction()实现子弹入场

在shootAction中:

每300毫秒,获取子弹数组对象bs,bullets扩容,将bs追加到bullets的末尾

8.飞行物移动:

1) 飞行物移动为派生类所共有的行为,所以在超类FlyingObject中设计抽象方法step()移动,派生类中重写

2) 飞行物移动为定时发生的,所以在run()中调用 stepAction()实现飞行物移动

在stepAction中:

天空动,遍历敌人敌人动,遍历子弹子弹动

9.英雄机随着鼠标移动:

1) 英雄机随着鼠标动为英雄机的行为,所以在Hero中设计moveTo()实现英雄机随着鼠标动

2) 英雄机随着鼠标移动为事件触发的,所以在侦听器中重写mouseMoved()鼠标移动事件

在mouseMoved()中:

获取鼠标的x和y坐标,调用Hero的moveTo()方法

10.删除越界的敌人和子弹:

1) 在FlyingObject中设计outOfBounds()检测敌人是否越界

在Bullet中重写outOfBounds()检测子弹是否越界

2) 删除越界的敌人和子弹为定时发生的,所以在run中调用outOfBoundsAction()删除越界的敌人和子弹

在outOfBoundsAction()中:

声明不越界敌人/子弹数组,遍历enemies/bullets数组,判断若不越界,则将对象装到不越界数组中

最后将不越界数组复制到enemies/bullets数组中

11.接口设计:

              1)设计Enemy得分接口,Airplane和BigAirplane实现Enemy接口,击中小敌机/大敌机,得1分/3分.

               2)设计Award奖励接口,Bee实现Award接口,击中小蜜蜂随机奖励:生命值加一/火力值加40双倍火力

12.敌人与子弹的碰撞:

1) 在 FlyingObject中设计hit()检测敌人与子弹的碰撞、goDead()飞行物去死

在Hero中设计addLife()增命、addFire()增火力

2) 敌人与子弹的碰撞为定时发生的,所以在run()中调用bulletBangAction()实现敌人与子弹的碰撞

在bulletBangAction()中:

遍历子弹得子弹,遍历敌人得敌人,判断若都活着并且撞上了:

子弹去死、敌人去死

判断若为Enemy分,则玩家得分

若为Award奖励,则英雄机得奖励

13.画分和画命:

1) 在Hero中设计getLife()获取英雄机的命数

2) 在World类的paint()中: 画分和画命

14.敌人与英雄机的碰撞:

1) 借用FlyingObject中的hit()碰撞检测、goDead()去死

在Hero中设计subtractLife()减命、clearFire()清空火力值

2) 敌人与英雄机的碰撞为定时发生的,所以在run()中调用heroBangAction()实现敌人与英雄机的碰撞

在heroBangAction中:

遍历敌人得敌人,判断若都活着并且撞上了:

敌人去死、英雄机减命、英雄机清空火力值

15.检测游戏结束:

1) 借助于Hero的getLife()获取命数

2) 检测游戏结束为定时发生的,所以在run()中调用checkGameOverAction()检测游戏结束

在checkGameOverAction()中:

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

16.画状态:

1) 在World中设计四个状态常量,同时设计state变量表示当前状态,默认为START(启动状态)

在Images中设计start、pause、gameover三个状态图片,在static块中赋值

在World类的paint()中设计在不同的状态下画不同的图片

2) 设计run()中那一堆action,仅在运行状态时执行

设计英雄机随着鼠标动,仅在运行状态时执行

3) 重写mouseClicked()鼠标点击: 启动状态时变运行状态,游戏结束状态时先清理现场,再变启动状态

重写mouseExited()鼠标移出: 运行状态变为暂停状态

重写mouseEntered()鼠标移入: 暂停状态变为运行状态

(注:每一次功能的实现都要不断测试调试,防止报错.)

代码实现:

FlyingObject:

package cn.tedu.shoot;
import java.awt.image.BufferedImage;
import java.util.Random;

/**飞行物*/
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;     //x 坐标
	protected int y;     //y 坐标
	
	/**专门给小敌机 ,大敌机,小蜜蜂提供的 */
	public FlyingObject(int width,int height){//传2个参是因为敌人只有width 和height 不一样
		this.width=width;
		this.height=height;
		Random rand =new Random();//随机数对象
		x =rand.nextInt(World.WIDTH-width);//0到(窗口宽-敌机宽)的随机数
		y=-height;//负的小敌机的高
		
	}
	
	/**专门给 英雄机, 天空 ,子弹提供*/
	public FlyingObject(int width,int height,int x,int y){//传四个参是因为他们的width,height,x,y都不一样
		this.width=width;
		this.height=height;
		this.x=x;
		this.y=y;
		
	}
	/**飞行物移动*/
	public abstract void step();
	
	/**获取对象的图片方法 */
	public abstract BufferedImage getImage();
	//公开 抽象  返回 值图片
	
	/**判断对象是否活着*/
	public boolean isLife(){	
		return state ==LIFE;//当前状态为LIFE,表示对象是活着的返回true 否则false
	}
	
	/**判断对象是否死了着*/
	public boolean isDead(){	
		return state ==DEAD;//当前状态为DEAD,表示对象是死着的返回true 否则false
	}
	
	/**判断对象是否删除的*/
	public boolean isRemove(){	
		return state ==REMOVE;//当前状态为REMOVE,表示对象是删除的返回true 否则false
	}
	
	/**检测敌人是否越界*/
	public boolean outOfBounds(){
		return this.y>= World.HEIGHT;//敌人的y大于等于窗口的 高 即为越界了
	}
	
	/**判断检测敌人 与 子弹/ 英雄机  this:敌人  other :子弹/英雄机*/
	public boolean hit(FlyingObject other){
		int x1 = this.x - other.width;//x1:敌人的x- 子弹/英雄机的宽
		int x2 = this.x + this.width; //x2: 敌人的x+敌人的width
		int y1 = this.y - other.height;//y1: 敌人的y - 子弹/英雄机的高
		int y2 = this.y + this.height;// y2: 敌人的 y + 敌人的高
		int x = other.x;
		int y = other.y;
		// x在x1 和 x2之间 并且 y在y1和y2之间  即为装上了
		return x>=x1 && x<=x2 && y>=y1 &&y<=y2;
	}
	
	/**飞行物去死*/
	public void goDead(){
		state = DEAD;//将当前状态修改为 DEAD死
	}
	
}

Airplane:

package cn.tedu.shoot;

import java.awt.image.BufferedImage;

/** 小敌机 是飞行物,也能得分*/
public class Airplane extends FlyingObject implements Enemy{
	
	private int speed;//移动速度
	
	/**构造方法*/ //Airplane a=new Airplane
	public Airplane(){
		super(48,50);
		speed=2;
	}
	
	/**重写 step() 移动*/
	public void step(){
		y+=speed;
	}

	private int index=1;//爆破图的下标
	/**重写 getImage() 获取图片方法*/
	public  BufferedImage getImage(){//每10毫秒走一次
		if(isLife()){//活着的
			return Images.airs[0];//返回airs第一张图片
		}else if(isDead()){//死了的
			BufferedImage img = Images.airs[index++];
			if(index==Images.airs.length){
				state = REMOVE;
			}
			return img;
			/*
			 * index= 1;
			 * 10M airs[1] index=2 返回airs[1]
			 * 20M airs[2] index=3 返回airs[2]
			 * 30M airs[3] index=4;返回airs[3]
			 * 40M airs[4] index=5(REMOVE) 返回airs[4]
			 * 50M  因为REMOVE状态 ,所以不走isDead()里面了,直接返回null 
			 */
		}
		return null;//删除状态时,不返回图片
	}
	
	/**重写getScore()得分方法*/
	public int getScore(){
		return 1;//打掉小敌机,玩家得1分;
	}

}

BigAirplane

package cn.tedu.shoot;

import java.awt.image.BufferedImage;

/** 大敌机 是飞行物,也能得分*/
public class BigAirplane extends FlyingObject implements Enemy{
	
	private int speed;//移动速度 
	
	/**构造方法*/
	public BigAirplane(){
		super(66,89);
		speed=2;
	}
	
	/**重写 step() 移动*/
	public void step(){
		y+=speed;//y+为(向下移动
	}
	
	private int index=1;//爆破图的下标
	/**重写 getImage() 获取图片方法*/
	public  BufferedImage getImage(){//每10毫秒走一次
		if(isLife()){//活着的
			return Images.bairs[0];//返回bairs第一张图片
		}else if(isDead()){//死了的
			BufferedImage img = Images.bairs[index++];
			if(index==Images.bairs.length){
				state = REMOVE;
			}
			return img;
		}
		return null;//删除状态时,不返回图片
	}
	
	/**重写getScore()得分方法*/
	public int getScore(){
		return 3;//打掉小敌机,玩家得3分;
	}
	
}

Bee:

package cn.tedu.shoot;

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

/** 小蜜蜂 是飞行物, 也是奖励*/
public class Bee extends FlyingObject implements Award{
	
	private int xSpeed;//x坐标移动速度
	private int ySpeed;//y坐标移动速度
	private int awardType;//奖励类型
	
	/**构造方法*/
	public Bee(){
		super(60,51);
		xSpeed=1;
		ySpeed=2;
		Random rand =new Random();//随机数对象
		awardType=rand.nextInt(2);//0-1之内的随机数
	}

	/**重写 step() 移动*/
	public void step(){
		x+=xSpeed;//x+(向左向右)
		y+=ySpeed;//y+一定向下
		//若x<=0  或者 x>=窗口宽-小蜜蜂宽,说明
		if(x<=0||x>=World.WIDTH-this.width){
			xSpeed*=-1;//切换方向(正变负 ,负变正)
		}
	}
	
	private int index=1;//爆破图的下标
	/**重写 getImage() 获取图片方法*/
	public  BufferedImage getImage(){//每10毫秒走一次
		if(isLife()){//活着的
			return Images.bees[0];//返回airs第一张图片
		}else if(isDead()){//死了的
			BufferedImage img = Images.bees[index++];
			if(index==Images.bees.length){
				state = REMOVE;
			}
			return img;
		}
		return null;//删除状态时,不返回图片
	}
	
	/**重写getAwardType()获取奖励类型*/
	public int getAwardType(){
		return awardType;//返回奖励类型
	}
	
}

Hero:

package cn.tedu.shoot;

import java.awt.image.BufferedImage;

/**英雄机:是飞行物*/
public class Hero extends FlyingObject {
	
	private int life;//生命
	private int fire;//火力值
	
	/**构造方法*/
	public Hero(){
		super(97,139,140,400);
		life=3;
		fire=0;
	}
	
	/**重写 step() 移动*/
	public void step(){
		
	}
	
	private int index=0;
	/**重写getImage方法*/
	public BufferedImage getImage(){
		if(isLife()){//若活着
			return Images.heros[index++%Images.heros.length];//heros[0]和heros[1]之间来来回回切换
		}                             //写活 数组长度
		return null;////保证程序一定有返回值
	}
	
	
	/**英雄机发射子弹(生成子弹对象)*/
	public Bullet[] shoot(){	
		int xStep = this.width/4;//1/4英雄级的宽
		int yStep = 20; //固定20
		if(fire>0){//双
			Bullet[] bs= new Bullet[2];//2发子弹
			bs[0]= new Bullet(this.x+1*xStep,this.y-yStep);
			bs[1]= new Bullet(this.x+3*xStep,this.y-yStep);
			fire-=2;//发射一次双倍火力 则火力值减2
			return bs;
		}else{//单倍火力
			Bullet[] bs= new Bullet[1];//1发子弹
			// x: 英雄级x+2/4英雄机的宽  y:英雄机的y-固定20
			bs[0]= new Bullet(this.x+2*xStep,this.y-yStep);
			return bs;
		}		
	}
	
	/**英雄机随着鼠标动           x/y 为鼠标坐边*/
	public void  moveTo(int x,int y){
		this.x = x-this.width/2;//英雄机的x = 鼠标x- 1/2英雄机的宽
		this.y = y-this.height/2;////英雄机的y = 鼠标x- 1/2英雄机的高
	}
	
	/**英雄机增命*/
	public void addLife(){
		life++;//命数增1
	}
	/**获取英雄机命*/
	public int getLife(){
		return life;//获取命
	}
	/**英雄机减命*/
	public void subtractLife(){
		life--;//命数减1
	}
	/**英雄机增火力值*/
	public void addFire(){
		fire+=40;//火力值增40
	}
	/***/
	public void clearFire(){
		fire=0;//火力值归0
	}
	
}

Sky:

package cn.tedu.shoot;
/**天空  是飞行物*/

import java.awt.Image;
import java.awt.image.BufferedImage;
public class Sky extends FlyingObject{
      //成员变量
	
	private int speed;//移动速度
	private int y1;//第二张图片的y坐标
	
	/**构造方法*/
	public Sky(){
		super(World.WIDTH,World.HEIGHT,0,0);
		speed=1;
		y1=-World.HEIGHT;
		
	}
	
	/**重写 step() 移动*/
	public void step(){
		y+=speed;//y+向下
		y1+=speed;//y1+向下
		if(y>=World.HEIGHT){//y>=窗口高,说明移除窗口
			y=-World.HEIGHT;//则设置y为负的窗口的高(挪到最上面去)
		}
		if(y1>=World.HEIGHT){//y1>=窗口高,说明移除窗口
			y1=-World.HEIGHT;//则设置y1为负的窗口的高(挪到最上面去)
		}
	}
	
	/**重写 getImage() 获取图片方法*/
	public  BufferedImage getImage(){
		return Images.sky;
	}
	
	/**获取天空y1坐标*/
	public int getY1(){
		return y1;//返回y1坐标
	}
}

Bullet: 

package cn.tedu.shoot;

import java.awt.image.BufferedImage;

/** 子弹 是飞行物*/
public class Bullet extends FlyingObject {
	
	private int speed;//移动速度
	
	/**构造的方法*/
	public Bullet(int x,int y){//Bullet b=new Bullet(100,200);
		super(8,20,x,y);
		speed=3;
	}

	/**重写 step() 移动*/
	public void step(){
		y-=speed;//y-为(向上移动
	}
	/**重写 getImage() 获取图片方法*/
	public  BufferedImage getImage(){
		if(isLife()){
			return Images.bullet;//活着
		}else if(isDead()){
			state=REMOVE;//若死了
		}
		return null;
	}
	
	/**重写outofBounds()--检测子弹是否越界*/
	public boolean outOfBounds(){
		return this.y<= - this.height;//敌人的y大于等于窗口的 高 即为越界了
	}
	
}

Images:

package cn.tedu.shoot;
import java.awt.image.BufferedImage;

import javax.imageio.ImageIO;
/**	图片工具类*/
public class Images {
   //公开的 静态的   数据类型 图片   变量名
	public static BufferedImage sky;//天空图片
	public static BufferedImage bullet;//子弹图片
	public static BufferedImage[] heros;//英雄图片
	public static BufferedImage[] airs;//小敌机图片
	public static BufferedImage[] bairs;//大敌机图片
	public static BufferedImage[] bees;//小蜜蜂图片
	
	public static BufferedImage start;//启动图
	public static BufferedImage pause;//暂停图
	public static BufferedImage gameover;//游戏结束图
	
	static{//初始化静态图片
		sky = readImage("background.png");
		bullet = readImage("bullet.png");
		heros =new BufferedImage[2];//两张图片
		heros[0]=readImage("hero0.png");
		heros[1]=readImage("hero1.png");
		
		airs=new BufferedImage[5];
		bairs=new BufferedImage[5];
		bees=new BufferedImage[5];
		
		airs[0]=readImage("airplane1.png");
		bairs[0]=readImage("bigairplane1.png");
		bees[0]=readImage("bee1.png");
		for(int i=1;i

Award:

package cn.tedu.shoot;
/**奖励接口*/
public interface Award {
	public int FIRE = 0;//火力值  默认..实际public static final int FIRE
	public int LIFE = 1;//命名  ..实际public static final int LIFE
	
	/**获取奖励类型(0 或1)*/
	public int getAwardType();
}

Enemy:

package cn.tedu.shoot;
/**得分接口*/
public interface Enemy {
	/**得分方法*/
	public int getScore();
}

World:

package cn.tedu.shoot;
import java.awt.event.MouseAdapter;//侦听器
import java.awt.event.MouseEvent;
import javax.swing.JFrame;//画框
import javax.swing.JPanel;//画板
import java.awt.Graphics;//绘制
import java.util.Random;
import java.util.Arrays;
import java.util.Timer;//定时器
import java.util.TimerTask;//定时任务
/** 整个窗口 */
public class World extends JPanel{// 测试类 窗口
	/**把游戏界面窗口宽 窗口高固定值*/
	public static final int WIDTH=400;//窗口宽
	public static final int HEIGHT=700;//窗口高
	
	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 Sky sky=new Sky();//天空对象
	private Hero hero=new Hero();//英雄机对象
	private FlyingObject[] enemies={};//敌人(小敌机,大敌机,小蜜蜂)数组
	private Bullet[] bullets={};//子弹数组
	
	/**创建敌人(小敌机 大敌机 小蜜蜂)对象*/
	public FlyingObject nextOne(){
		Random rand = new Random();//随机对象
		int type = rand.nextInt(20);//0-19
		if(type<5){//0-4时  返回小敌机
			return new Bee();
		}else if(type<12){//5-11返回小敌机
			return new Airplane();
		}else{//12到19生成大敌机
			return new BigAirplane();
		}
	}
	//敌人入场, 子弹入场 ,飞行物移动.
	
	private int enterIndex= 0;
	/**敌人(小敌机 大敌机 小蜜蜂)对象*/
	public void enterAction(){//没10毫秒走一次
		enterIndex++;//每10毫秒增1
		if(enterIndex%40==0){//每400(40*10)毫秒走一次
			FlyingObject obj = nextOne();//获取敌人数组
			enemies = Arrays.copyOf(enemies, enemies.length+1);//扩容
			enemies[enemies.length-1] = obj;//将敌人对象添加到最后一个元素上
		}
	}
	
	private int shootIndex=0;
	/**子弹入场*/
	public void shootAction(){//每10毫秒走一次
		shootIndex++;//每10毫秒增1
		if(shootIndex%30==0){//每300(30*10)毫秒走一次
			Bullet[] bs=hero.shoot();//获取英雄机发射出来的子弹对象
			bullets = Arrays.copyOf(bullets, bullets.length+bs.length);//扩容(bs长度为几就扩大几个容量)
			System.arraycopy(bs,0,bullets,bullets.length-bs.length,bs.length);//数组的追加			
		}
	}
	
	/**飞行物移动*/
	public void stepAction(){//每10毫秒
		sky.step();//天空动
		for(int i=0;i

 

 

 

 

 

 

 

 

:
 

 

 

你可能感兴趣的:(简易版--Java飞机大战)