飞机大战
前言
Java的学习来到了线程的阶段,接下来总结一下如何手撸一个线程飞机大战小游戏
到了这个阶段,我们就要有系统的思维了,制作一款这样的游戏,我们需要什么,我们的顺序又是什么。
首先借用一张图片,来看看我们的设计思路。
话不多说,开始动手。
我们注意到,无论是敌我飞机,还是子弹等等,都是飞行物,那么我们就可以用到继承的方法,写出一个飞行物的父类,之后的其他飞行物子类,都继承自它,然后重写里面的方法即可。
FlyingObject父类
如果你想设计这样一个类,该类包含一个特别的成员方法,该方法的具体实现由它的子类确定,那么你可以在父类中声明该方法为抽象方法。
Abstract关键字同样可以用来声明抽象方法,抽象方法只包含一个方法名,而没有方法体。
这里的飞行物的飞行方法和越界判断也许不一样,但是碰撞规则是一样的,所以我们写了两个abstract方法。
public abstract class FlyingObject {
protected BufferedImage image;// 图片命名--java包自有的
protected int width; // 宽
protected int height; // 高
protected int x; // x坐标
protected int y; // y坐标
// 飞行方法
public abstract void step();
// 越界方法
public abstract boolean outOfBounds();
// 敌人被子弹撞,传入Bullet类的对象,获取子弹的x,y坐标
public boolean shootBy(Bullet bullet) {
// this:敌人 other:子弹
int x1 = this.x;
int x2 = this.x + this.width;
int y1 = this.y;
int y2 = this.y + this.height;
int x = bullet.x;
int y = bullet.y;
//矩形检测原理
return x > x1 && x < x2 && y > y1 && y < y2;
}
}
在我们的游戏中,我们有计分原则,奖励原则,所以我们需要写一个方法,在所有的类中都可以使用,类似于我们的鼠标监听器一样,这里我们就要用到接口
Enemy接口
//攻击敌人得分
public interface Enemy {
public int getScore();
}
Award接口
//l击中特殊飞行物获得奖励
public interface Award {
public static final int DOUBLE_FIRE = 0; // int DOUBLE_FIRE = 0;
public static final int LIFE = 1; // int LIFE = 1;
// 获取奖励方法
public int getType();
}
AirPlane类 (敌机)
这里我们继承FlyingObject父类,以及使用我们定义的Enemy接口
public class AirPlane extends FlyingObject implements Enemy {
private int speed = 2;// 敌机走步的步数
//构造方法,实例化类的时候自动调用
public AirPlane() {
image = ShootGame.airplane;
width = image.getWidth();
height = image.getHeight();
Random rand = new Random();
x = rand.nextInt(ShootGame.WIDTH - this.width);
y = -this.height; // y:负的敌机的高
}
// 重写 getScore();
public int getScore() {
return 5;
}
//重写飞行方法
public void step() {
y += speed;
}
//重写越界方法
public boolean outOfBounds() {
return this.y > ShootGame.HEIGHT; // 敌机的y坐标大于窗口的高
}
}
Bee类(特殊飞行物)
这里我们继承FlyingObject父类,以及使用我们定义的Award接口
//Bee也是飞行物,击中能获取奖励,并且飞行轨迹不定
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();
Random rand = new Random();
x = rand.nextInt(ShootGame.WIDTH - this.width);
y = -this.height;
awardType = rand.nextInt(2);// 随机生成奖励类型
}
//重写获取奖励方法
public int getType() {
return awardType;
}
//重写飞行方法
public void step() {
if (x >= ShootGame.WIDTH - this.width) {
xSpeed = -1;
}
if (x <= 0) {
xSpeed = 1;
}
x += xSpeed;
y += ySpeed;
}
//重写越界方法
public boolean outOfBounds() {
return this.y > ShootGame.HEIGHT;
}
}
Bullet类(子弹)
这里我们继承FlyingObject父类
public class Bullet extends FlyingObject{
//子弹走步步数,只有y坐标在变,x发射以后不再改变
private int speed = 3;
public Bullet(int x,int y){//子弹的坐标随着英雄机的变化而变化
image = ShootGame.bullet;
width = image.getWidth();
height = image.getHeight();
this.x = x;
this.y = y;
}
//重写飞行方法
public void step(){
y -= speed;
}
//重写越界方法
public boolean outOfBounds(){
return this.y < -this.height;
}
}
Hero类(我机)
这里我们继承FlyingObject父类
//英雄机是飞行物
public class Hero extends FlyingObject {
private int life; // 命
private int doubleFire; // 火力值
private BufferedImage[] images; // 图片数组
private int index; // 协助图片切换
public Hero() {
image = ShootGame.hero0;
width = image.getWidth();
height = image.getHeight();
x = 150;
y = 400;
life = 3; // 3条命
doubleFire = 0; // 单倍火力
images = new BufferedImage[] { ShootGame.hero0, ShootGame.hero1 };
index = 0;
}
public void step() {
// 每100毫秒切一次,动态感出现
image = images[index++ / 10 % images.length];
}
public Bullet[] shoot() {
int xStep = this.width / 4;
if (doubleFire > 0) { // 双发
Bullet[] bullets = new Bullet[2];
bullets[0] = new Bullet(this.x + 1 * xStep, this.y - 20);
bullets[1] = new Bullet(this.x + 3 * xStep, this.y - 20);
doubleFire -= 2; // 发射双倍火力,每次减2,实际就是2倍火力的持续时间
return bullets;
} else { // 单发
Bullet[] bullets = new Bullet[1];
bullets[0] = new Bullet(this.x + 2 * xStep, this.y - 20);
return bullets;
}
}
//飞机随鼠标位置移动
public void moveTo(int x, int y) {
this.x = x - this.width / 2;
this.y = y - this.height / 2;
}
public boolean outOfBounds() {
return false; // 英雄机永不越界
}
// 加命
public void addLife() {
life++;
}
// 获取命
public int getLife() {
return life;
}
public void addDoubleFire() {
doubleFire += 40;
}
// 活力值清零
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;
int hx = this.x + this.width / 2;
int hy = this.y + this.height / 2;
return hx > x1 && hx < x2 && hy > y1 && hy < y2;
}
// 减命
public void subtractLife() {
life--;
}
}
以上就是我们的基础类以及接口,完成了以上的准备以后,可以说我们的游戏已经完成了一大半,接下来只需要完成我们的射击规则以及游戏界面,就可以了,游戏的完成,我会放在(2)中,下面先放上截图。