Java开发《飞机大战》
作者:互联网
《飞机大战》是一款由腾讯开发的经典射击类游戏。
下面介绍用Java开发《飞机大战》的步骤。
GitHub地址:https://github.com/xydang2019/ShootGame.git
创建一个普通的Java项目,编写好类以及导入相关贴图:
主要代码如下:
1、奖励类
package com.bzyd.shoot;
/**表示奖励,提供奖励类型属性及获取奖励类型的方法,蜜蜂实现此方法*/
public interface Award {
int DOUBLE_FIRE = 0;//0表示双倍火力
int LIFE = 1;//1表示1条命
/**获取奖励类型,0或1*/
int getType();
}
2、敌人类
package com.bzyd.shoot;
/**敌人类,提供获取分数的方法,敌飞机实现此接口。*/
public interface Enemy {
/**获取分数*/
int getSroce();
}
3、飞行物类
package com.bzyd.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();
/**
* 检查飞行物(敌机、蜜蜂)是否被子弹击中
* bee.x < bullet.x < bee.x + width
* &&
* bee.y < bullet.y < bee.y + height
* @param bullet 子弹对象
* @return true 表示被击中了
*/
public boolean shootBy(Bullet bullet) {
int x = bullet.x;//子弹x坐标
int y = bullet.y;//子弹y坐标
return x > this.x && x < this.x + width && y > this.y && y < this.y + height;
}
/**
* 检查是否越界(体现多态性)
* @return true 出界与否
*/
public abstract boolean outOfBounds();
}
4、敌飞机类
package com.bzyd.shoot;
import java.util.Random;
/**敌飞机类,继承FlyingObject类,实现Enemy接口*/
public class Airplane extends FlyingObject implements Enemy {
private int speed = 2;
/**实现获取分数的方法*/
@Override
public int getSroce() {
return 5;
}
public Airplane() {
image = ShootGame.airplane;
width = image.getWidth();
height = image.getHeight();
Random r = new Random();
y = -height;
x = r.nextInt(ShootGame.WIDTH-width);
}
@Override
public void step() {//移动
y += speed;
}
@Override
public boolean outOfBounds() {
return y>ShootGame.HEIGHT;
}
}
5、蜜蜂类
package com.bzyd.shoot;
import java.util.Random;
/**蜜蜂类,继承FlyingObject,实现Award接口*/
public class Bee extends FlyingObject implements Award {
private int xSpeed = 1;//x方向移动速度
private int ySpeed = 2;//y方向移动速度
private int awardType;//奖励类型
@Override
public int getType() {
return awardType;
}
public Bee() {
image = ShootGame.bee;//继承来的image属性就是ShootGame类中加载得到的静态Bee的图片
width = image.getWidth();//蜜蜂的宽度
height = image.getHeight();//蜜蜂的高度
Random r = new Random();
y = -height;//y坐标赋值
x = r.nextInt(ShootGame.WIDTH - width);//x坐标赋值
awardType = r.nextInt(2);//给奖励类型赋值
}
@Override
public void step() {
x += xSpeed;//x方向移动
y += ySpeed;//y方向移动
if (x > ShootGame.WIDTH - width) {//如果到达右边界就向左移动
xSpeed = -1;
}
if (x < 0) {//如果到达左边界就向右移动
xSpeed = 1;
}
}
@Override
public boolean outOfBounds() {
return y > ShootGame.HEIGHT;
}
}
6、英雄机类
package com.bzyd.shoot;
import java.awt.image.BufferedImage;
/**英雄机类,是飞行物,继承FlyingObject类*/
public class Hero extends FlyingObject {
protected BufferedImage[] images = {};//表示Hero的贴图,有两张组成
protected int index = 0;//两张图片进行交替显示的计数
private int doubleFire;//双倍火力子弹数量
private int life;//增命的数量
public Hero() {
life = 3;
doubleFire = 0;
image = ShootGame.hero0;
width = image.getWidth();
height = image.getHeight();
images = new BufferedImage[] {ShootGame.hero0,ShootGame.hero1};
x = 150;
y = 400;
}
@Override
public void step() {
if (images.length > 0) {
image = images[index++/10%images.length];
}
}
/**射击(产生子弹)*/
public Bullet[] shoot() {
int xStep = width/4;
int yStep = 20;//子弹到飞机的位置
if (doubleFire > 0) {//双倍火力
Bullet[] bullets = new Bullet[2];//双倍火力一次发射2颗子弹
bullets[0] = new Bullet(x+xStep, y-yStep);//子弹发射点1
bullets[1] = new Bullet(x+3*xStep,y-yStep);//子弹发射点2
doubleFire -= 2;//子弹数量不断减少
return bullets;
}else {//单倍火力
Bullet[] bullets = new Bullet[1];//单倍火力一次发射1颗子弹
bullets[0] = new Bullet(x+2*xStep, y-yStep);
return bullets;
}
}
/**鼠标移动(设定鼠标点为英雄的中心位置)*/
public void moveTo(int x,int y) {
this.x = x-width/2;//英雄机的x=鼠标的x-width/2
this.y = y-height/2;//英雄机的y=鼠标的y-height/2
}
/**获取双倍火力*/
public void addDoubleFire() {
doubleFire += 40;
}
/**增命*/
public void addLife() {
life++;
}
/**获取英雄机的命数*/
public int getLife() {
return life;
}
@Override
public boolean outOfBounds() {
return false;
}
/**减命*/
public void subtractLife() {
life--;
}
/**重置双倍火力*/
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;
return this.x + this.width/2 > x1 && this.x + this.width/2 < x2
&& this.y + this.height/2 > y1
&& this.y + this.height/2 < y2;
}
}
7、子弹类
package com.bzyd.shoot;
/**子弹类,属于飞行物,继承FlyingObject类*/
public class Bullet extends FlyingObject {
private int speed = 3;//子弹速度
public Bullet(int x,int y) {
this.x = x;
this.y = y;
image = ShootGame.bullet;
}
@Override
public void step() {
y -= speed;//子弹向上移动
}
@Override
public boolean outOfBounds() {
return y < -height;
}
}
8、主类
package com.bzyd.shoot;
import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Arrays;
import java.util.Random;
import java.util.Timer;
import java.util.TimerTask;
/**
* 飞机大战
*/
public class ShootGame extends JPanel {//继承面板类
public static final int WIDTH = 400;//面板宽
public static final int HEIGHT = 654;//面板高
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 static BufferedImage background;//背景图片
public static BufferedImage start;//游戏开始图片
public static BufferedImage airplane;//敌飞机图片
public static BufferedImage bee;//蜜蜂图片
public static BufferedImage bullet;//子弹图片
public static BufferedImage hero0;//英雄机图片1
public static BufferedImage hero1;//英雄机图片2
public static BufferedImage pause;//暂停图片
public static BufferedImage gameover;//游戏结束图片
private FlyingObject[] flyings = {};//敌机蜜蜂数组
private Bullet[] bullets = {};//子弹数组
private Hero hero = new Hero();//英雄机
private Timer timer;//定时器
private int intervel = 10;//时间间隔10毫秒
private int score = 0;//计分
private int state;//游戏状态
/**加载图片*/
static {
try {
//ImageIO.read(URL input),得到BufferedImage对象
//类对象.getResource("文件名"),在当前类的包下查找文件,得到URL对象
background = ImageIO.read(ShootGame.class.getResource("/background.png"));
start = ImageIO.read(ShootGame.class.getResource("/start.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"));
pause = ImageIO.read(ShootGame.class.getResource("/pause.png"));
gameover = ImageIO.read(ShootGame.class.getResource("/gameover.png"));
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 随机生成飞行物
* @return 飞行物对象
*/
public static FlyingObject nextOne() {
Random r = new Random();
int type = r.nextInt(20);//[0,20)
if (type == 0) {
return new Bee();
}else {
return new Airplane();
}
}
/**重构paint方法(绘画组件,是Jpanel的父类JComponent中的方法)*/
@Override
public void paint(Graphics g) {
g.drawImage(background,0,0,null);//画背景图
paintHero(g);//画英雄机
paintBullets(g);//画子弹
paintFlyingObjects(g);//画飞行物(敌机和蜜蜂)
paintScore(g);//画分数和命
paintState(g);//画游戏状态
}
/**画英雄机*/
public void paintHero(Graphics g) {
g.drawImage(hero.getImage(),hero.getX(),hero.getY(),null);
}
/**画子弹*/
public void paintBullets(Graphics g) {
for (int i = 0; i < bullets.length; i++) {
Bullet b = bullets[i];
g.drawImage(b.getImage(),b.getX(),b.getY(),null);
}
}
/**画飞行物*/
public void paintFlyingObjects(Graphics g) {
for (int i = 0; i < flyings.length; i++) {
FlyingObject f = flyings[i];
g.drawImage(f.getImage(),f.getX(),f.getY(),null);
}
}
/**画分数和命数*/
public void paintScore(Graphics g) {
int x = 10;
int y = 25;
Font font = new Font(Font.SANS_SERIF, Font.BOLD, 14);
g.setColor(new Color(0x3A3B3B));//设置画笔颜色
g.setFont(font);//设置字体
g.drawString("SCORE: "+score,x,y);//画分数
y += 20;
g.drawString("LIFE: "+hero.getLife(), x, y);//画命
}
/**画游戏状态*/
public void paintState(Graphics g) {
switch (state) {
case START:
g.drawImage(start, 0, 0, null);
break;
case PAUSE:
g.drawImage(pause, 0, 0, null);
break;
case GAME_OVER:
g.drawImage(gameover, 0, 0, null);
break;
}
}
/**实现飞行物入场:即每调用该方法40次就随机生成一个飞行物放入flyings数组中*/
int flyEnterIndex = 0;//飞行物入场计数
public void enterAction() {
flyEnterIndex++;
if (flyEnterIndex%40 == 0) {//400毫秒=10*40
FlyingObject obj = nextOne();//随机生成一个飞行物
flyings = Arrays.copyOf(flyings,flyings.length+1);//扩容
flyings[flyings.length-1] = obj;//放在最后
}
}
/**所有飞行物:敌机、蜜蜂、子弹、英雄机的移动*/
public void stepAction() {
/**飞行物移动*/
for (int i = 0; i < flyings.length; i++) {
FlyingObject f = flyings[i];
f.step();
}
/**子弹移动*/
for (int i = 0; i < bullets.length; i++) {
Bullet b = bullets[i];
b.step();
}
/**英雄机移动*/
hero.step();
}
/**实现英雄机射击,即每调用该方法30次就发射一次子弹,并将发射的子弹存储到bullets数组中*/
int shootIndex = 0;//射击计数
public void shootAction() {
shootIndex++;
if (shootIndex%30 == 0) {
Bullet[] bs = hero.shoot();
bullets = Arrays.copyOf(bullets,bullets.length+bs.length);//扩容
System.arraycopy(bs,0,bullets,bullets.length-bs.length,bs.length);//追加
}
}
/**子弹与飞行物碰撞检测*/
public void bangAction() {
for (int i = 0; i < bullets.length; i++) {
bang(bullets[i]);//所有子弹逐个检测
}
}
private void bang(Bullet bullet) {
int index = -1;//击中的飞行物的索引
for (int i = 0; i < flyings.length; i++) {//逐个飞行物检测
FlyingObject obj = flyings[i];
if (obj.shootBy(bullet)) {//判断是否击中
index = i;//记录被击中的飞行物的索引
break;//如果当前子弹击中了,就结束循环,外循环判断下一枚子弹
}
}
if (index != -1) {//如果与击中的飞行物
FlyingObject one = flyings[index];//记录被击中的飞行物
FlyingObject temp = flyings[index];//与最后一个交换
flyings[index] = flyings[flyings.length-1];
flyings[flyings.length-1] = temp;
flyings = Arrays.copyOf(flyings,flyings.length-1);//缩容,删除最后一个被击中的
//检测被击中的飞行物的类型,如果是敌机就算分,如果是蜜蜂就给予奖励(增命或者双倍火力)
if (one instanceof Enemy) {
Enemy e = (Enemy)one;
score += e.getSroce();
}
if (one instanceof Award) {
Award a = (Award)one;
int type = a.getType();
switch (type) {
case Award.DOUBLE_FIRE:
hero.addDoubleFire();
break;
case Award.LIFE:
hero.addLife();
break;
}
}
}
}
/**删除越界飞行物及子弹*/
public void outOfBoundsAction() {
int index = 0;
FlyingObject[] flyingLives = new FlyingObject[flyings.length];
//用来存储活着的飞行物
for (int i = 0; i < flyings.length; i++) {
FlyingObject f = flyings[i];
if (! f.outOfBounds()) {
flyingLives[index] = f;//不越界的留着
index++;
}
}
flyings = Arrays.copyOf(flyingLives, index);//将不越界的飞行物留着
index = 0;//重置为0
Bullet[] bulletLives = new Bullet[bullets.length];
//用来存储活着的子弹
for (int i = 0; i < bullets.length; i++) {
Bullet b = bullets[i];
if (! b.outOfBounds()) {
bulletLives[index] = b;//不越界的留着
index++;
}
}
bullets = Arrays.copyOf(bulletLives, index);//将不越界的子弹留着
}
/**判断游戏是否结束*/
public boolean isGameOver() {
for (int i = 0; i < flyings.length; i++) {
FlyingObject obj = flyings[i];
int index = -1;
if (hero.hit(obj)) {//检测英雄机与飞行物是否碰撞
hero.subtractLife();
hero.setDoubleFire(0);
index = i;
}
if (index != -1) {
FlyingObject temp = flyings[index];
flyings[index] = flyings[flyings.length-1];
flyings[flyings.length-1] = temp;
flyings = Arrays.copyOf(flyings,flyings.length-1);
}
}
return hero.getLife() <= 0;
}
/**检查游戏是否已经结束*/
public void checkGameOverAction() {
if (isGameOver()) {
state = GAME_OVER;
}
}
/**实现10毫秒入场一个飞机或者蜜蜂,并使所有飞行物移动一步,最后重画页面*/
public void action() {//启动执行代码
//鼠标监听事件
MouseAdapter event = new MouseAdapter() {
@Override
public void mouseMoved(MouseEvent e) {//鼠标移动事件
if (state == RUNNING) {//运行时移动英雄机
int x = e.getX();
int y = e.getY();
hero.moveTo(x, y);
}
}
@Override
public void mouseEntered(MouseEvent e) {//鼠标进入事件
if (state == PAUSE) {//暂停时运行
state = RUNNING;
}
}
@Override
public void mouseExited(MouseEvent e) {//鼠标退出事件
if (state != GAME_OVER) {
state = PAUSE;//游戏未结束,则设置为暂停
}
}
@Override
public void mouseClicked(MouseEvent e) {//鼠标点击事件
switch (state) {
case START:
state = RUNNING;
break;
case GAME_OVER://游戏结束,重新开始
flyings = new FlyingObject[0];
bullets = new Bullet[0];
hero = new Hero();
score = 0;
state = START;
break;
}
}
};
this.addMouseListener(event);//处理鼠标点击操作
this.addMouseMotionListener(event);//处理鼠标滑动操作
timer = new Timer();
timer.schedule(new TimerTask() {//使用匿名内部类创建一个任务TimerTask
@Override
public void run() {
if (state == RUNNING) {
enterAction();//飞行物入场(实例方法可以直接调用实例方法)
stepAction();//走一步
shootAction();//射击
bangAction();//检测击中
outOfBoundsAction();//删除越界飞行物与子弹
checkGameOverAction();//检查游戏是否结束
}
repaint();//重画页面,调用paint()方法
}
}, intervel, intervel);//安排指定的任务从指定的延迟后开始进行重复的固定延迟执行。
}
/**主方法*/
public static void main(String[] args) {
JFrame frame = new JFrame("飞机大战");//创建游戏窗口实例
ShootGame shootGame = new ShootGame();//面板对象
frame.add(shootGame);//添加面板到窗口
frame.setSize(WIDTH, HEIGHT);//设置窗口初始大小
frame.setAlwaysOnTop(true);//初始位置总是在最上面
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//设置关闭窗口就结束进程(必须)
frame.setLocationRelativeTo(null);//设置窗口初始位置
frame.setVisible(true);//设置窗体是否显示
shootGame.action();//启动执行
}
}
编译后:
运行主类ShootGame的main()方法即可启动游戏:
标签:飞机,Java,int,void,大战,飞行物,flyings,public,ShootGame 来源: https://blog.csdn.net/weixin_44360895/article/details/113809690