java实现飞机⼤战案例详解
前⾔
飞机⼤战是⼀个⾮常经典的案例,因为它包含了多种新⼿需要掌握的概念,是⼀个⾮常契合⾯向对象思想的⼊门练习案例
程序分析:
在此游戏中共有六个对象:
⼩敌机Airplane,⼤敌机BigAirplane,⼩蜜蜂Bee,天空Sky,英雄机Hero,⼦弹Bullet
其次我们还需要三个类:
超类Flyer,图⽚类Images,测试类World
还需:
英雄机2张,⼩敌机,⼤敌机,⼩蜜蜂,⼦弹,天空各1张,爆炸图4张,游戏开始,暂停,游戏结束各1张,共14张图⽚放⼊与图⽚类Images同包中
超类Flyer:
此类是⽤来封装所有对象共有的⾏为及属性的
不管是写什么程序,都建议遵循两点:数据私有化,⾏为公开化
import java.util.Random;
import java.awt.image.BufferedImage;
public abstract class Flyer {
//所有对象都有三种状态:活着的,死了的,及删除的
//这⾥之所以选择⽤常量表⽰状态是因为⾸先状态是⼀个不需要去修改的值
//其次状态需要反复使⽤所以结合这两个特点,我选择了使⽤常量表⽰
//state是⽤来表⽰当前状态的,每个对象都有⼀个实时的状态,此状态是会改变的,且初始状态都是活着的
public static final int LIVE = 0;//活着的
public static final int DEAD = 1;//死了的
public static final int REMOVE = 2;//删除的
protected int state = LIVE;//当前状态(默认状态为活着的)
每个对象都是⼀张图⽚,既然是图⽚那么就⼀定有宽⾼,其次因为每个对象都是会随时移动的即为都有x,y坐标
protected int width;//宽
protected int height;//⾼
protected int x;//左右移动(x坐标)
protected int y;//上下移动(y坐标)
/**
* 飞⾏物移动(抽象)
* 每个飞⾏物都是会移动的,但是移动⽅式不同
* 所以这⾥就将共有的⾏为抽到了超类中
* 但是设置成了抽象⽅法,实现了多态的效果
*/
public abstract void step();
/**
* 获取图⽚(抽象)
* 所有对象都是图⽚但图⽚不相同所以抽象化了
*/
public abstract BufferedImage getImage();
/**
* 判断对象是否是活着的
*/
public boolean isLive(){
return state == LIVE;
}
/**
* 判断对象是否是死了的
*/
public boolean isDead(){
return state == DEAD;
}
/**
* 判断对象是否删除了
*/
public boolean isRemove(){
return state == REMOVE;
}
/**
* 判断对象(⼤敌机,⼩敌机,⼩蜜蜂)是否越界
* 当敌⼈越界我们就需要删除它否则程序越执⾏越卡,会出现内存泄露的问题,此⽅法就是为后续删除越界对象做铺垫的 * @return
*/
public boolean isOutOfBounds(){
return y >= World.HEIGHT;
}
/**
* 给⼩/⼤敌机,⼩蜜蜂提供的
* 因为三种飞⾏物的宽,⾼不同所以不能写死。
* 若三种飞⾏物的宽,⾼相同,那么就可以将宽,⾼写死
*/
public Flyer(int width,int height){
Random rand = new Random();
this.width = width;
this.height = height;
x = Int(World.WIDTH-width);//x:0到负的width长度的之间的随机数
y = -height;//y:负的height⾼度
}
/**
* 给天空,⼦弹,英雄机提供的
* 因为英雄机,⼦弹,天空的宽,⾼,x,y都是不同的,所以数据不能写死,需要传参
*/
public Flyer(int width,int height,int x,int y){
this.width = width;
this.height = height;
this.x = x;
this.y = y;
}
/**
*检测碰撞
* this:敌⼈(⼩敌机/⼩蜜蜂/⼤敌机)
* other:⼦弹/英雄机
*@return
*/
public boolean isHit(Flyer other){
int x1 = this.x - other.width;//x1:敌⼈的x-英雄机/⼦弹的宽 int x2 = this.x + this.width;//x2:敌⼈的x加上敌⼈的宽
int y1 = this.y - other.height;//y1:敌⼈的y-英雄机/⼦弹的⾼ int y2 = this.y + this.height;//y2:敌⼈的y加上敌⼈的⾼
int x = other.x;//x:英雄机/⼦弹的x
int y = other.y;//y:英雄机/⼦弹的y
/*
x在x1与x2之间并且 y在y1与y2之间,即为撞上了
*/
return x>x1 && x<=x2 && y>=y1 && y<=y2;
}
/**
* 飞⾏物死亡
*/
public void goDead(){
state = DEAD;//将当前状态修改为死了的
}
}
图⽚⼯具类Images:
此类⽤来获取每个对象对应的图⽚
import java.awt.image.BufferedImage;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
/**
* 图⽚⼯具类
*/
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("background01.png");//天空
bullet = readImage("bullet.png");//⼦弹
heros = new BufferedImage[2];//英雄机图⽚数组
heros[0] = readImage("hero0.png");//英雄机图⽚1
heros[1] = readImage("hero1.png");//英雄机图⽚2
airs = new BufferedImage[5];//⼩敌机图⽚数组
bairs = new BufferedImage[5];//⼤敌机图⽚数组
bees = new BufferedImage[5];//⼩蜜蜂图⽚数组
airs[0] = readImage("airplane.png");//⼩敌机图⽚读取
bairs[0] = readImage("bigairplane.png");//⼤敌机图⽚读取 bees[0] = readImage("bee01.png");//⼩蜜蜂图⽚读取
/**爆炸图迭代读取*/
for (int i=1;i<5;i++){//遍历/迭代赋值
airs[i] = readImage("bom"+i+".png");//⼩敌机图⽚数组其余元素赋值爆炸图
bairs[i] = readImage("bom"+i+".png");//⼤敌机图⽚数组其余元素赋值爆炸图
bees[i] = readImage("bom"+i+".png");//⼩蜜蜂图⽚数组其余元素赋值爆炸图
}
start = readImage("start.png");//启动状态图
pause = readImage("pause.png");//暂停状态图
gameover = readImage("gameover.png");//游戏结束状态图
}
/**
* 读取图⽚
* 此处的fileName:图⽚⽂件名
*
* atch:异常的⼀种处理⽅法
*/
public static BufferedImage readImage(String fileName){
try{
BufferedImage img = ad(Resource(fileName)); //读取与Flyer在同⼀个包中的图⽚ return img;
}catch(Exception e){
e.printStackTrace();
throw new RuntimeException();
}
}
}
世界窗⼝类/测试类 World:
此类⽤来集合所有类进⾏排序及具体的操作,和程序的最终运⾏
import javax.swing.JFrame;
import javax.swing.JPanel;
import java.awt.Graphics;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.nio.Buffer;
//定时器
import java.util.Timer;
//定时器任务
import java.util.TimerTask;
//打开随机类
import java.util.Random;
//扩容类
import java.util.Arrays;
/**
* 世界测试类(整个游戏窗⼝)
*/
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 s = new Sky();//天空对象
private Hero h = new Hero();//英雄机对象
private Flyer[] enemies ={};//敌⼈对象,分别是⼤敌机,⼩敌机,⼩蜜蜂所以写成了数组
private Bullet[] bt ={};//⼦弹也是有很多的所以写成了数组
/
**
* ⽣成敌⼈对象(⼩敌机,⼤敌机,⼩蜜蜂)
*/
public Flyer nextOne(){
Random rand = new Random();
int type = Int(20);//0-19之间的随机数
if (type < 5){//当随机数⼩于5
return new Bee();//返回⼩蜜蜂
}else if (type < 13){//当随机数⼩于13
return new Airplane();//返回⼩敌机
对象图片高清}else{//⼤于⼗三则
return new BigAirplane();//返回⼤敌机
}
}
private int enterIndex = 0;
/**
* 敌⼈(⼤敌机,⼩敌机,⼩蜜蜂)⼊场
*/
public void enterAction() {//每10毫秒⾛⼀次
enterIndex++;
if (enterIndex%40 == 0 ){//四百毫秒⾛⼀次
Flyer fl = nextOne();//获取敌⼈对象
enemies = pyOf(enemies,enemies.length+1);//扩容(每产⽣⼀个敌⼈数组就扩容1) enemies[enemies.length-1] = fl;//将⽣成的敌⼈fl放置enemies数组的末尾
}
}
int shootIndex = 0;
/**
* ⼦弹⼊场
*/
public void shootAction(){//10毫秒⾛⼀次
shootIndex++;
if (shootIndex%30 == 0){//每300毫秒⾛⼀次
Bullet[] bs = h.shoot();//获取⼦弹数组对象
bt = pyOf(bt,bt.length+bs.length);//扩容⼦弹数组(每⼊场⼀个⼦弹就加⼀个元素) System.arraycopy(bs,0,bt,bt.length-bs.length,bs.length);//数组的追加
}
}
/**
* 让除去英雄机外的所有对象(⼩敌机,⼤敌机,⼩蜜蜂,⼦弹,天空)移动
*/
public void setpAction() {//每10毫秒⾛⼀次
s.step();//天空移动
for (int i=0;i<enemies.length;i++) {//遍历所有敌⼈
enemies[i].step();//敌⼈移动
}
for (int i=0;i<bt.length;i++){//遍历所有⼦弹
bt[i].step();//⼦弹移动
}
}
/**
* 重写outOfBoundsAction(⽅法)
*/
public void outOfBoundsAction() {//每10毫秒⾛⼀次
for (int i=0;i<enemies.length;i++){//遍历所有敌⼈
if (enemies[i].isOutOfBounds() || enemies[i].isRemove()){
enemies[i] = enemies[enemies.length-1];//最后⼀个敌⼈和越界敌⼈替换
enemies = pyOf(enemies,enemies.length-1);//缩容
}
}
for (int i=0;i<bt.length;i++){//迭代所有⼦弹
if (bt[i].isOutOfBounds() || bt[i].isRemove()){
bt[i] = bt[bt.length-1];//⽤最后⼀个⼦弹替换出界的⼦弹
bt = pyOf(bt,bt.length-1);//缩容
}
}
}
private int score = 0;//玩家的得分
/
**
* ⼦弹与敌⼈的碰撞
*/
public void bulletBangAction() {//每10毫秒⾛⼀次
for (int i=0;i<bt.length;i++){//遍历所有⼦弹
Bullet b = bt[i];//获取每⼀个⼦弹
for (int j=0;j<enemies.length;j++){//迭代每⼀个敌⼈
Flyer f = enemies[j];//获取每⼀个敌⼈
if (b.isLive() && f.isLive() && f.isHit(b)){//若⼦弹活着的,敌⼈活着的,并且两个对象相撞
if (f instanceof EnemyScore) {//判断死亡的敌⼈类型能否强转为得分接⼝类型
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论