java飞机小游戏,实现了以下功能:
1.我方小飞机可以通过鼠标移动来控制。
2.蜜蜂(必须打死而不是碰到,并且碰到蜜蜂会失去生命值)分为两种奖励 获得生命值或者子弹翻3倍。
3.当鼠标移动到界面外可导致游戏暂停。
4.我方英雄机生命值为3,当撞到敌机时生命值-1,敌机消失,为0时游戏结束。
5.有不同类型大小敌机,随机出现。
6.当敌机被子弹打中时,分数+10,当敌机被撞到时生命值-1.
目录
一、项目演示效果
二、项目源码
1、JAVA工程文件
2、Airplane.java
3、Award.java
4、Bee.java
5、BigAirplane.java
6、Bullet.java
7、Enemy.java
8、FlyingObject.java
9、Hero.java
10、ShootGame.java
11、Sky.java
三、图片资料
一、项目演示效果
二、项目源码
1、JAVA工程文件
2、Airplane.java
package TestShootgameDemo;
/**
* 小敌机类
* 飞行物、得分
* @author liujiacheng
*
*/
import java.awt.image.BufferedImage;
public class Airplane extends FlyingObject implements Enemy{
//定义小敌机图片集
public static BufferedImage[] images;
/*使用静态代码块 加载小敌机图片*/
static {
images=new BufferedImage[5];
//循环加载5张图片
for (int i = 0; i < images.length; i++) {
images[i]=loadImage("airplane"+i+".png");
}
}
//定义当前小敌机特有坐标
private int speed;
/*构造方法*/
public Airplane() {
super(49,36);//调用父类的构造方法 初始化参数
speed=2;
}
/*打中得分*/
@Override
public int getScore() {
// TODO Auto-generated method stub
return 10;
}
/*小敌机移动*/
@Override
public void step() {
// TODO Auto-generated method stub
y+=speed;
}
//定义小敌机死了的下标
int deadIndex=1;
/*获得小敌机图片---爆炸效果*/
@Override
public BufferedImage getImage() {
// TODO Auto-generated method stub
//判断小敌机是否活着
if (isLife()) {
return images[0];
}else if (isDead()) {//判断是否死了
//从第二张图片进行切换
BufferedImage img=images[deadIndex++];
//判断是否切换到最后一张图片
if (deadIndex==images.length) {
//移出飞行物
state=REMOVE;
}
return img;
}
return null;
}
/*小敌机是否越界*/
@Override
public boolean outOfBounds() {
// TODO Auto-generated method stub
return this.y>=ShootGame.jframeHeight ;
}
}
3、Award.java
package TestShootgameDemo;
/**
* 打中蜜蜂后的奖励接口
* 定义双倍火力或者生命值的奖励类型为0或1
* -目的是为了随机产生数字0或1来确定奖励类型
* @author liujiacheng
*
*/
public interface Award {
//定义奖励类型
public int DOUBLE_FIRE=0;//双倍火力
public int LIFE=1;//生命值
/*获取奖励类型的方法*/
public int getAward();
}
4、Bee.java
package TestShootgameDemo;
/**
* 蜜蜂类
* 飞行物 奖励
* @author liujiacheng
*
*/
import java.awt.image.BufferedImage;
import java.util.Random;
public class Bee extends FlyingObject implements Award {
/*定义图片集*/
private static BufferedImage[] images;
/*静态代码块*/
static {
images = new BufferedImage[5];
for (int i = 0; i < images.length; i++) {
images[i]=loadImage("bee"+i+".png");
}
}
private int xSpeed;//x坐标增量
private int ySpeed;//y坐标增量
private int awardType;//奖励类型(0/1)
/*构造方法*/
public Bee() {
super(60,50);
xSpeed=1;
ySpeed=2;
Random rand=new Random();
awardType =rand.nextInt(2);//0/1
}
/*获取奖励*/
@Override
public int getAward() {
// TODO Auto-generated method stub
return awardType;
}
/*小蜜蜂的移动*/
@Override
public void step() {
x+=xSpeed;
y+=ySpeed;
//判断是否碰撞左右边界
if(x<=0||x>=ShootGame.jframeWidth-this.width) {
xSpeed*=-1;//改变方向
}
}
//定义死了的下标
int deadIndex=1;
//获取当前图片--爆炸
@Override
public BufferedImage getImage() {
// TODO Auto-generated method stub
if(isLife()) {
return images[0];
}else if (isDead()) {
BufferedImage img=images[deadIndex++];
if (deadIndex==images.length) {
state=REMOVE;
}
return img;
}
return null;
}
@Override
public boolean outOfBounds() {
// TODO Auto-generated method stub
return this.y>=ShootGame.jframeHeight;
}
}
5、BigAirplane.java
package TestShootgameDemo;
/**
* 小敌机类
* 飞行物、得分
* @author liujiacheng
*
*/
import java.awt.image.BufferedImage;
public class BigAirplane extends FlyingObject implements Enemy{
//定义小敌机图片集
public static BufferedImage[] images;
/*使用静态代码块 加载小敌机图片*/
static {
images=new BufferedImage[5];
//循环加载5张图片
for (int i = 0; i < images.length; i++) {
images[i]=loadImage("bigplane"+i+".png");
}
}
//定义当前小敌机特有坐标
private int speed;
/*构造方法*/
public BigAirplane() {
super(69,99);//调用父类的构造方法 初始化参数
speed=3;
}
/*打中得分*/
@Override
public int getScore() {
// TODO Auto-generated method stub
return 10;
}
/*小敌机移动*/
@Override
public void step() {
// TODO Auto-generated method stub
y+=speed;
}
//定义小敌机死了的下标
int deadIndex=1;
/*获得小敌机图片---爆炸效果*/
@Override
public BufferedImage getImage() {
// TODO Auto-generated method stub
//判断小敌机是否活着
if (isLife()) {
return images[0];
}else if (isDead()) {//判断是否死了
//从第二张图片进行切换
BufferedImage img=images[deadIndex++];
//判断是否切换到最后一张图片
if (deadIndex==images.length) {
//移出飞行物
state=REMOVE;
}
return img;
}
return null;
}
/*小敌机是否越界*/
@Override
public boolean outOfBounds() {
// TODO Auto-generated method stub
return this.y>=ShootGame.jframeHeight ;
}
}
6、Bullet.java
package TestShootgameDemo;
/**
* 子弹类
* 飞行物
* @author liujiacheng
*
*/
import java.awt.image.BufferedImage;
public class Bullet extends FlyingObject {
/*定义图片*/
public static BufferedImage image;
/*静态代码块*/
static {
image=loadImage("bullet.png");
}
/*定义坐标增量*/
/*当前子弹的坐标增量*/
private int speed=50;
/*构造方法*/
public Bullet(int x,int y) {
super(8,14,x,y);
}
/*子弹移动*/
@Override
public void step() {
// TODO Auto-generated method stub
y-=speed;
}
@Override
public BufferedImage getImage() {
// TODO Auto-generated method stub
if(isLife()) {
return image;
}else if (isDead()) {
state=REMOVE;
}
return null;
}
/*判断子弹是否越界*/
@Override
public boolean outOfBounds() {
// TODO Auto-generated method stub
return this.y<=-this.height;
}
}
7、Enemy.java
package TestShootgameDemo;
/**
* 打中敌人(大、小敌机)后的奖励接口
* @author liujiacheng
*
*/
public interface Enemy {
/*得分*/
public int getScore();
}
8、FlyingObject.java
package TestShootgameDemo;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Random;
import javax.imageio.ImageIO;
/**
* 飞行物总类---抽象类
* 所有实体类的父类
* 1.包括飞行物所共有的属性,构造方法,自定义方法
* 2.使用实体类继承该类实现抽象方法
* 3.体现代码复用,增强代码可读性。
* @author liujiacheng
*
*/
public abstract class FlyingObject {
/*定义飞行物的基本属性*/
//飞行的状态
public static final int LIFE=0;//活着
public static final int DEAD=1;//死了
public static final int REMOVE=2;//删除
//定义当前飞行物的初始状态--活着
public int state=LIFE;
/*定义飞行物的基本属性*/
protected int width;//宽
protected int height;//高
protected int x;//x坐标
protected int y;//y坐标
/*定义不同的构造方法*/
/*
* 两种
* 1.英雄机、天空、子弹提供的
* 2.大小敌机、蜜蜂提供的
*/
//定义英雄机、天空、子弹提供的构造方法
public FlyingObject(int width,int height,int x,int y) {
this.width=width;
this.height=height;
this.x=x;
this.y=y;
}
//定义大小敌机、蜜蜂提供的构造方法
public FlyingObject(int width,int height) {
this.width=width;
this.height=height;
//初始化飞行物出现的范围
Random ran=new Random();
x=ran.nextInt(ShootGame.jframeWidth-this.width);
y=-this.height;
}
/*自定义方法-读取图片的方法*/
public static BufferedImage loadImage(String filename){
BufferedImage imgBufferedImage;
try {
imgBufferedImage = ImageIO.read(FlyingObject.class.getResource(filename));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
throw new RuntimeException();
} //加载,路径
return imgBufferedImage;
}
/*自定义方法 飞行物移动*/
public abstract void step();
/*自定义方法--获取图片*/
public abstract BufferedImage getImage();
/*判断是否活着*/
public boolean isLife() {
return state==LIFE;
}
/*判断是否删除*/
public boolean isRemove() {
return state==REMOVE;
}
/*判断是否死了*/
public boolean isDead() {
return state==DEAD;
}
/*自定义方法--绘制图片*/
public void paintObject(Graphics g) {
g.drawImage(getImage(), x, y, null);
}
/*检测飞行物是否越界*/
public abstract boolean outOfBounds();
/*碰撞算法:this-敌人 other:子弹或者英雄*/
public boolean hit(FlyingObject other) {
//计算X的最大最小边界
int x1=this.x-other.width;
int x2=this.x+this.width;
//计算y的最大最小边界
int y1=this.y-other.height;
int y2=this.y+this.height;
//获取英雄机或者子弹的xy坐标
int x=other.x;
int y=other.y;
return x>=x1&&x<=x2&&y>=y1&&y<=y2;
}
/*飞行物去死*/
public void goDead() {
state=DEAD;//死了但是没有删除
}
}
9、Hero.java
package TestShootgameDemo;
import java.awt.image.BufferedImage;
public class Hero extends FlyingObject{
/*定义图片集*/
private static BufferedImage[] images;
/*静态代码块加载图片*/
static {
images=new BufferedImage[2];
for (int i = 0; i < images.length; i++) {
images[i]=loadImage("hero"+i+".png");
}
}
/*定义双倍火力*/
private int doubleFire;
/*定义生命值*/
private int life;
/*构造方法*/
public Hero() {
super(97, 124,150,400);
life=3; //初始生命值
doubleFire=0;//初始为单倍火力
}
/*英雄机随鼠标移动*/
public void moveTo(int x,int y) {
//将鼠标移动至英雄机中间
this.x=x-this.width/2;
this.y=y-this.height/2;
}
@Override
public void step() {
// TODO Auto-generated method stub
//英雄级随鼠标移动
}
/*获取英雄机图片*/
int deadIndex=0;
@Override
public BufferedImage getImage() {
// TODO Auto-generated method stub
if(isLife()) {
return images[deadIndex++%2];
}
return null;
}
@Override
public boolean outOfBounds() {
// TODO Auto-generated method stub
return false;
}
/*英雄机发射子弹的核心算法*/
public Bullet[] shoot() {
//计算英雄机1/15宽
int xStep=this.width/4;
int yStep=20;//英雄机和子弹间的距离
if(doubleFire>0) { //双倍火力
//定义两束子弹
Bullet[] bs= new Bullet[3];
bs[0]=new Bullet(this.x+xStep,this.y-yStep);
bs[1]=new Bullet(this.x+2*xStep, this.y-yStep);
bs[2]=new Bullet(this.x+3*xStep,this.y-yStep);
//双倍子弹发射一定数量后,自动变为单倍
doubleFire-=2;
return bs;
}else {
Bullet[] bs= new Bullet[1];
bs[0]=new Bullet(this.x+2*xStep, this.y-yStep);
return bs;
}
}
/*自定义方法--英雄机减少性命*/
public void substractLife() {
life--;
}
/*自定以方法-英雄机增加性命*/
public void addLife() {
life++;
}
/*自定义方法-获取英雄机的命*/
public int getLife() {
return life;
}
/*自定义方法增加火力值*/
public void addDoubleFire() {
doubleFire+=40;
}
/*自定义方法-火力清0*/
public void clearDoubleFire() {
doubleFire=0;
}
}
10、ShootGame.java
package TestShootgameDemo;
import java.awt.Graphics;
import java.awt.Toolkit;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.util.Arrays;
import java.util.Random;
import java.util.Timer;
import java.util.TimerTask;
import javax.swing.JFrame;
import javax.swing.JPanel;
/**
*
* @author Liujiacheng
*代码实现
* 1.如图
*/
public class ShootGame extends JPanel{
/*定义窗体的基本属性*/
public static int width = Toolkit.getDefaultToolkit().getScreenSize().width;
//获取屏幕的宽
public static int height = Toolkit.getDefaultToolkit().getScreenSize().height;
//获取屏幕的高
public static int jframeWidth = 400;//窗体的宽
public static int jframeHeight = 700;//窗体的高
//获取屏幕居中的X坐标
public static int jframeX=width/2-jframeWidth/2;
//获取居中Y坐标
public static int jframeY=height/2-jframeHeight/2;
/*
* 设置游戏状态
* 启动、运行、暂停、结束
* 默认状态为启动
*/
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;//默认状态为启动
/*定义图片集*/
public static BufferedImage start;//启动图
public static BufferedImage pause;//暂停图
public static BufferedImage gameover;//游戏结束图
/*加载图片*/
static {
start = FlyingObject.loadImage("start.png");//开始图片
pause = FlyingObject.loadImage("pause.png");//暂停图片
gameover = FlyingObject.loadImage("gameover.png");//结束图片
}
/*定义实体类*/
private Sky sky = new Sky();//天空
private Hero hero = new Hero();//英雄机
private FlyingObject[] enemies = {};//敌人(大、小敌机、蜜蜂)数组
private Bullet[] bullets = {};//子弹数组
/*生成敌人的核心算法*/
public FlyingObject nextOne() {
/*实例化随机数对象--随机产生敌人的类型(大、小敌机、蜜蜂)*/
Random ran = new Random();
/*0-20内的随机数来生成对象*/
int type = ran.nextInt(20);//0-19
if(type < 4) {//0-3
return new Bee();//产生蜜蜂
} else if(type < 12) {//4-11
return new Airplane();//小敌机
} else{//12-19
return new BigAirplane();//大敌机
}
}
/*敌人入场计数器*/
int enterIndex = 0;
/*敌人入场事件*/
public void enterAction() {
enterIndex ++;//定时器计数器,表示每s产生的对象的次数
if(enterIndex % 8 == 0) {//定时器每400ms走一次--生成一个对象
FlyingObject obj = nextOne();//随机生成一个敌人
enemies = Arrays.copyOf(enemies, enemies.length + 1);//扩容
enemies[enemies.length - 1] = obj;//将敌人放在数组的最后
}
}
/*子弹入场计数器*/
int shootIndex = 0;
/*子弹入场事件*/
public void shootAction() {
shootIndex ++;
if(shootIndex % 10 == 0) {//每300ms走一次
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 stepAction() {
sky.step();//天空移动
hero.step();//英雄机移动
//子弹移动
for (int i = 0; i < bullets.length; i++) {
bullets[i].step();
}
//敌人移动
for (int i = 0; i < enemies.length; i++) {
enemies[i].step();
}
}
/*删除越界的飞行物事件*/
public void outOfBoundsAction() {
//定义不越界敌人数组的下标和个数
int index = 0;
//定义不越界敌人的数组
FlyingObject[] enemyLives = new FlyingObject[enemies.length];
//遍历所有敌人
for (int i = 0; i < enemies.length; i++) {
//获取每一个敌人
FlyingObject f = enemies[i];
//判断敌人是否越界
if(!f.outOfBounds()) {//不越界
enemyLives[index] = f;//存入不越界数组
index ++;//计数不越界的敌人
}
}
//将不越界敌人数组赋值到enemies--转化为原数组
enemies = Arrays.copyOf(enemyLives, index);
index = 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);
}
/*定义玩家得分*/
int score = 0;
/*敌人与子弹碰撞事件*/
public void BulletBangAction() {
//遍历所有子弹
for (int i = 0; i < bullets.length; i++) {
Bullet b = bullets[i];//获取每一颗子弹
//遍历所有敌人
for (int j = 0; j < enemies.length; j++) {
FlyingObject f = enemies[j];//获取每一个敌人
//判断是否碰撞
if(f.hit(b) && f.isLife() && b.isLife()) {
f.goDead();//敌人去死
b.goDead();//子弹去死
//碰撞后的处理逻辑
if(f instanceof Enemy) {
Enemy en = (Enemy)f;//获取当前碰撞的敌人
score += en.getScore();//累加得分
}
if(f instanceof Award) {
Award aw = (Award)f;
//获取奖励类型
int type = aw.getAward();
//根据奖励类型判断奖励项
switch (type) {
case Award.DOUBLE_FIRE:
hero.addDoubleFire();//增加双倍火力
break;
case Award.LIFE:
hero.addLife();//增加生命值
break;
}
}
}
}
}
}
/*英雄机和敌人碰撞事件*/
public void heroBangAction() {
//遍历所有敌人
for (int i = 0; i < enemies.length; i++) {
FlyingObject f = enemies[i];//获取每一个敌人
//判断是否撞上
if(f.hit(hero) && f.isLife() && hero.isLife()) {
f.goDead();//敌人去死
hero.substractLife();//减命
hero.clearDoubleFire();//火力清0
}
}
}
/*检测是否游戏结束*/
public void checkGameOverAction() {
if(hero.getLife() < 0) {//判断英雄机的生命值是否为0
state = GAME_OVER;//游戏状态变为GameOver
}
}
/*启动程序的执行*/
public void action() {
MouseAdapter l = new MouseAdapter() {
@Override
public void mouseMoved(MouseEvent e) {//鼠标移动事件
//判断当前状态是否为运行状态
if(state == RUNNING) {
int x = e.getX();//获取鼠标x坐标
int y = e.getY();//获取鼠标y坐标
hero.moveTo(x, y);//英雄机移动
}
}
@Override
public void mouseClicked(MouseEvent e) {//鼠标点击事件
//根据不同的状态做出不同的结果
switch (state) {
case START:
state = RUNNING;//开始->运行
break;
case GAME_OVER:
state = START;//结束->启动
//初始化参数
score = 0;
sky = new Sky();
hero = new Hero();
bullets = new Bullet[0];
enemies = new FlyingObject[0];
break;
}
}
@Override
public void mouseExited(MouseEvent e) {//鼠标移出事件
if(state == RUNNING) {
state = PAUSE;//运行->暂停
}
}
@Override
public void mouseEntered(MouseEvent e) {//鼠标移入事件
if(state == PAUSE) {
state = RUNNING;//暂停->运行
}
}
};
//添加鼠标监听事件
this.addMouseListener(l);
//添加鼠标滑动事件
this.addMouseMotionListener(l);
//定义定时器对象
Timer timer = new Timer();
int intervel = 10;//10ms
timer.schedule(new TimerTask() {
@Override
public void run() {//定时器任务
//定义执任务,没10ms走一次
if(state == RUNNING) {
enterAction();//大、小敌蜜蜂机入场
shootAction();//子弹入场
stepAction();//飞行物移动
outOfBoundsAction();//删除越界的飞行物
BulletBangAction();//子弹与敌人碰撞
heroBangAction();//英雄机与敌人碰撞
checkGameOverAction();//检测游戏是否结束
}
repaint();//重绘
}
}, intervel,intervel);
}
/*绘制图形*/
@Override
public void paint(Graphics g) {
sky.paintObject(g);//绘制天空
hero.paintObject(g);//绘制英雄机
for (int i = 0; i < enemies.length; i++) {//绘制敌人
enemies[i].paintObject(g);
}
for (int i = 0; i < bullets.length; i++) {
bullets[i].paintObject(g);//绘制子弹
}
/*绘制得分*/
g.drawString("SCORE:" + score, 10, 25);
/*绘制生命值*/
g.drawString("LIFE:" + hero.getLife(), 10, 45);
/*根据不同状态绘制不同图片*/
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;
}
}
public static void main(String[] args) {
JFrame jf = new JFrame();//实例化窗体对象
jf.setTitle("飞行大战-初级");//设置标题
jf.setBounds(jframeX, jframeY, jframeWidth, jframeHeight);//设置位置及尺寸
ShootGame sg = new ShootGame();//实例化当前类对象
jf.add(sg);//将画板添加在窗体容器中
jf.setVisible(true);//窗体可见
sg.action();//程序启动
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
11、Sky.java
package TestShootgameDemo;
/**
* 天空类
* 飞行物
* @author liujiacheng
*
*/
import java.awt.Graphics;
import java.awt.image.BufferedImage;
public class Sky extends FlyingObject {
/*定义背景图片*/
public static BufferedImage image;
/*静态代码块加载图片*/
static {
image=loadImage("background.png");
}
/*属性*/
private int speed;
private int y2; //第二张图片(同一张)的y坐标
/*构造方法*/
public Sky() {
super(ShootGame.jframeWidth, ShootGame.jframeHeight, 0, 0);
speed=1;
y2=-this.height;//第二张图片的初始位置
}
/*背景图片的移动*/
@Override
public void step() {
y+=speed;
y2+=speed;
if(y>=ShootGame.jframeHeight) {
y=-ShootGame.jframeHeight;
}
if (y2>=ShootGame.jframeHeight) {
y2=-ShootGame.jframeHeight;
}
}
@Override
public BufferedImage getImage() {
// TODO Auto-generated method stub
return image;
}
@Override
public boolean outOfBounds() {
// TODO Auto-generated method stub
return false;
}
@Override
public void paintObject(Graphics g) {
g.drawImage(getImage(), x, y, null);
g.drawImage(getImage(), x, y2, null);
}
}
三、图片资料
百度网盘链接:https://pan.baidu.com/s/1f0lCq-o2nLZDSfknsQrn6w
提取码:ljco