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

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

大家好,欢迎来到IT知识分享网。

  • 作者简介:一名后端开发人员,每天分享后端开发以及人工智能相关技术,行业前沿信息,面试宝典。
  • 座右铭:未来是不可确定的,慢慢来是最快的。
  • 个人主页:极客李华-CSDN博客
  • 合作方式:私聊+
  • 这个专栏内容:BAT等大厂常见后端java开发面试题详细讲解,更新数目100道常见大厂java后端开发面试题。
  • 我的CSDN社区:https://bbs.csdn.net/forums/99ebabb5bfc4d513a8
  • 微信公众号,抖音,b站等平台统一叫做:极客李华,加入微信公众号领取各种编程资料,加入抖音,b站学习面试技巧,职业规划

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

游戏简介

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

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

游戏展示

在这里插入图片描述
按键盘的上下键来控制小鸟上下移动,碰到管道会大量扣血,但是没有的时候会缓慢回血。
在这里插入图片描述

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

代码讲解

文件结构
在这里插入图片描述

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

Constant类

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

一个游戏的工具类。

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对象,来启动游戏。

package com.bird.app; import com.bird.main.GameFrame; public class GameApp { 
    public static void main(String[] args) { 
    new GameFrame(); } } 

Barrier

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

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的过程就是一次新的内存申请,虽然最开始的时候这个占用的内存没有什么明显的感觉,但是当玩的时间久了,这个运行内存会越来越大,直到游戏崩溃,我见过很多非科班出身的游戏开发者,在内存及时处理这块往往都没有做,导致了,游戏玩着玩着就崩溃了。

package com.bird.main; import java.util.ArrayList; import java.util.List; /* * 为了避免反复的创建和销毁对象, 使用对象池来提前创建好一些对象 * 使用的时候从池中获得,使用完毕后,归还 * */ public class Barrierpool { 
    // 用于管理池中所有对象的容器 private static List<Barrier> 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

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

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; } } 

Cloud

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

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

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

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

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

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<Barrier> 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对象等等拼接组装到了一个框架中了。

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类,云类这些东西就是游戏的前景。

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<Cloud> 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

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

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; } } 

如果大家觉得有用的话,可以关注我下面的微信公众号,极客李华,我会在里面更新更多行业资讯,企业面试内容,编程资源,如何写出可以让大厂面试官眼前一亮的简历等内容,让大家更好学习编程,我的抖音,B站也叫极客李华。

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/119595.html

(0)
上一篇 2025-11-04 12:45
下一篇 2025-11-04 13:10

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注微信