java 飞机大战_Java学习:用面向对象简单实现飞机大战

利用面想对象知识,实现一个简单的“飞机大战”小游戏。代码粗糙,有兴趣可以自己优化下!

7010812399eb67576594d7e10f0c07ba.png

案例具体要求:

要求实现飞机大战功能有敌机,加分

有奖励机,加生命值,或者火力值,飞行有一定规则

有英雄机,碰到敌机会减少生命值,且火力值回复初始,直至游戏结束

有子弹,与敌机、奖励机碰撞,敌机、奖励机消失

有计分,生命值(声明变量,画出分数,生命值。子弹和飞行物有碰撞时,判断类型)

敌机,奖励机不可以越界(逆向思维,将在窗口中显示的对象添加到相关的数组中。定义一个abstract,判断y的值,有没有超过飞行物的值。遍历所有的飞行物,把没有越界的放到下面,判断是否越界)

有开始界面,鼠标控制英雄机,鼠标移出暂停游戏,鼠标进入继续游戏,生命归零,结束游戏(定义一个初始状态,添加鼠标监听器,调用英雄机类,重写相关方法)

c65dd2606b70e4b75d120f0199e008d7.png

实现代码:

飞行物的父类package cn.yflad.game;

import java.awt.image.BufferedImage;

/**

* @Author: yflad (yflad@qq.com)

* @Blog: https://yflad.cn

* @Date: 2018-12-09

* @role: 飞行物的父类

*/

public abstract class FlyingObject {

public BufferedImage image;// 有图片

public int x;// x坐标

public int y;// y坐标

public int height;// 图片的高度

public int width;// 图片的宽度

public abstract void step(); // 飞机移动

public boolean checkBang(Bullet b) {// 检查子弹和飞行物碰撞的方法

int x1 = this.x - b.width;

int y1 = this.y - b.height;

int x2 = this.x + width;

int y2 = this.y + height;

if (b.x >= x1 && b.x <= x2 && b.y >= y1 && b.y <= y2) {

return true;

}

return false;

}

// 检查飞行物越界

public abstract boolean outOfBounds();

}

普通的敌机类:飞行物的子类

b2afb3904c7e1a44a3dee9d304da7062.pngpackage cn.yflad.game;

/**

* @Author: yflad (yflad@qq.com)

* @Blog: https://yflad.cn

* @Date: 2018-12-10

* @role: 普通的敌机类:飞行物的子类

*/

public class Airplane extends FlyingObject implements Enemy {

int ySpeed = 3; // y轴上的速度

// 通过构造函数对敌机进行初始化操作

public Airplane() {

image = TestGame.airplane;// 敌机的图片

width = image.getWidth();// 获取图片宽度

height = image.getHeight();// 获取图片的高度

x = (int) (Math.random() * (TestGame.WIDTH - width));// x轴 原点到(窗口宽-敌机宽)之间的随机数

y = -height;

}

// 敌机移动的方式

@Override

public void step() {

y += ySpeed;// y轴+(向下)

}

// 子弹碰撞敌机,每碰撞一次加10分

@Override

public int getScore() {

return 10;

}

// 敌机越界

@Override

public boolean outOfBounds() {

return y > TestGame.HEIGHT;// 判断y的值,有没有超过本类的值

}

}

小蜜蜂类:飞行物的子类

9918c87231c639f81da1a7c0a0e7d73a.pngpackage cn.yflad.game;

/**

* @Author: yflad (yflad@qq.com)

* @Blog: https://yflad.cn

* @Date: 2018-12-09

* @role: 小蜜蜂类:飞行物的子类

*/

public class Bee extends FlyingObject implements Award {

int xspeed = 3; // x坐标移动速度

int yspeed = 2; // y坐标移动速度

// 初始化数据

public Bee() {

image = TestGame.bee;// 小蜜蜂的图片

width = image.getWidth();

height = image.getHeight();

x = (int) (Math.random() * (TestGame.WIDTH - width));// x轴出现的位置在窗口高度范围内随机出现

y = -height;

}

@Override

public void step() {

// 蜜蜂走z字型

x += xspeed;// x+(向左或向右)

y += yspeed;// y+(向下)

if (x <= 0 || x >= TestGame.WIDTH - width) {

xspeed = -xspeed;

}

}

//奖励类型可能为加命或者加双倍火力

@Override

public int getType() {

int type = (int) (Math.random() * 2);

return type;

}

// 小蜜蜂越界

@Override

public boolean outOfBounds() {

return y > TestGame.HEIGHT;

}

}

英雄机类:飞行物的子类

422d8aea342975e8f3ea221930a30b21.pngpackage cn.yflad.game;

import java.awt.image.BufferedImage;

/**

* @Author: yflad (yflad@qq.com)

* @Blog: https://yflad.cn

* @Date: 2018-12-09

* @role: 英雄机类:飞行物的子类

*/

public class Hero extends FlyingObject {

// 有什么

BufferedImage[] images;

int doubleFire;// 默认为单倍火力

int life;// 默认生命值

public Hero() {// 通过构造函数对敌机进行初始化操作

image = TestGame.hero0;

images = new BufferedImage[] { TestGame.hero0, TestGame.hero1 };

width = image.getWidth();

height = image.getHeight();

x = TestGame.WIDTH / 2 - width / 2;

y = TestGame.HEIGHT / 2 + height / 2;

doubleFire = 0;// 默认单倍火力

life = 3;

}

int index = 0;

int indexStep = 0;

// 敌机移动的方式

@Override

public void step() {

if (index++ % 5 == 0) {// 相当于150毫秒切换一次图片

image = images[indexStep++ % images.length];

}

}

// 英雄机移动的方法。x:鼠标的x坐标 y:鼠标的y坐标

public void moveTo(int x, int y) {

this.x = x - width / 2;

this.y = y - height / 2;

}

// 英雄机发射子弹的方法

public Bullet[] shoot() {

int x = width / 4;// 局部变量

Bullet[] b;

if (doubleFire > 0) {

// 双倍火力

b = new Bullet[2];

b[0] = new Bullet(this.x + x, this.y - 10);

b[1] = new Bullet(this.x + 3 * x, this.y - 10);

//双倍火力不是源源不断,给定一定量双倍,发射完时 为单倍火力

doubleFire -= 2;// doubleFire=doubleFire-2;

} else {

// 单倍火力

b = new Bullet[1];

b[0] = new Bullet(this.x + 2 * x, this.y - 10);

}

return b;

}

// 获取生命的方法

public int getLife() {

return life;

}

// 加命的方法

public void addLife() {

life++;

}

// 减命的方法

public void deleteLife() {

life--;

}

// 加双倍火力的方法

public void addDoubleFire() {

doubleFire = 40;

}

// 双倍火力清零的方法

public void clearDoubleFire() {

doubleFire = 0;

}

// 英雄机和飞行物撞

public boolean hit(FlyingObject other) {// 传对象

int x1 = this.x - other.width;

int x2 = this.x + width;

int y1 = this.y - other.height;

int y2 = this.y + height;

if (other.x >= x1 && other.x <= x2 && other.y >= y1 && other.y <= y2) {

return true;

}

return false;

}

// 飞行机永不越界

@Override

public boolean outOfBounds() {

return false;

}

}

子弹类:飞行物的子类

d37fc66a2d41400e1abd2d7c324938fd.pngpackage cn.yflad.game;

/**

* @Author: yflad (yflad@qq.com)

* @Blog: https://yflad.cn

* @Date: 2018-12-09

* @role: 子弹类:飞行物的子类

*/

public class Bullet extends FlyingObject {

// 有什么

int yspeed = -3;// y轴上的速度

/*

* 因为子弹的坐标是由英雄机所决定的 所以这里可以用有参构造函数来初始化子弹

*/

public Bullet(int x, int y) {

image = TestGame.bullet;

height = image.getHeight();

width = image.getWidth();

this.x = x;

this.y = y;

}

@Override

public void step() {

y += yspeed;

}

// 子弹越界

@Override

public boolean outOfBounds() {

return y < -height;

}

}

加命或加双倍火力package cn.yflad.game;

/**

* @Author: yflad (yflad@qq.com)

* @Blog: https://yflad.cn

* @Date: 2018-12-11

* @role: 奖励类型: 加命或加双倍火力

*/

public interface Award {

public static final int ADD_LIFE = 0;// 生命

public static final int DOUBLE_FIRE = 1;// 火力

public abstract int getType();// 奖励类型

}

加分类package cn.yflad.game;

/**

* @Author: yflad (yflad@qq.com)

* @Blog: https://yflad.cn

* @Date: 2018-12-09

* @role: 奖励类型:加分

*/

public interface Enemy {

// 获取分数的方法

public abstract int getScore();

}

运行窗口程序:package cn.yflad.game;

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.Timer;

import java.util.TimerTask;

import javax.imageio.ImageIO;

import javax.swing.JFrame;

import javax.swing.JPanel;

/**

* @Author: yflad (yflad@qq.com)

* @Blog: https://yflad.cn

* @Date: 2018-12-09

* @role: 实现

*/

public class TestGame extends JPanel {// 继承了JPanel类,相当于继承了一个画笔

public static final int WIDTH = 400;// 面板宽

public static final int HEIGHT = 654;// 面板高

/*

* 加载图片

*/

public static BufferedImage bj;

public static BufferedImage airplane;

public static BufferedImage bee;

public static BufferedImage bullet;

public static BufferedImage gameover;

public static BufferedImage hero0;

public static BufferedImage hero1;

public static BufferedImage pause;

public static BufferedImage start;

// 程序的状态

public static final int START = 0;// 开始

public static final int RUNNING = 1;// 运行状态

public static final int PAUSE = 2;// 暂停状态

public static final int GAMEOVER = 3;// 结束状态

// 默认状态为开始状态

int state = 0;

FlyingObject[] flyings = {};// 创建飞行物类型数组

Hero hero = new Hero();// 创建英雄机对象

Bullet[] bullets = {};// 声明一个存放子弹的数组

int score = 0;// 声明一个分数的变量

/*

* 通过静态代码块来加载图片

*/

static {

try {

bj = ImageIO.read(TestGame.class.getResource("..\\image\\background.png"));

airplane = ImageIO.read(TestGame.class.getResource("..\\image\\airplane.png"));

bee = ImageIO.read(TestGame.class.getResource("..\\image\\bee.png"));

bullet = ImageIO.read(TestGame.class.getResource("..\\image\\bullet.png"));

gameover = ImageIO.read(TestGame.class.getResource("..\\image\\gameover.png"));

hero0 = ImageIO.read(TestGame.class.getResource("..\\image\\hero0.png"));

hero1 = ImageIO.read(TestGame.class.getResource("..\\image\\hero1.png"));

pause = ImageIO.read(TestGame.class.getResource("..\\image\\pause.png"));

start = ImageIO.read(TestGame.class.getResource("..\\image\\start.png"));

} catch (Exception e) { // 删掉IO

System.out.println("图片加载失败!");

}

}

/*

* 用画笔画画,重写JPanel中的paint()方法

*/

@Override

public void paint(Graphics g) {

// 画背景

g.drawImage(bj, 0, 0, null);

// 画敌人

for (int i = 0; i < flyings.length; i++) {// 遍历所有敌人(敌机+小蜜蜂)

FlyingObject f = flyings[i];// 获取每一个飞行物对象

g.drawImage(f.image, f.x, f.y, null);// 画敌人(敌机+小蜜蜂)对象

}

// 画英雄机

g.drawImage(hero.image, hero.x, hero.y, null);

// 画子弹

for (int i = 0; i < bullets.length; i++) {// 遍历所有子弹

Bullet b = bullets[i];

g.drawImage(b.image, b.x, b.y, null);

}

// 设置字体的颜色和大小

g.setColor(Color.BLUE);

g.setFont(new Font(Font.SANS_SERIF, Font.BOLD, 24));

// 画分数和生命值

g.drawString("分数:" + score, 10, 25);

g.drawString("生命:" + hero.life, 10, 45);

// 画状态

switch (state) {

case START:

g.drawImage(start, 0, 0, null);

break;

case PAUSE:

g.drawImage(pause, 0, 0, null);

break;

case GAMEOVER:

g.drawImage(gameover, 0, 0, null);

break;

}

}

/**

* 创建飞行物对象的方法

*/

public FlyingObject nextOne() {

int type = (int) (Math.random() * 10);// 生成敌机和小蜜蜂的概率比大约为10:1

if (type == 0) {

return new Bee();// 蜜蜂对象

}

return new Airplane();// 敌机对象

}

/**

* 将创建的飞行物对象添加到飞行物数组中去

*/

int index = 0;

public void addAction() {// 添加飞行物,并对数组进行扩容

/*

* 默认情况下是30毫秒创建一个对象添加到数组中去,通过index遍历来控制添加的对象个数

*/

if (index++ % 20 == 0) {// 相当于30*20毫秒往数组中添加一个对象

flyings = Arrays.copyOf(flyings, flyings.length + 1);// 将飞行物数组扩容

flyings[flyings.length - 1] = nextOne();// 将创建的对象放到数组中去

}

}

/**

* 将英雄机发射出来的子弹数组复制到bullets子弹数组中去

*/

int index2 = 0;

public void shootAction() {

if (index2++ % 20 == 0) {

// 英雄机发射子弹

Bullet[] bs = hero.shoot();

// 对bullets子弹数据进行扩容

bullets = Arrays.copyOf(bullets, bullets.length + bs.length);

// 通过数组的复制将英雄机发射出来的子弹添加到bullets数组中去

System.arraycopy(bs, 0, bullets, bullets.length - bs.length, bs.length);

}

}

/**

* 所有飞行物类移动的方法

*/

public void stepAction() {

for (int i = 0; i < flyings.length; i++) {// 敌机飞行一步

FlyingObject f = flyings[i];// 向上造型。获取每一个敌机对象

/*

* 判断对象属于哪个子类,因为子类的移动方式不一样 所以在这里得通过向下造型来操作

*/

if (f instanceof Airplane) {// 敌机移动方式

Airplane a = (Airplane) f;

a.step();

}

if (f instanceof Bee) {// 蜜蜂移动方式

Bee b = (Bee) f;

b.step();

}

}

// 英雄机移动的方式

hero.step();

// 子弹的移动方式

for (int i = 0; i < bullets.length; i++) {// 敌机飞行一步

Bullet b = bullets[i];// 获取每一个敌机对象

b.step();

}

}

/**

* 一个子弹和一堆敌人撞

*/

public void bang(Bullet b) {

int index = -1;// 记录被撞飞行物下标

// 遍历所有的飞行物对象

for (int i = 0; i < flyings.length; i++) {

FlyingObject f = flyings[i];

if (f.checkBang(b)) {

// 进入到这说明子弹和飞行物发生了碰撞

index = i;// 将被撞物的下标赋值给临时变量

break;

}

}

if (index != -1) {// 说明子弹和飞行物有碰撞

if (flyings[index] instanceof Enemy) {// 判断属于什么奖励类型.是敌人,则加分

score += ((Enemy) flyings[index]).getScore();

}

if (flyings[index] instanceof Award) {// 若为奖励,设置奖励

Bee bee = (Bee) flyings[index];

int type = bee.getType();// 获取奖励类型

if (type == 0) {

hero.addLife();// 加命

}

if (type == 1) {

hero.addDoubleFire();// 加双倍火力

}

}

// 对碰撞的飞行物进行缩容

FlyingObject fo = flyings[index];

flyings[index] = flyings[flyings.length - 1];

flyings[flyings.length - 1] = fo;

flyings = Arrays.copyOf(flyings, flyings.length - 1);

}

}

/**

* 一堆子弹和一堆敌人碰撞

*/

public void bangAction() {

// 遍历所有的子弹对象

for (int i = 0; i < bullets.length; i++) {

Bullet b = bullets[i];

bang(b);

}

}

/**

* 英雄机和敌机碰撞

*/

public void hitAction() {

int index = -1;// 记录被撞飞行物的下标

for (int i = 0; i < flyings.length; i++) {// 遍历所有敌人

FlyingObject f = flyings[i];// 获取每一个敌人

if (hero.hit(f)) {// 进入到这里说明英雄机和飞行物撞上了

index = i;

break;

}

}

if (index != -1) {

// 交换被撞的敌人与数组中的最后一个元素

FlyingObject fo = flyings[index];

flyings[index] = flyings[flyings.length - 1];

flyings[flyings.length - 1] = fo;

flyings = Arrays.copyOf(flyings, flyings.length - 1);// 缩容(去掉最后一个元素,即被撞的敌人对象)

hero.deleteLife();// 碰撞后要减命

hero.clearDoubleFire();// 碰撞后火力值清零

}

}

/**

* 检查游戏是否结束的方法

*/

public void checkGameOver() {

int life = hero.getLife();

if (life == 0) {

state = GAMEOVER;

}

}

/**

* 检查飞行物越界方法

* 思路:用逆向思维,将在窗口中显示的对象添加到相关的数组中

*/

public void outOfBoundsAction() {

int index = 0;// 记录数组的下标,记录对象的个数

// 声明一个在窗口中显示的飞行物对象数组

FlyingObject[] aliveFlying = new FlyingObject[flyings.length];// 默认所有的对象都活着

// 遍历所有的飞行物,把没有越界的放到下面,判断是否越界,越界的不添加到aliveFlying

for (int i = 0; i < flyings.length; i++) {

FlyingObject f = flyings[i];

if (!f.outOfBounds()) {

// 进入到这说明没有越界,添加到aliveFlying

aliveFlying[index++] = f;

}

}

// for循环遍历完之后,fAlive中存放的都是没有越界的对象

// 将fAlive这个数组中对象把flying数组覆盖掉

flyings = Arrays.copyOf(aliveFlying, index);

// 子弹数组和飞行物数组一致

index = 0;// 记录数组的下标,记录对象的个数

Bullet[] aliveBullet = new Bullet[bullets.length];// 默认所有的对象都活着

// 遍历所有的飞行物,把没有越界的放到下面,判断是否越界,越界的不添加到aliveBullet

for (int i = 0; i < bullets.length; i++) {

Bullet b = bullets[i];

if (!b.outOfBounds()) {

// 进入到这说明没有越界,添加到aliveBullet

aliveBullet[index++] = b;

}

}

// for循环遍历完之后,fAlive中存放的都是没有越界的对象

// 将fAlive这个数组中对象把flying数组覆盖掉

bullets = Arrays.copyOf(aliveBullet, index);

}

/**

* 通过定时器来执行程序和刷新页面

*/

Timer timer = new Timer();

/*

* 执行代码

*/

public void action() {

// 添加一个鼠标监听器

MouseAdapter l = new MouseAdapter() {

// 重写所需的方法

@Override

public void mouseMoved(MouseEvent e) {// 鼠标移动

// 获取鼠标的x坐标,y坐标

int x = e.getX();

int y = e.getY();

hero.moveTo(x, y);// 调用Hero类的方法

}

// 重写鼠标点击的方法

@Override

public void mouseClicked(MouseEvent e) {

if (state == START) {

state = RUNNING;

}

if (state == GAMEOVER) {

state = START;

score = 0;// 分数清零

hero.life = 3;// 恢复到初始状态

hero.clearDoubleFire();

state=START;

}

}

// 重写鼠标移入的方法

@Override

public void mouseExited(MouseEvent e) {

if (state == RUNNING) {

state = PAUSE;

}

}

// 重写鼠标移出的方法

@Override

public void mouseEntered(MouseEvent e) {

if (state == PAUSE) {

state = RUNNING;

}

}

};

timer.schedule(new TimerTask() {

@Override

public void run() {

if (state == RUNNING) {

addAction();// 调用 将敌机对象放入敌机数组 的方法

shootAction();// 英雄机发射出来的子弹

stepAction();// 调用 敌机移动 方法

bangAction();// 一堆子弹和一堆敌人碰撞

hitAction();// 英雄机撞

outOfBoundsAction();

checkGameOver();

}

repaint();// 刷新页面

}

}, 0, 30);

// 将监听器适配器添加到鼠标移动事件中去

this.addMouseMotionListener(l);// 添加鼠标运动监听器

this.addMouseListener(l);// 添加鼠标监听器

}

public static void main(String[] args) {

JFrame frame = new JFrame("飞机大战1.0"); // 创建一个窗体程序,相当于画板

TestGame game = new TestGame(); // 创建一个画板对象

frame.add(game); // 将面板(画笔)添加到frame

frame.setSize(WIDTH, HEIGHT);// 设置窗口的大小

frame.setVisible(true);// 设置窗口的显示

frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);// 设置窗口关闭按钮

frame.setAlwaysOnTop(true);// 设置窗口置顶显示

frame.setLocationRelativeTo(null);// 设置窗口居中

game.action(); // 执行

}

}

下载信息 飞机大战素材

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值