FlyBird(飞翔的小鸟)Java小游戏

FlyBird(飞翔的小鸟)Java小游戏

FlyBird(飞翔的小鸟)Java小游戏游戏简介《flappy bird》是一款由来自越南的独立游戏开发者Dong Nguyen所开发的作品,游戏于2013年5月24日上线,并在2014年2月突然暴红。2014年2月,《Flappy Bird》被开发者本人从苹果及谷歌应用商店(Google Play)撤下。2014年8月份正式回归App Store,正式加入Flappy迷们期待已久的多人对战模式。游戏中玩家必须控制一只小鸟,跨越由各种不同长度水管所组成的障碍。

在《FlappyBird》这款游戏中,玩家只需要用一根手指来操控,点击触摸屏幕,小鸟就会往上飞,不断的点击就会不断的往高处飞。放松手指,则会快速下降。所以玩家要控制小鸟一直向前飞行,然后注意躲避途中高低不平的管子。

1、在游戏开始后,点击屏幕,要记住是有间歇的点击屏幕,不要让小鸟掉下来。

2、尽量保持平和的心情,点的时候不要下手太重,尽量注视着小鸟。

3、游戏的得分是,小鸟安全穿过一个柱子且不撞上就是1分。当然撞上就直接挂掉,只有一条命。

上面简介是这款游戏的原始版本的简介,本文主要是根据这款游戏,进行逆向工程把这款游戏复刻一遍。

游戏展示

按键盘的上下键来控制小鸟上下移动,碰到管道会大量扣血,但是没有的时候会缓慢回血。

当生命值不是正数的时候,就结束游戏,按下空格可以重新开始。

我的代码如下

我的gitee地址:https://gitee.com/geek-li-hua/small-game

代码讲解文件结构:

在这里插入图片描述首先是util包,这个包中放置的就是一些工具类,这里面存放的就是整个项目需要用到的各种常数,希望修改游戏的各种初始大小的话,那么可以通过修改这个类中的各个常数。

Constant类代码语言:javascript复制package com.bird.util;

import java.awt.*;

public class Constant {

// 窗口的大小

public static final int FRAM_WIDTH=600;

public static final int FRAM_HEIGHT=500;

// 窗口的标题

public static final String FRAM_TITLE="Fly Bird";

// 窗口的初始化位置

public static final int FRAM_X=200;

public static final int FRAM_Y=200;

// 图片路径

public static final String BK_IMG_PATH = "img/bird_bk.png";

// 游戏背景颜色

public static final Color BK_COLOR = new Color(0x4B4CF); // 浅蓝色的背景

// 小鸟的图片资源

public static final String[] BIRD_IMG={"img/bird_normal.png", "img/bird_up.png","img/bird_down.png"};

// 障碍物图片资源

public static final String [] BARRIER_IMG_PATH={

"img/barrier.png","img/barrier_up.png","img/barrier_down.png"};

}GameUtil一个游戏的工具类。

代码语言:javascript复制package com.bird.util;

import javax.imageio.ImageIO;

import java.awt.image.BufferedImage;

import java.io.FileInputStream;

import java.io.IOException;

public class GameUtil {

public static BufferedImage loadBufferedImage(String imgPath){

try{

return ImageIO.read(new FileInputStream(imgPath));

} catch (IOException e){

e.printStackTrace();

}

return null;

}

}GameApp项目的启动类,这个类通过创建GameApp对象,来启动游戏。

代码语言:javascript复制package com.bird.app;

import com.bird.main.GameFrame;

public class GameApp {

public static void main(String[] args) {

new GameFrame();

}

}Barrier在Barrier类中,是创造游戏中的各种障碍物的,里面拥有着详细的注释,通过注释的内容,用户可以自定义里面的某些内容。

代码语言:javascript复制package com.bird.main;

import com.bird.util.Constant;

import com.bird.util.GameUtil;

import java.awt.*;

import java.awt.image.BufferedImage;

/*

* 障碍物类

* */

public class Barrier {

// 矩形参数

private Rectangle rect;

// 障碍物是否可以移动

private boolean mob = true;

// 障碍物的移动速度

private int speed = 3;

// 障碍物需要的三个图片

private static BufferedImage[] imgs;

// 障碍物状态

private boolean visible;

// 静态代码块初始化成员

static {

final int COUNT = 3;

// 类加载的时候将三个图片初始化

imgs = new BufferedImage[COUNT];

for (int i = 0; i < COUNT; i++) {

imgs[i] = GameUtil.loadBufferedImage(Constant.BARRIER_IMG_PATH[i]);

}

}

// 位置

private int x, y;

// 宽度和高度

private int width, height;

// 障碍物的类型

private int type;

public static final int TYPE_TOP_NORMAL = 0;

public static final int TYPE_BOTTOM_NORMAL = 2;

// 障碍物悬空

public static final int TYPE_HOVER_NORMAL = 4;

// 障碍物可以移动的状态

public static final int TYPE_MOBILE = 6;

// 获取障碍物的宽度和高度

public static final int BARRIER_WIDTH = imgs[0].getWidth();

public static final int BARRIER_HEIGHT = imgs[0].getHeight();

public static final int BARRIER_HEAD_WIDTH = imgs[1].getWidth();

public static final int BARRIER_HEAD_HEIGHT = imgs[1].getHeight();

// 构造器

public Barrier() {

// 初始化矩形参数

rect = new Rectangle();

}

// 宽度都是固定的,只需要控制障碍物的高度就可以了

public Barrier(int x, int y, int height, int type) {

this.x = x;

this.y = y;

this.width = BARRIER_WIDTH;

this.height = height;

this.type = type;

}

// 根据不同的类型绘制障碍物

public void draw(Graphics g){

switch ((type)){

case TYPE_TOP_NORMAL:

drawTopMormal(g);

break;

case TYPE_BOTTOM_NORMAL:

drawNormalTop(g);

break;

case TYPE_HOVER_NORMAL: // 中间的悬空障碍物

drawHoverNormal(g);

break;

case TYPE_MOBILE: // 障碍物可移动

drawMobile(g);

break;

}

}

// 绘制从上到下的障碍物

public void drawTopMormal(Graphics g){

// 求出所需要的障碍物的块数

// 公式:(当前障碍物的高度-障碍物的头部)/每一块的高度 然后 + 1

int count = (height - BARRIER_HEAD_HEIGHT)/BARRIER_HEIGHT + 1;

// for循环绘制障碍物

for (int i = 0; i < count; i++) {

g.drawImage(imgs[0], x, y + i * BARRIER_HEIGHT, null);

}

// 绘制头

int y = height - BARRIER_HEAD_HEIGHT;

g.drawImage(imgs[2], x - (BARRIER_HEAD_WIDTH - BARRIER_WIDTH) / 2, y, null);

// 给障碍物添加向左的速度

x -= speed;

if (x < -50){ // 当障碍物越界了

visible = false; // 状态为false

}

// 调用矩形

rect(g);

}

/*

* 绘制障碍物碰撞矩形

* */

public void rect(Graphics g){

int x1 = this.x;

int y1 = this.y;

int w1 = imgs[0].getWidth();

// g.setColor(Color.blue);

// g.drawRect(x1, y1, w1, height);

// 设置矩形参数

setRectangle(x1, y1, w1, height);

}

/*

* 障碍物的碰撞矩形参数

* */

public void setRectangle(int x, int y, int width, int height){

rect.x = x;

rect.y = y;

rect.width = width;

rect.height = height;

}

// 获取矩形

public Rectangle getRect() {

return rect;

}

//绘制从下向上的障碍物

private void drawNormalTop(Graphics g) {

//求出所需要障碍物的块数

int count = height/BARRIER_HEIGHT+1;

//for循环绘制障碍物

for (int i = 0; i < count; i++) {

g.drawImage(imgs[0], x, Constant.FRAM_HEIGHT-i*BARRIER_HEIGHT, null);

}

//绘制头

int y = Constant.FRAM_HEIGHT-height;

g.drawImage(imgs[1], x - (BARRIER_HEAD_WIDTH - BARRIER_WIDTH) / 2, y, null);

x -= speed;

if (x < -50){ // 当障碍物越界了

visible = false; // 状态为false

}

// 调用矩形

rect(g);

}

//绘制中间的障碍物

private void drawHoverNormal(Graphics g) {

//求出所需要障碍物的块数

int count = (height - BARRIER_HEAD_HEIGHT)/BARRIER_HEIGHT;

// 绘制上头

g.drawImage(imgs[1], x, y, null);

//for循环绘制障碍物

for (int i = 0; i < count; i++) {

g.drawImage(imgs[0], x, y+BARRIER_HEAD_HEIGHT + i * BARRIER_HEIGHT, null);

}

// 给障碍物绘制矩形外边

rect(g);

//绘制下头

int yll = y + height - BARRIER_HEAD_HEIGHT;

g.drawImage(imgs[2], x, yll, null);

x -= speed;

if (x < -50){ // 当障碍物越界了

visible = false; // 状态为false

}

}

// 绘制可以移动的障碍物

private void drawMobile(Graphics g) {

//求出所需要障碍物的块数

int count = (height - BARRIER_HEAD_HEIGHT)/BARRIER_HEIGHT;

// 绘制上头

g.drawImage(imgs[1], x, y, null);

//for循环绘制障碍物

for (int i = 0; i < count; i++) {

g.drawImage(imgs[0], x, y+BARRIER_HEAD_HEIGHT + i * BARRIER_HEIGHT, null);

}

// 给障碍物绘制矩形外边

rect(g);

//绘制下头

int yll = y + height - BARRIER_HEAD_HEIGHT;

g.drawImage(imgs[2], x, yll, null);

x -= speed;

if (x < -50){ // 当障碍物越界了

visible = false; // 状态为false

}

// 让物体移动

if (mob){ // 让障碍物向上移动

y += 5;

if (y >= 250){

mob = false;

}

}

else{ // 让障碍物向下移动

y -= 5;

if (y <= 100){

mob = true;

}

}

}

// 判断什么时候绘制下一组障碍物

public boolean isInFrame(){

return 600 - x > 150;

}

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 getHeight() {

return height;

}

public void setHeight(int height) {

this.height = height;

}

public int getType() {

return type;

}

public void setType(int type) {

this.type = type;

}

public boolean isVisible() {

return visible;

}

public void setVisible(boolean visible) {

this.visible = visible;

}

}Barrierpool在真实的游戏中,我们不仅仅是需要考虑,游戏的可以运行,对于游戏的设计者我们还需要考虑内存大小问题,是否会发生内存泄露或者内存溢出等等问题,我们在创造障碍物对象的时候,会不断的new对象,每一次new的过程就是一次新的内存申请,虽然最开始的时候这个占用的内存没有什么明显的感觉,但是当玩的时间久了,这个运行内存会越来越大,直到游戏崩溃,我见过很多非科班出身的游戏开发者,在内存及时处理这块往往都没有做,导致了,游戏玩着玩着就崩溃了。

代码语言:javascript复制package com.bird.main;

import java.util.ArrayList;

import java.util.List;

/*

* 为了避免反复的创建和销毁对象, 使用对象池来提前创建好一些对象

* 使用的时候从池中获得,使用完毕后,归还

* */

public class Barrierpool {

// 用于管理池中所有对象的容器

private static List pool = new ArrayList<>();

// 池中初始的对象个数

public static final int initCount = 16;

// 对象池中的最大个数

public static final int maxCount = 20;

static {

// 初始化池中的对象

for (int i = 0; i < initCount; i++) {

pool.add(new Barrier());

}

}

/*

* 从池中获取一个对象

*

* */

public static Barrier getPool(){

int size = pool.size();

// 如果池子中有对象才可以拿

if(size > 0){

// 移除并返回对象

System.out.println("拿走一个");

return pool.remove(size - 1);

}

else {

// 池中没有对象了 只能new

System.out.println("新的对象");

return new Barrier();

}

}

/*

* 将对象归还容器中

* */

public static void setPool(Barrier barrier){

if (pool.size() < maxCount){

pool.add(barrier);

System.out.println("容器归还了");

}

}

}Bird这个是鸟对象的类,如何创建一只小鸟,和这个小鸟的个性属性值怎么设置,这个在这个类里面我都通过了详细的注释进行了说明。

代码语言:javascript复制package com.bird.main;

import com.bird.util.Constant;

import com.bird.util.GameUtil;

import java.awt.*;

import java.awt.image.BufferedImage;

/*

* 小鸟类

* */

public class Bird {

// 小鸟矩形对象

private Rectangle rect;

// 小鸟加速度

private int acceleration;

// 小鸟的命数

private int bird_energe; // 默认1000滴血

private int bird_default = 1000; // 初始值

public int getBird_default() {

return bird_default;

}

public void setBird_default(int bird_default) {

this.bird_default = bird_default;

}

public int getBird_energe() {

return bird_energe;

}

public void setBird_energe(int bird_energe) {

this.bird_energe = bird_energe;

}

// 小鸟的生命 默认是存活

public boolean life = true;

// 存放小鸟图片

private BufferedImage[] images;

// 鸟的图片数量

public static final int BIRD_IMG_COUNT = 3;

// 鸟的状态

private int state;

public static final int STATE_NORMAR = 0; // 正常飞

public static final int STATE_UP = 1; // 向上飞

public static final int STATE_DOWN = 2; // 向下飞

// 小鸟位置

private int x = 200, y = 200;

// 小鸟移动方向 上下

public boolean up = false, down = false; // 默认不上不下

// 小鸟移动速度

private int speed = 4;

// 构造方法中初始化资源

public Bird(){

// 创建小鸟图片数组

images = new BufferedImage[BIRD_IMG_COUNT];

for (int i = 0; i < BIRD_IMG_COUNT; i++) {

// 加载每一张图片

images[i] =GameUtil.loadBufferedImage(Constant.BIRD_IMG[i]);

}

int w = images[0].getWidth();

int h = images[0].getWidth();

rect = new Rectangle(w, h);

bird_energe = getBird_default();

}

// 绘制小鸟

public void draw(Graphics g){

// 导入小鸟飞翔组件

flyLogic();

// 时刻绘制小鸟的图片

g.drawImage(images[state], x, y, null);

// 绘制小鸟的矩形

// g.drawRect(x, y, (int)rect.getWidth(), rect.height);

rect.x = this.x;

rect.y = this.y;

}

// 控制小鸟移动方向

public void flyLogic(){

if (up){ // 判断鸟垂直方向怎么运动

acceleration --;

y += acceleration;

if (acceleration < -10){ // 越往上扑腾越慢

acceleration = -10;

}

if (y < 20){ // 到达底部边界了

y = 20;

acceleration = 0; // 加速度设置为0防止越界

}

}

if (!up){ // 往下走

acceleration ++; // 越落地越快

y += acceleration;

if (acceleration > 10){ // 最高10

acceleration = 10;

}

if (y > 475){ // 到达顶部边界了

y = 475;

acceleration = 0; // 加速度设置为0防止越界

}

}

}

// 通过传入参数来判断小鸟垂直飞翔的方向

public void fly(int fly){

switch (fly){

case 1: // 如果是1的话那么就是往上飞

state=STATE_UP;

up = true;

break;

case 5: // 如果是5的话往下飞

state=STATE_DOWN;

up = false;

break;

}

}

// 获取矩形参数

public Rectangle getRect() {

return rect;

}

/*

* 重新绘制小鸟位置

* */

public void restartDraw(){

life = true;

x = 200;

y = 200;

}

}CloudCloud类云彩类,云彩会有哪些属性,在这个类中都会体现出来,至于云彩的移动效果是怎么做出来的,原理为给云彩一个向后的速度,这样就可以制作出云彩在动的效果了,想要给游戏更多的可扩展性,不如给游戏加上导弹或者什么道具,本质上和做云彩是一个道理的。

代码语言:javascript复制package com.bird.main;

import java.awt.*;

import java.awt.image.BufferedImage;

/*

* 云彩类

* */

public class Cloud {

// 云彩图片

private BufferedImage img;

// 云彩速度

private int speed;

// 云彩位置

private int x, y;

// 有参和无参构造方法

public Cloud() {

}

public Cloud(BufferedImage img, int speed, int x, int y) {

this.img = img;

this.speed = speed;

this.x = x;

this.y = y;

}

// 绘制方法

public void draw(Graphics g){

// 给云一个向后的速度

x-= speed;

g.drawImage(img, x, y, null);

}

/*

* 用于判断云彩是否飞出屏幕以外

* */

public boolean isOutFrame(){

if (x < -100){

return true;

}

return false;

}

}GameBackGround背景类,在这个类中会初始化很多游戏的背景相关的图片等等属性。

代码语言:javascript复制package com.bird.main;

import com.bird.util.Constant;

import com.bird.util.GameUtil;

import java.awt.*;

import java.awt.image.BufferedImage;

/*

* 游戏背景类

* */

public class GameBackGround {

//背景需要的资源图片

private BufferedImage bkimg;

// 构造器初始化资源

public GameBackGround(){

bkimg = GameUtil.loadBufferedImage(Constant.BK_IMG_PATH);

}

// 绘制图片

public void draw(Graphics g){

// 填充背景颜色

g.setColor(Constant.BK_COLOR);

// 画在窗口

g.fillRect(0, 0, Constant.FRAM_WIDTH, Constant.FRAM_HEIGHT);

// 设置背景为黑色

g.setColor(Color.black);

// 获取图片的高度和宽度

int height = bkimg.getHeight();

int width = bkimg.getWidth();

// 循环次数

int count = Constant.FRAM_WIDTH/width + 1;

for (int i = 0; i < count; i++) {

g.drawImage(bkimg, width * i, Constant.FRAM_HEIGHT-height, null);

}

}

}GameBarrierLayer这个类就是如何布置游戏中产生的障碍物。

代码语言:javascript复制package com.bird.main;

import com.bird.util.Constant;

import java.awt.*;

import java.io.*;

import java.util.ArrayList;

import java.util.List;

import java.util.Random;

/*

* 游戏中障碍物层类

* */

public class GameBarrierLayer {

// 游戏时间

private GameTime gameTime;

// 最高成绩的文本

private int txt;

// 随机种子

private Random random = new Random();

// 障碍物的集合

private List barriers;

public GameBarrierLayer(){

// 初始化障碍物

barriers = new ArrayList<>();

// 初始化时间

gameTime = new GameTime();

}

// 绘制障碍物

public void draw(Graphics g, Bird bird) throws IOException {

// Barrier barrier = new Barrier(200, 0, 200, 0);

// barriers.add(barrier);

// barriers.get(0).draw(g);

//

// Barrier barrier1 = new Barrier(300, 0, 200, 2);

// barriers.add(barrier1);

// barriers.get(1).draw(g);

// 画障碍物

for (int i = 0; i < barriers.size(); i++) {

Barrier barrier = barriers.get(i);

if (barrier.isVisible()){ // 如果对象存在

barrier.draw(g); // 画出对象

}

else {

// 如果不存在

Barrier remove = barriers.remove(i);

// 设置对象

Barrierpool.setPool(remove);

i --;

}

}

// 判断障碍物和小鸟是否撞上了

collideBird(bird);

// 加入逻辑控制组件

logic(g, bird);

}

// 逻辑组件

public void logic(Graphics g, Bird bird) throws IOException {

// 小鸟当前生命值

g.setColor(Color.red);

g.setFont(new Font("微软雅黑", 1, 20));

g.drawString("生命值:" + bird.getBird_energe(),370, 50);

if (barriers.size() == 0){

ran();

// 游戏刚开始的时候

gameTime.begin(); // 时间开始

// Barrier top = new Barrier(600, 0, numberTop, 0);

// barriers.add(top);

// Barrier down = new Barrier(600, 500-numberDown, numberDown, 2);

// barriers.add(down);

insert(600, 0, numberTop, 0);

insert(600, Constant.FRAM_HEIGHT -numberDown, numberDown, 2);

}

else

{

// 计算时间差

long differ = gameTime.differ();

// 设置时间样式

g.setColor(Color.white);

g.setFont(new Font("微软雅黑", 1, 20));

g.drawString("坚持了"+ differ + "秒", 30, 50);

// 显示最高成绩记录

txt = getText();

if (differ <= txt)

{

g.drawString("最高成绩:" + txt, 200, 50);

}

else

{

setText(String.valueOf(differ));

g.drawString("最高成绩:" + getText(), 200, 50);

}

// 判断最后一个障碍物是否完全进入屏幕内

Barrier last = barriers.get(barriers.size() - 1);

if (last.isInFrame()){

ran();

// Barrier top = new Barrier(600, 0, numberTop, 0);

// barriers.add(top);

// Barrier down = new Barrier(600, 500-numberDown, numberDown, 2);

// barriers.add(down);

if (number < 50){

insert(600, 32, 440, 4);

}

else if (number > 250) // 绘制可以移动的障碍物

{

insert(600, 125, 200, 6);

}

else

{

insert(600, 0, numberTop, 0);

insert(600, Constant.FRAM_HEIGHT -numberDown, numberDown, 2);

}

}

}

}

/*

* 用于从池中获取对象,并把参数封装成barrier,存入barriers数组中

*

* */

public void insert(int x, int y, int height, int type){

// 获取一个新的障碍物

Barrier top = Barrierpool.getPool();

// 设置参数并加入到障碍物数组里面

top.setX(x);

top.setY(y);

top.setHeight(height);

top.setType(type);

// 初始设置对象状态为true

top.setVisible(true);

barriers.add(top);

}

// 上方障碍物的高度

private int numberTop;

// 下方障碍物的高度

private int numberDown;

// 障碍物的种类数量

private int number;

// 产生两个100~500之间的随机高度

public void ran(){

numberTop = random.nextInt(400) + 100;

numberDown = random.nextInt(400) + 100;

number = random.nextInt(500);

if (numberTop + numberDown > 450){

ran(); // 如果两个管道的高度相加大于450 就代表两个管道重合了

// 然后重新生成

}

}

/*

* 判断障碍物和小鸟是否发生碰撞

* */

public boolean collideBird(Bird bird){

for (int i = 0; i < barriers.size(); i++) {

Barrier barrier = barriers.get(i);

// 判断矩形是否相交

if (barrier.getRect().intersects(bird.getRect())){

System.out.println("撞上了");

bird.setBird_energe(bird.getBird_energe() - random.nextInt(60)); // 随机扣除0~100点血

if (bird.getBird_energe() <= 0){

bird.life = false; // 小鸟装上之后就g了

}

return true;

}

else

{

if (bird.getBird_energe() == bird.getBird_default()){

}

else {

// 回血功能

bird.setBird_energe(bird.getBird_energe() + 1);

}

}

}

return false;

}

/*

* 用于清空障碍物的池子

* */

public void restart(){

barriers.clear();

}

File file = new File("record/game.txt");

/*

* 用于得到文件中的数据

* */

public int getText() throws IOException {

BufferedReader in = null;

try {

in = new BufferedReader(new FileReader(file));

} catch (FileNotFoundException e) {

throw new RuntimeException(e);

}

int read = Integer.parseInt(in.readLine()); // 把获取的字符串转换为int

in.close();

return read;

}

/*

* 用于存储数据

* */

public void setText(String str) throws IOException {

FileWriter fileWriter = null;

fileWriter = new FileWriter(file);

// 向文件中写数据

fileWriter.write(str);

fileWriter.close();

}

}GameFrame游戏框架类,在这个类中就把所有创建好了的类,Bird,GameBackGroud对象等等拼接组装到了一个框架中了。

代码语言:javascript复制public class GameFrame extends Frame { // 继承框架类

// 实例化gamebackGround类

private GameBackGround gameBackGround;

// 实例化Bird类

private Bird bird;

// 实例化GameFrontGround类

private GameFrontGround gameFrontGround;

// 实例化GameBarrierLayer类

private GameBarrierLayer gameBarrierLayer;

// 存放图片的集合

private BufferedImage buffimg = new BufferedImage(Constant.FRAM_WIDTH, Constant.FRAM_WIDTH, BufferedImage.TYPE_4BYTE_ABGR);

// 构造方法中初始化一些参数

public GameFrame(){

// 窗口是否可见

setVisible(true); // 设置窗口可见

// 窗口的大小

setSize(Constant.FRAM_WIDTH, Constant.FRAM_HEIGHT);

// 窗口的标题

setTitle(Constant.FRAM_TITLE);

// 窗口的初始化位置

setLocation(Constant.FRAM_X, Constant.FRAM_Y);

// 窗口的大小不可改变

setResizable(false);

// 窗口的关闭事件

addWindowListener(new WindowAdapter() {

@Override

public void windowClosing(WindowEvent e) {

System.exit(0); // 结束程序 返回0

}

});

// 初始化背景

initGamg();

// 启动线程

new run().start();

// 添加按键监听

addKeyListener(new KeyAdapter() {

@Override

public void keyPressed(KeyEvent e) {

// 按下向上键的话 然后向上飞

add(e);

}

@Override

public void keyReleased(KeyEvent e) {

// 松开向上键的话 就是往下飞

minu(e);

}

});

}

// 初始化对象

public void initGamg(){

// 加载背景图片

gameBackGround = new GameBackGround();

// 加载小鸟图片

bird = new Bird();

// 加载前景

gameFrontGround = new GameFrontGround();

// 加载障碍物

gameBarrierLayer = new GameBarrierLayer();

}

// 创建线程

class run extends Thread{

@Override

public void run(){

// 弄一个循环 持续的调用下面的方法

while(true){

repaint();

try {

// 设置每33毫秒刷新一次

Thread.sleep(33);

} catch (InterruptedException e) {

throw new RuntimeException(e);

}

}

}

}

// 重写update方法时刻更新背景

@Override

public void update(Graphics g) {

if (bird.life){

// 得到图片画笔

Graphics graphics = buffimg.getGraphics();

// 把画笔存入到背景和小鸟对象中

gameBackGround.draw(graphics);

bird.draw(graphics);

// 绘制前景

gameFrontGround.draw(graphics);

// 绘制障碍物

try {

gameBarrierLayer.draw(graphics, bird);

} catch (IOException e) {

throw new RuntimeException(e);

}

// 一次性的将图片绘制到屏幕

// 通过这个方法可以解决屏幕闪烁问题

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

}

else {

String over = "游戏结束";

g.setColor(Color.red);

// 设置字体属性

g.setFont(new Font("微软雅黑", 1, 60));

g.drawString(over, 120, 250);

// 重开提示词

String reset = "Space Reset Game";

g.drawString(reset, 25, 350);

}

}

// 按键 让小鸟往上飞

public void add(KeyEvent e){

// 通过按键事件e来获取按键的值

// 判断按键的值

switch (e.getKeyCode()){

// 如果是向上的按键的话 那么就传值1

case KeyEvent.VK_UP:

bird.fly(1);

break;

case KeyEvent.VK_SPACE:

if (bird.life == false){ // 当小鸟死了的时候按下空格键重开

restart();

}

break;

}

}

// 抬键 让小鸟往下飞

public void minu(KeyEvent e){

// 通过按键事件e来获取按键的值

// 判断按键的值

switch (e.getKeyCode()){

// 这里是还是up因为是松开向上键的事件

case KeyEvent.VK_UP:

bird.fly(5);

break;

}

}

/*

* 重置游戏

* */

public void restart(){

gameBarrierLayer.restart(); // 清空障碍物

bird.restartDraw(); // 重绘小鸟

bird.setBird_energe(bird.getBird_default());

}

}GameFrontGround游戏前景类,这个类就是用于制作游戏的一些前景,比如就是我们最开始的Cloud类,云类这些东西就是游戏的前景。

代码语言:javascript复制import com.bird.util.GameUtil;

import java.awt.*;

import java.awt.image.BufferedImage;

import java.util.ArrayList;

import java.util.List;

import java.util.Random;

/*

* 游戏的前景类

* */

public class GameFrontGround {

// 云彩的个数

public static final int CLOUND_COUNT = 2;

// 存放云彩的容器

private List clouds;

// 云彩的飞行速度

public static final int CLOUND_SPEED = 9;

// 使用得到的图片资源

private BufferedImage[] img;

// 用于产生随机数

private Random random;

// 构造器初始化数据

public GameFrontGround() {

clouds = new ArrayList<>();

img = new BufferedImage[CLOUND_COUNT];

// 容器中添加云彩图片

for (int i = 0; i < CLOUND_COUNT; i++) {

img[i] = GameUtil.loadBufferedImage("img/cloud" + i + ".png");

}

// 用于产生随机的云彩

random = new Random();

}

// 绘制云彩

public void draw(Graphics g){

logic(); // 载入逻辑组件

// 绘制云彩

for (int i = 0; i < clouds.size(); i++) {

clouds.get(i).draw(g);

}

}

/*

* 用于控制云彩的个数

* */

private void logic(){

if ((int)(500 * Math.random()) < 20){ // 这里就是控制云彩产生的频率的判断 可以自定设置 通过修改if中的表达式

// 创建云对象

// 我们有两张云朵的图片 随机产生,然后再试速度 位置的话 就是 从最右边开始生成 上下的话位置随机

Cloud cloud = new Cloud(img[random.nextInt(CLOUND_COUNT)], CLOUND_SPEED, 600, random.nextInt(150));

// 向容器中添加云彩

clouds.add(cloud);

}

for (int i = 0; i < clouds.size(); i++) {

Cloud cloud = clouds.get(i);

if (cloud.isOutFrame()){ // 如果云出界了

clouds.remove(i);

i -- ;

System.out.println("云被移除" + cloud);

}

}

}

}GameTime游戏的时间类,这类的目的是记录游戏的时间,开始时间,结束时间,时间差,这个的可以用来记录每次小鸟的游戏记录。

代码语言:javascript复制package com.bird.main;

/*

* 游戏计时器

* */

public class GameTime {

// 开始时间

private long beginTime;

// 结束时间

private long endTime;

// 时间差

public long differ;

public GameTime(){}

public void begin(){

beginTime = System.currentTimeMillis(); // 系统当前时间

}

// 开始与结束相差的时间

public long differ(){

endTime = System.currentTimeMillis(); // 系统当前时间

return differ = (endTime - beginTime) / 1000;

}

}

相关推荐

怎么把qq空间打开
365bet365官网

怎么把qq空间打开

📅 06-27 👁️ 6895
你知道什么叫情人?情人分几种?真正的情人你拥有过没有?
南投吃河豚中毒「兇手」品種出爐 吃2片就會致死
正版约彩365软件

南投吃河豚中毒「兇手」品種出爐 吃2片就會致死

📅 07-13 👁️ 6226