4

基于Java语言在窗体上实现飞机大战小游戏

 2 years ago
source link: https://blog.csdn.net/newlw/article/details/122802279
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
  • 飞机大战:用 Java 语言在窗体上实现飞机大战小游戏,运行程序后,出现一个窗体,在窗体上用鼠标控制英雄机的移动,通过子弹打击敌机进行分数的计算,以及英雄机血量的计算等。
  • 主要模块:登陆界面、音乐、子弹、敌机、英雄机、背景图、结束界面、BOSS 机、分数计算、血量计算。
  • 负责模块:登陆界面、音乐、子弹、结束界面。

模块需求描述

登陆界面:运行程序后,弹出窗体,在窗体上显示关卡模式的选择,点击其中的模式后,开始游戏。

结束界面:重新选择关卡模式,即可开始游戏

音乐:登陆音乐,开始游戏音乐。

  1. 子弹的创建
  2. 子弹的发射
  3. 子弹的移动
  • 一直向上:中间的子弹
  • 左上方向:左边的子弹
  • 右上方向:右边的子弹

4.子弹与敌机碰撞

5.子弹的类型升级

描述:当子弹打到道具机时,子弹一次发射的个数增加一个,最大为 3 个,当发射的个数为 3 时,子弹再打到道具机,子弹的类型就升一级,发射的个数置为 1,继续重新计算。第四种子弹只发射 3 个,发射后,子弹类型置为第三种子弹,第四种子弹无敌的,打到敌机不会消失。若期间英雄机被敌机碰到,子弹的类型置为 1,发射的个数置为 1。

  • 第一种子弹:伤害值:1
  • 第二种子弹:伤害值:2
  • 第三种子弹:伤害值:3
  • 第四种子弹:伤害值:100

6.子弹的一次发射个数的升级

描述:在子弹的类型升级中有涉及

  • 一次发射一个子弹
  • 一次发射两个子弹
  • 一次发射三个子弹

7.子弹与敌机碰撞

描述:当子弹与敌机碰撞后,子弹消失,敌机消失,消灭敌机数增加

总体开发思想

  • 主要的数据结构

集合:用集合来存储子弹的对象,子弹的发射是从集合中调出对象,子弹的消失是从集合中删除相应的子弹对象

List<Fire> fires = new ArrayList<Fire>();
  • 移动与碰撞原理

    子弹的移动:子弹图片在窗口中显示位置横纵坐标的改变

    移动方向:

  • 直向上:子弹的横坐标不变,纵坐标逐渐变大

  • 左上方向:子弹的横坐标逐渐变小,纵坐标逐渐变大

  • 右上方向:子弹的横坐标逐渐变大,纵坐标逐渐变大

    子弹与敌机的碰撞:子弹的位置坐标在敌机图片的位置大小范围内

  • 音乐播放原理

    在音乐类中,使用文档输入流来读入音频,再使用多线程实现游戏登陆和播放音乐、游戏运行和播放音乐的同时进行,在主类中调用音乐播放的方法。

  • 界面设计原理

运行程序后,游戏运行状态为 false,此时调用画板画出背景图,选中相应的模式后,游戏运行状态为 ture,登录界面切换为游戏运行界面,游戏结束后,游戏运行状态为 false,重新显示登录界面。

选择关卡模式:调用鼠标监听器,用鼠标点击相应的模式字体区域,获取到鼠标点击的相应坐标后,在相应的坐标区域中选着相应的关卡模式,关卡模式是根据每循环多少次创建一个敌机来实现的。

  • 开发语言:Java

1.登录与结束界面

在画板类中:

登陆界面的实现:

// 当游戏结束时,

if (gameover) {

//画游戏登陆时的界面

try {

bg = App.getImg("/img/face.png");

} catch (IOException e) {

printStackTrace();//捕获抛出异常

}

drawImage(bg, 0 ,  0, 512, 728,  null);//画背景图片

//选择关卡模式(鼠标点击相应的位置进行操作)

//画笔为黑色

setColor(Color.black);

//字体大小和类型

setFont(new Font("楷体", Font.BOLD, 30));

//画的内容和位置

drawString("请选择关卡模式:", 130, 450);

drawString("(鼠标点击相应的位置进行操作)", 40, 480);

//画笔为蓝色

setColor(Color.blue);

//字体大小和类型

setFont(new Font("楷体", Font.BOLD, 50));

//画的内容和位置

drawString("1、简单模式", 100, 550);

drawString("2、普通模式" , 100, 600);

drawString("3、困难模式" , 100, 650);

}


newCodeMoreWhite.png

读取关卡模式:

//当游戏结束时,读取鼠标的点击位置

if(gameover&&ms==0) {

int x=e.getX();//获取鼠标的横坐标

int y=e.getY();//获取鼠标的纵坐标

if(y>=500&&y<550&&x>=100&&x<400) {

ms=1;//模式 1

}else if(y>=550&&y<600&&x>=100&&x<400) {

ms=2; //模式 2

}else if(y>=600&&y<650&&x>=100&&x<400) {

ms=3; //模式 3

}

// 刷新界面

repaint();

}

2.播放音乐

在音乐类中:

读取音乐文件的方法:

static Player player = null;
static void  play(String str) {
    try {
        File file = new File(str);//读取文件
        FileInputStream fis = new FileInputStream(file);
        BufferedInputStream stream = new BufferedInputStream(fis);//读取流的转化
        player = new Player(stream);//创建一个播放音乐类对象
        player.play();//播放音乐
    } catch (FileNotFoundException | JavaLayerException e1) {
        printStackTrace();//抛出捕获异常
    }
}

播放音乐的方法:

/*

播放音乐的线程

*/
//游戏运行音乐
public void music1() {
    new Thread() {
        @Override
        public void run() {
            while (true) {
                System.out.println("播放音乐");
//如果游戏没结束就播放
                if (!GamePanel.gameover) {
                    Music.play("D:\\java文件\\飞机大战.mp3");
                }
            }
        }
    } .start();
}
//登陆音乐
public void music2() {
    new Thread() {
        @Override
        public void run() {
            Music.play("D:\\java文件\\mini.mp3");
        }
    } .start();
}
newCodeMoreWhite.png

在主类中:

//创建音乐类对象
Music music =new Music();
//播放登陆音乐
music.music2();
//播放游戏运行音乐
music.music1();

子弹类中:

//hx、hy子弹的横纵坐标,dir子弹的移动方向,num子弹的类型
public Fire(int hx,int hy,int dir,int num) throws IOException {
//确定子弹的图片
    img=App.getImg("/img/fire"+num+".png");
//确定子弹火力的大小
    if(num==1) {
        fr=1;
    } else if(num==2) {
        fr=2;
    } else if(num==3) {
        fr=3;
    } else if(num==4) {
        fr=100;
    }
    w=35;
    h=35;
//确定子弹的位置(初始位置在英雄机上)
    x=hx;
    y=hy;
    this.dir=dir;
    this.num=num;
}

在画板类中:

/*

*创建子弹的方法

*/
int findex = 0;// 记录shoot方法执行的次数
protected void shoot() throws IOException {
    findex++;
    if (findex == 20) {//减少创建的频率
        if (power == 1) {//当火力值为1,即一次发射一颗子弹
// 创建子弹,num子弹的类型
            Fire fire3 = new Fire(hero.x + 40, hero.y, 1, num);
// 将子弹加入到弹药库中
            fires.add(fire3);
//当火力值为2,即一次发射两颗子弹
        } else if (power == 2) {
// 创建子弹
            Fire fire1 = new Fire(hero.x + 10, hero.y, 1, num);
// 将子弹加入到弹药库中
            fires.add(fire1);
// 创建子弹
            Fire fire2 = new Fire(hero.x + 80, hero.y, 1, num);
// 将子弹加入到弹药库中
            fires.add(fire2);
//当火力值为3,即一次发射三颗子弹
        } else if (power == 3) {
// 创建子弹
            Fire fire1 = new Fire(hero.x, hero.y, 0, num);
// 将子弹加入到弹药库中
            fires.add(fire1);
// 创建子弹
            Fire fire2 = new Fire(hero.x + 50, hero.y - 20, 1, num);
// 将子弹加入到弹药库中
            fires.add(fire2);
// 创建子弹
            Fire fire3 = new Fire(hero.x + 100, hero.y, 2, num);
// 将子弹加入到弹药库中
            fires.add(fire3);
//当火力值为4,即一次发射三颗无敌子弹
        } else if (power == 4) {
// 创建子弹
            Fire fire1 = new Fire(hero.x+15, hero.y, 0, num);
// 将子弹加入到弹药库中
            fires.add(fire1);
// 创建子弹
            Fire fire2 = new Fire(hero.x, hero.y - 20, 1, num);
// 将子弹加入到弹药库中
            fires.add(fire2);
// 创建子弹
            Fire fire3 = new Fire(hero.x + 70, hero.y, 2, num);
// 将子弹加入到弹药库中
            fires.add(fire3);
//power置为1,无敌子弹创建完后,变成类型3
            power=1;
            num=3;
        }
        findex = 0;// 计数器归零
    }
}

- 
newCodeMoreWhite.png

在画板类中:

// 在窗体上画子弹
// 遍历集合,画出所有的敌机
for (int i = 0; i < fires.size(); i++) {
// 获取每一个子弹
    Fire fire = fires.get(i);
//画出子弹
    drawImage(fire.img, fire.x, fire.y, fire.w, fire.h, null);
}

子弹类中:

/*

* 子弹移动的方法

*/

public void move() {

if(dir==0) {

//左上

y=y-10;

x=x-2;

}else if(dir==1) {

//直走

y=y-10;

}else if(dir==2) {

//右上

y=y-10;

x=x+2;

}

}
newCodeMoreWhite.png
  • 碰撞敌机与升级
在画板类中:

/*

​    *判断一颗子弹是否击中了敌机

*/
private void bang(Fire fire) {
// 遍历所有的敌机
    for (int i = 0; i < eps.size(); i++) {
// 获取每一个敌机
        Ep e = eps.get(i);
// 判断该子弹是否击中敌机
        if (e.shootBy(fire)) {
// 如果敌机被子弹击中
// 如果不是导弹机(导弹机不会死亡,编号是15)
            if (e.type != 15) {
// 1.让敌机的血量减少
                hp=e.hp-fire.fr;
// 当敌机的血量减少到零时,死亡
                if (e.hp <= 0) {
// 判断敌机是否是道具机(道具机编号为12,打死道具机,子弹会升级)
                    if (e.type == 12) {
// 增加火力值,即一次发射的子弹数
                        power++;
// 如果power值大于3,增加英雄机血量,子弹类型升级
                        if (power > 3) {
                            hero.hp++;//英雄机增加血量
                            if (hero.hp > 5) {
                                hero.hp = 5;
                            }
//类型1-》类型2
                            if (num == 1) {
                                num = 2;
                                power=1;
//类型2-》类型3
                            } else if (num == 2) {
                                num = 3;
                                power=1;
//类型3-》类型4(创建完子弹类型4后,创建方法后面num置为3,power置为1)
                            } else if(num==3) {
                                num=4;
                                power=4;
                            }
                        }
                    }
// 2.敌机死亡(消失:从敌机大本营中删除)
                    eps.remove(e);
// 3.增加分数
                    score =e.type+ score;
//4.消灭的敌机数
                    Ep.number++;
                }
// 4.子弹消失:如果不是类型4(类型4无敌的),就从子弹库中删除
                if(num!=4) {
                    fires.remove(fire);
                }
            }
        }
    }
}
newCodeMoreWhite.png

子弹类型 1

子弹类型 2

子弹类型 3

子弹类型 4


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK