飞机大战(简单步骤)

一、项目对象如下:

ShootGame
|-- 英雄机 Hero
|-- 敌飞机 Airplane
|-- 蜜蜂 Bee
|-- 子弹 Bullet

二、游戏界面显示

一,新建工程和包
首先,新建名为shoot的Java工程;然后,在工程下的src目录下新建包com.cetc.shoot,将所需要图拷贝到该包下
在这里插入图片描述
二,创建抽象父类Flyingobject
分析出英雄机、敌飞机、子弹以及蜜蜂都有x, y,width以及height属性,因此,将这些属性抽象到父类Flyingobject中。另外,它们在界面上都以图片的形式显示,因此在父类Flyingobject中,添加image属性,表示它们的贴图,并提供上述5个属性的getter和setter方法, FlyingObject类的代码如下所示:

package com.cetc.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();
	
	/**
	 *	 检查当前飞行物体是否被子弹(x,y)击(shoot)中,
	 * @param bullet 子弹对象
	 * @return true表示击中
	 */
	public boolean shootBy(Bullet bullet) {
		int x = bullet.x;
		int y = bullet.y;
		return this.x<x && x<this.x+width 
			   && 
			   this.y<y && y<this.y+height;
	}
	
	
	/** 检查飞行物是否出界 */
	public abstract boolean outOfBounds();
}

三,创建接口Enemy,实现接口的类为敌人
创建接口Enemy ,表示敌人。如果子弹击中敌飞机,英雄机可以获取分数,因此,在Enemy接口中提供获取分数的方法,代码如下所示:

package com.cetc.shoot;
/**
 * 	敌人 ,可以有分数
 *
 */
public interface Enemy {
	/**
	 * 敌人的分数
	 */
	public int getScore();
}

四,创建接口Award,实现接口的类表示奖励


public interface Award {
	public int DOUBLE_FIRE = 0; //火力
	public int LIFE = 1; //命
	
	/** 获取奖励类型 0为火力 1为命 */
	public int getType();
}

五,新建类Airplane,表示敌飞机
新建类Airplane ,表示敌飞机。敌飞机属于飞行物,因此,继承自Flyingobject类;敌飞机也属于敌人,因此,需要实现Enemy接口。敌飞机可以向下移动,因此有移动的速度作为属性,代码如下所示:

package com.cetc.shoot;

/** 敌机: 是飞行物,也是敌人 */
public class Airplane extends FlyingObject implements Enemy {
	
	private int speed = 2; //走步的步数
	
	/** 构造方法 */
	public Airplane(){
		image = ShootGame.airplane; //图片
		width = image.getWidth();   //宽
		height = image.getHeight(); //高
		x = (int) (Math.random()*(ShootGame.WIDTH-this.width))
	}
	/** 重写getScore() */
	public int getScore(){
		return 5;
	}
	
	/** 重写step() */
	public void step(){
		y+=speed; //y加(向下)
	}
	
	/** 重写outOfBounds() */
	public boolean outOfBounds(){
		return this.y>=ShootGame.HEIGHT; //敌机的y>=屏幕的高,即为越界
	}
}

六,新建类Bee,表示蜜蜂
新建类Bee ,表示蜜蜂。蜜蜂属于飞行物,因此,继承自Flyingobject类;击中蜜蜂可以获得奖励,因此,需要实现Award接口,并且有奖励类型作为属性。蜜蜂可以左右移动、向下移动,因此有移动的速度作为属性,代码如下所示:

package com.cetc.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; //奖励类型
	
	/** 构造方法 */
	public Bee(){
		image = ShootGame.bee; //图片
		width = image.getWidth();   //宽
		height = image.getHeight(); //高
		y = -height; //y:负的蜜蜂的高
		Random rand = new Random(); //创建随机数对象
		x = rand.nextInt(ShootGame.WIDTH-this.width); //x:0到(屏幕宽-蜜蜂宽)之内的随机数
		awardType = rand.nextInt(2); //奖励类型为0到1之间的随机数

	/** 重写getType() */
	public int getType(){
		return awardType; 
	}
	/** 重写step() */
	public void step(){
		x+=xSpeed; //x加(向左或向右)
		y+=ySpeed; //y加(向下)
		if(x>=ShootGame.WIDTH-this.width){ //x>=(屏幕宽-蜜蜂宽)时,x减(向左)
			xSpeed = -1;
		}
		if(x<=0){ //x<=0时,x加(向右)
			xSpeed = 1;
		}
	}
	
	/** 重写outOfBounds() */
	public boolean outOfBounds(){
		return this.y>=ShootGame.HEIGHT; //蜜蜂的y>=屏幕的高,即为越界
}
}

七,新建类Bullet,表示子弹
新建类Bullet,表示子弹。子弹属于飞行物,因此,继承自Flyingobject类;子弹可以向上移动,因此有移动的速度作为属性,代码如下所示:

package com.cetc.shoot;
/** 子弹: 是飞行物 */
public class Bullet extends FlyingObject {
	private int speed = 3; //走步步数

	/** 构造方法   x:子弹的x坐标   y:子弹的y坐标*/
	public Bullet(int x,int y){
		image = ShootGame.bullet; //图片
		this.x = x; //x坐标:与英雄机有关
		this.y = y; //y坐标:与英雄机有关
	}
	
	/** 重写step() */
	public void step(){
		y-=speed; //y减(向上)
	}
	

	/** 重写outOfBounds() */
	public boolean outOfBounds(){
		return this.y<=-this.height; //子弹的y<=负的子弹的高,即为越界
  }
}

八,新建Hero,表示英雄机
新建类Hero,表示英雄机。英雄机属于飞行物,因此,继承自Flyingobject类;英雄机发出子弹,击中蜜蜂可以获取双倍火力或增命,因此,将双倍火力的子弹数量和命的数虽作为该类的属性,代码如下所示:

package com.cetc.shoot;

import java.awt.image.BufferedImage;
/** 英雄机: 是飞行物 */
public class Hero extends FlyingObject {
	private int life; //命
	private int doubleFire; //火力值
	private BufferedImage[] images = {}; //图片切换数组
	private int index = 0; //协助图片切换
	
	/** 构造方法 */
	public Hero(){
		image = ShootGame.hero0; //图片
		width = image.getWidth();   //宽
		height = image.getHeight(); //高
		x = 150; //x坐标:固定的值
		y = 400; //y坐标:固定的值
		life = 3; //命数为3
		doubleFire = 0; //火力值为0(单倍火力)
		images = new BufferedImage[]{ShootGame.hero0,ShootGame.hero1}; //两张图片切换
	}
	
	/** 重写step() */
	public void step() {
		if(images.length>0) {
			image = images[index++/10%images.length];
		}
	}
	
	/** 英雄机发射子弹 */
	public Bullet[] shoot(){
		int xStep = this.width/4; //1/4英雄机的宽
		int yStep = 20; //固定的值
		if(doubleFire>0){ //双倍
			Bullet[] bs = new Bullet[2]; //两发子弹
			bs[0] = new Bullet(this.x+1*xStep,this.y-yStep); //x:英雄机的x+1/4英雄机的宽 y:英雄机的y-20
			bs[1] = new Bullet(this.x+3*xStep,this.y-yStep); //x:英雄机的x+3/4英雄机的宽 y:英雄机的y-20
			doubleFire-=2; //发射一次双倍火力时,火力值减2
			return bs;
		}else{ //单倍
			Bullet[] bs = new Bullet[1]; //一发子弹
			bs[0] = new Bullet(this.x+2*xStep,this.y-yStep); //x:英雄机的x+2/4英雄机的宽 y:英雄机的y-20
			return bs;
		}
}
/** 英雄机随着鼠标移动  x:鼠标的x坐标  y:鼠标的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:鼠标的y-1/2英雄机的高
	}
	
	/** 英雄机增火力 */
	public void addDoubleFire(){
		doubleFire+=40; //火力值增40
	}
	
	/** 增命 */
	public void addLife(){
		life++; //命数增1
	}
	
	/** 获取命 */
	public int getLife(){
		return life; //返回命数
	}

	/** 减命 */
	public void subtractLife(){
		life--;
	}
	
	public void setDoubleFire(int doubleFire) {
		this.doubleFire = doubleFire;
	}

	/** 重写outOfBounds() */
	public boolean outOfBounds(){
		return false; //永不越界
	}
	
	/** 检测英雄机与敌人的碰撞 this:英雄机 other:敌人 */
	public boolean hit(FlyingObject other){
		int x1 = other.x-this.width/2; //x1:敌人的x-1/2英雄机的宽
		int x2 = other.x+other.width+this.width/2; //x2:敌人的x+敌人的宽+1/2英雄机的宽
		int y1 = other.y-this.height/2; //y1:敌人的y-1/2英雄机的高
		int y2 = other.y+other.height+this.height/2; //y2:敌人的y+敌人的高+1/2英雄机的高
		int x = this.x+this.width/2;  //x:英雄机的x+1/2英雄机的宽
		int y = this.y+this.height/2; //y:英雄机的y+1/2英雄机的高
		
		return x>x1 && x<x2
			   &&
			   y>y1 && y<y2; //x在x1和x2之间,并且,y在y1和y2之间,即为撞上了
	}
}

九,新建ShootGame,加载图片

新建类ShootGame ,该类继承自JPanel ,在该类中,使用静态常量定义面板的宽和高并使用Imagero的read方法加载图片,代码如下所示:
在ShootGame类中添加以下属性和常量
在ShootGame类中添加checkGameoverAction方法,该方法用于判断游戏是否已经结束,如果已经结束,G设置为GAME-OVER
修改ShootGame类的action方法,添加鼠标点击、移入、退出等操作的状态处理
在ShootGame类中添加paintstate方法,画出START, PAUSE以及GAMEOVER
ShootGame类中paint方法中,调用paintstate方法

package com.cetc.shoot;

import java.awt.Color;
import java.awt.Font;
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.imageio.ImageIO;
import javax.swing.JPanel;

//主程序类
public class ShootGame extends JPanel{
	public static final int WIDTH = 400;  //窗口宽
	public static final int HEIGHT = 654; //窗口高
	
	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;      //英雄机0
	public static BufferedImage hero1;      //英雄机1

private Hero hero = new Hero(); //英雄机对象
	private FlyingObject[] flyings = {}; //敌人(敌机+小蜜蜂)数组
	private Bullet[] bullets = {}; //子弹数组
	
	private Timer timer;	//定时器
	private int intervel = 1000/100;	//时间间隔(毫秒)
	
	private int score = 0; //玩家的得分
	
	private int state;
	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 ShootGame(){
	}
	
	
	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();
		}
	}
}
  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
package cn.feike.shoot; import java.awt.Graphics; import java.awt.image.BufferedImage; public abstract class FlyingObject { protected double x;//物体的x坐标 protected double y;//物体的y坐标 protected double width;//物体的宽 protected double heigth;//物体的高 protected BufferedImage image;//当前正在显示的图片 protected int index = 0;//图片数组下标序号,子类中使用 protected double step;//飞行物每次(1/24秒)移动的距离 protected int life;//命 protected int state;//飞行物的状态 public static final int ACTIVE=0;//活着状态 public static final int DEAD=1;//死亡状态 public static final int REMOVE=2;//回收状态 //默认构造器 public FlyingObject() { life = 1; state = ACTIVE; } //有参构造器 public FlyingObject(double width,double heigth){ this();//调用无参数的构造器,必须写在第一行. this.x = (int)(Math.random()*(480-width)); this.y = -heigth; this.width = width; this.heigth = heigth; step = Math.random()*3+0.8;//初始化step为[0.8,3.8)之间的数 } //重写toString方法 public String toString() { return x+","+y+","+width+","+heigth+","+image; } //重写paint,方便子类对象的使用 public void paint(Graphics g) { g.drawImage(image, (int)x, (int)y, null);//绘制图片 } //飞行物移动的move方法 /** * 重构了move,方法实现播放销毁动画功能 */ public void move(){ if(state == ACTIVE){ y += step; return ; } if(state == DEAD){ //从子类对象中获取下一张照片 BufferedImage img = nextImage(); if(img == null){ state = REMOVE;//没有照片则回收 }else{ image = img;//否则把子类的图片传给image } //越界则销毁 if(y>=825){ state = REMOVE; } } } /** * 子类中必须有的方法,返回下一个要播放的照片引用, * 如果返回null表示没有可播放的照片了. */ protected abstract BufferedImage nextImage(); /** * 飞行物被打了一下 */ public void hit(){ if(life>0){ life--; } if(life==0){ state = DEAD; } } /** * 碰撞检测的方法 * 检测物体的位置是否在碰撞的范围内. * (子弹是否在飞行物的碰撞范围内) */ public boolean duang(FlyingObject obj){ //this(x,y,w,h) //obj(x,y,w,h) double x1 = this.x - obj.width; double x2 = this.x + this.width; double y1 = this.y - obj.width; double y2 = this.y + this.heigth; return x1<obj.x&&obj;.x<x2&&y1;<obj.y&&obj;.y<y2; } /** 重构FlyingObject,添加了状态检查方法 */ /** 检查飞行物死了吗 */ public boolean isDead(){ return state == DEAD; } /** 检查飞行物是否活动的 */ public boolean isActive(){ return state == ACTIVE; } /** 检查飞行是否可以被删除*/ public boolean canRemove(){ return state == REMOVE; } /** 飞行物添加"去死"方法*/ public void goDead(){ if(isActive()){ state = DEAD; } } }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值