Java实现经典游戏Flappy Bird的示例代码

 更新时间:2022年02月26日 08:40:48   作者:小虚竹and掘金  
Flappy Bird是13年红极一时的小游戏,即摁上键控制鸟的位置穿过管道间的缝隙。本文将用Java语言实现这一经典的游戏,需要的可以参考一下

前言

《布谷鸟闯关-简单版》是一个基于java的布谷鸟闯关游戏,摁上键控制鸟的位置穿过管道间的缝隙,需要做碰撞检测,监听键盘事件,背景图片的切换,障碍物管道产生时y轴上需要随机位置。

主要设计

  • 设计游戏界面,用swing实现
  • 设计背景
  • 设计移动墙
  • 设计布谷鸟
  • 设计障碍物
  • 设计背景音乐和音效
  • 由几个关键的布尔类型变量start,crash,over是产生键键盘事件时用来控制界面显示的弹框的
  • 操作:空格键开始游戏,enter键取消"game over"弹框,摁空格键继续,上键(up)是对鸟的控制
  • 工具类ImageMgr专用于读取图片

功能截图

游戏开始:

控制布谷鸟

飞过障碍物

撞到障碍物,游戏结束

代码实现

游戏启动类

public class Main {
    public static void main(String[] args) {
        Cuckoo frame = new Cuckoo();
        while (true){
            try {
                Thread.sleep(100);
                if(!frame.crash){
                    frame.repaint();
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

核心类

/**
 * 1.窗口
 * 2.背景
 * 3.移动墙
 * 4.布谷鸟
 * 5.障碍物
 * 6.背景音乐
 * 7.音效
 * 8.欢迎界面
 * 9.game over
 */
public class Cuckoo extends Frame {
    private int step;
    private int score;
    private int height;
    private int moveLeft;
    private int pipeMove;

    boolean crash = false;
    private boolean over = false;
    private boolean start = false;

    private static int bird_y = 270;
    private static final int L_X = 800;
    private static final int L_Y = 200;
    private static final int SPEED = 2;
    private static final int BIRD_X = 100;
    private static final int GAME_X_Y_0 = 0;
    private static final int GAME_WIDTH = 288;
    private static final int GAME_HEIGHT = 512;
    private static final int PIPE_WIDTH = ImageMgr.pipe.getWidth();
    private static final int PIPE_HEIGHT = ImageMgr.pipe.getHeight();
    private static final int READY_WIDTH = ImageMgr.ready.getWidth();
    private static final int READY_HEIGHT = ImageMgr.ready.getHeight();
    private static final int START_WIDTH = ImageMgr.start.getWidth();
    private static final int BIRD_WIDTH = ImageMgr.bird[0].getWidth();
    private static final int BIRD_HEIGHT = ImageMgr.bird[0].getWidth();
    private static final int GROUND_HEIGHT = ImageMgr.ground.getHeight();
    private static final int GAME_OVER_WIDTH = ImageMgr.gameOver.getWidth();
    private static final int GAME_OVER_HEIGHT = ImageMgr.gameOver.getHeight();
    private static final int BACKGROUND_HEIGHT = ImageMgr.background.getHeight();

    private static Image offScreenImage;
    private static Rectangle pipeRectangle1;
    private static Rectangle pipeRectangle2;
    private static Rectangle birdRectangle;

    Cuckoo(){
        setVisible(true);
        setResizable(false);
        //setTitle("cuckoo");
        setBounds(L_X, L_Y,GAME_WIDTH,GAME_HEIGHT);

        addKeyListener(new KeyAdapter() {
            @Override
            public void keyPressed(KeyEvent e) {
                switch (e.getKeyCode()){
                    case KeyEvent.VK_SPACE : start = true;break;
                    case KeyEvent.VK_ENTER : reopen();break;
                }
            }

            @Override
            public void keyReleased(KeyEvent e) {
                if (e.getKeyCode() == KeyEvent.VK_UP) {
                    bird_y -= 20;
                }
            }
        });

        addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                System.exit(0);
            }
        });
    }

    @Override
    public void update(Graphics g) {
        if(offScreenImage == null){
            offScreenImage = this.createImage(GAME_WIDTH,GAME_HEIGHT);
        }
        Graphics gOffScreen = offScreenImage.getGraphics();
        Color c = gOffScreen.getColor();
        gOffScreen.setColor(Color.BLACK);
        gOffScreen.fillRect(0,0,GAME_WIDTH,GAME_HEIGHT);
        gOffScreen.setColor(c);
        paint(gOffScreen);
        g.drawImage(offScreenImage,0,0,null);
    }

    @Override
    public void paint(Graphics g) {
        background(g);
        ground(g);
        start(g);

        if(start){
            bird(g);
            pipe(g);
            colliedWith();
            gameOver(g);
            score(g);
        }

    }

    //如果碰撞后,可以嗯enter键重开
    private void reopen(){
        if(crash){
            score = 0;
            over = false;
            crash = false;
            start = false;
            moveLeft = 0;
            pipeMove = 0;
            //bird_y = 270;//继上次死的位置开始
        }
    }

    private void score(Graphics g){
        Font font = new Font("微软雅黑",Font.BOLD,18);
        g.setFont(font);
        Color c = g.getColor();
        g.setColor(Color.lightGray);
        g.drawString("score " + score,20,70);
        g.setColor(c);
    }

    private void background(Graphics g){
        g.drawImage(ImageMgr.background,
                GAME_X_Y_0 - moveLeft,GAME_X_Y_0,
                GAME_WIDTH - moveLeft,GAME_HEIGHT,
                GAME_X_Y_0,
                GAME_X_Y_0,
                GAME_WIDTH,
                GAME_HEIGHT, null);
        g.drawImage(ImageMgr.background,
                GAME_WIDTH-1 - moveLeft,GAME_X_Y_0,
                GAME_WIDTH*2 - moveLeft, GAME_HEIGHT,
                GAME_X_Y_0,
                GAME_X_Y_0,
                GAME_WIDTH,
                GAME_HEIGHT, null);
        moveLeft += SPEED;
        //游戏启动计分
        if(start && moveLeft % 100 == 0){
            score += 1;
        }
        if(moveLeft >= GAME_WIDTH){
            moveLeft = 0;
        }
    }

    private void ground(Graphics g){
        g.drawImage(ImageMgr.ground,0,BACKGROUND_HEIGHT - GROUND_HEIGHT,null);
    }

    private void bird(Graphics g){
        Color c = g.getColor();
        g.setColor(Color.BLUE);
        g.drawRect(BIRD_X, bird_y,BIRD_WIDTH,BIRD_HEIGHT);
        g.setColor(c);

        g.drawImage(ImageMgr.bird[step++], BIRD_X, bird_y,null);
        if(step >= ImageMgr.bird.length){
            step = 0;
        }

        if(start){
            bird_y += 4;
        }

        birdRectangle = new Rectangle(BIRD_X,bird_y,BIRD_WIDTH,BIRD_HEIGHT);
    }

    private void pipe(Graphics g){
        drawPipe(g);
        pipeMove += SPEED;
        if(pipeMove >= GAME_WIDTH + PIPE_WIDTH){
            pipeMove = 0;
            Random ran = new Random();
            height = ran.nextInt(10)*20;
            drawPipe(g);
        }

    }

    private void drawPipe(Graphics g){
        g.setColor(Color.RED);
//        g.drawRect(GAME_WIDTH - pipeMove,GAME_HEIGHT/5*3 - height,PIPE_WIDTH,PIPE_HEIGHT);
//        g.drawRect(GAME_WIDTH - pipeMove,-GAME_HEIGHT/5*4 - height,PIPE_WIDTH,PIPE_HEIGHT);

        g.drawImage(ImageMgr.pipe,GAME_WIDTH - pipeMove,GAME_HEIGHT/5*3 - height,null);
        g.drawImage(ImageMgr.pipe,GAME_WIDTH - pipeMove,-GAME_HEIGHT/5*4 - height,null);

        pipeRectangle1 = new Rectangle(GAME_WIDTH - pipeMove,GAME_HEIGHT/5*3 - height,PIPE_WIDTH,PIPE_HEIGHT);
        pipeRectangle2 = new Rectangle(GAME_WIDTH - pipeMove,-GAME_HEIGHT/5*4 - height,PIPE_WIDTH,PIPE_HEIGHT);
    }

    private void gameOver(Graphics g){
        if(over){
            g.drawImage(ImageMgr.gameOver,GAME_WIDTH/2 - GAME_OVER_WIDTH/2, GAME_HEIGHT/2 - GAME_OVER_HEIGHT,null);
        }
    }

    private void start(Graphics g){
        if(!start){
            g.drawImage(ImageMgr.ready,GAME_WIDTH/2 - READY_WIDTH/2, GAME_HEIGHT/2 - READY_HEIGHT,null);
            g.drawImage(ImageMgr.start,GAME_WIDTH/2 - START_WIDTH/2, GAME_HEIGHT/2,null);
        }
    }

    private void colliedWith(){
        if(birdRectangle.intersects(pipeRectangle1) || birdRectangle.intersects(pipeRectangle2)){
            crash = true;
            over = true;
            //gameOver(g);
        }
    }
}

工具类

public class ImageMgr {
    static BufferedImage background,ground,pipe,gameOver,start,ready;
    static BufferedImage[] bird = new BufferedImage[3];
    private static final ImageMgr INSTANCE = new ImageMgr();
    //nothing
    private ImageMgr(){
        initImage();
    };

    private void initImage(){
        try {
            background = ImageIO.read(Objects.requireNonNull(Cuckoo.class.getClassLoader().getResourceAsStream("images/bg_light.png")));
            ground = ImageIO.read(Objects.requireNonNull(Cuckoo.class.getClassLoader().getResourceAsStream("images/ground.png")));
            pipe = ImageIO.read(Objects.requireNonNull(Cuckoo.class.getClassLoader().getResourceAsStream("images/pipe.png")));
            gameOver = ImageIO.read(Objects.requireNonNull(Cuckoo.class.getClassLoader().getResourceAsStream("images/gameover.png")));
            start = ImageIO.read(Objects.requireNonNull(Cuckoo.class.getClassLoader().getResourceAsStream("images/start.png")));
            ready = ImageIO.read(Objects.requireNonNull(Cuckoo.class.getClassLoader().getResourceAsStream("images/ready.png")));

            for(int i = 0;i < 3;i++){
                bird[i] = ImageIO.read(Objects.requireNonNull(Cuckoo.class.getClassLoader().getResourceAsStream("images/blueBird_" + (i+1) + ".png")));
            }
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }

    public static ImageMgr getInstance(){
        return INSTANCE;
    }
}

总结

通过此次的《布谷鸟闯关-简单版》实现,让我对JAVA的相关知识有了进一步的了解,对java这门语言也有了比以前更深刻的认识。

java的一些基本语法,比如数据类型、运算符、程序流程控制和数组等,理解更加透彻。java最核心的核心就是面向对象思想,对于这一个概念,终于悟到了一些。

以上就是Java实现经典游戏Flappy Bird的示例代码的详细内容,更多关于Java Flappy Bird游戏的资料请关注脚本之家其它相关文章!

相关文章

  • Springboot实现多文件上传代码解析

    Springboot实现多文件上传代码解析

    这篇文章主要介绍了Springboot实现多文件上传代码解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-04-04
  • SpringBoot数据库恢复的两种方法mysqldump和mysqlbinlog

    SpringBoot数据库恢复的两种方法mysqldump和mysqlbinlog

    binlog用来实现主从复制,也常用来误删数据库找回丢失的记录,本文主要介绍了SpringBoot数据库恢复的两种方法mysqldump和mysqlbinlog,具有一定的参考价值,感兴趣的可以了解一下
    2024-01-01
  • Java数据库连接池之proxool_动力节点Java学院整理

    Java数据库连接池之proxool_动力节点Java学院整理

    Proxool是一种Java数据库连接池技术。方便易用,便于发现连接泄漏的情况
    2017-08-08
  • SpringBoot自定义注解API数据加密和签名校验

    SpringBoot自定义注解API数据加密和签名校验

    这篇文章主要介绍了SpringBoot自定义注解API数据加密和签名校验,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-04-04
  • MybatisPlus3.5.5与pagehelper starter2.1.0冲突的问题解决

    MybatisPlus3.5.5与pagehelper starter2.1.0冲突的问题解决

    在使用MybatisPlus 3.5.5与PageHelper Starter 2.1.0时,由于引用了不同版本的jsqlparser库(4.6与4.7),会导致运行时错误,解决方案涉及确认依赖版本,本文就来介绍一下,感兴趣的同学可以下载学习
    2024-10-10
  • Java中文乱码解决方案全解析,让你的程序“说人话”!

    Java中文乱码解决方案全解析,让你的程序“说人话”!

    探索Java中文乱码解决方案全解析,让你的程序终于能“说人话”!厌倦了看着一串串的问号或者奇怪符号吗?跟着我们的指南,一步步轻松解锁中文乱码的秘密,让你的代码清晰表达每一个字,需要的朋友可以参考下
    2024-02-02
  • Java里volatile关键字是什么意思

    Java里volatile关键字是什么意思

    volatile具有synchronized关键字的“可见性”,但是没有synchronized关键字的“并发正确性”,也就是说不保证线程执行的有序性。这篇文章主要介绍了Java里volatile关键字是什么意思的相关资料,需要的朋友可以参考下
    2016-11-11
  • Java中seata框架的XA模式详解

    Java中seata框架的XA模式详解

    这篇文章主要介绍了Java中seata框架的XA模式详解,Seata 是一款开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务,Seata 将为用户提供了 AT、TCC、SAGA 和 XA 事务模式,为用户打造一站式的分布式解决方案,需要的朋友可以参考下
    2023-08-08
  • springboot2.x集成swagger的方法示例

    springboot2.x集成swagger的方法示例

    这篇文章主要介绍了springboot2.x集成swagger的方法示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-05-05
  • Java中的值传递和引用传递实例介绍

    Java中的值传递和引用传递实例介绍

    java 中没有引用传递,都是值传递的,可以通过传递副本修改对象的,副本交换,并不影响原引用
    2013-09-09

最新评论