Java实战之飞翔的小鸟小游戏

前言

一个简单的单机小游戏:flypybird ,用来巩固java基础。

涉及主要知识点:JFrame 、 JPanel 、 继承、 键盘/鼠标监听 、 多线程 、 工具类设计

提示:这是大致的实现过程,实际实现过程有一定的修改,具体以源码为准。

一、大体思路

1、首先要有一个框架,作为主程序入口,这里使用 JFrame  类。

2、然后需要有一个画布,用来把游戏场景画上去,然后在上面添加键盘/鼠标监听来控制,这里使用的是 JPenal 类。

3、需要创建几个类:小鸟、地面、障碍物柱子、一个获取图片的工具类

4、然后逐步添加到画布中,实现对应的功能

二、具体步骤

2.1 创建窗体类

相当于窗户的框架,有了框架才能装玻璃。然后也是主程序执行的入口

2.1.1 具体代码

public class MainFrame extends JFrame {

    /* 图标 */
    BufferedImage Icon;

    /*
     * 构造器用来初始化框架*/
    public MainFrame() throws IOException {
        /* 设置图标 */
        Icon = ImageUtil.getImage("bird1_1.png");
        setIconImage(Icon);
        /* 设置关闭 */
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        /* 设置标题 */
        setTitle("飞翔的小鸟");
        /* 设置尺寸*/
        setSize(298, 550);
        /* 设置大小不可变 */
        setResizable(false);
        /* 设置窗体居中 */
        setLocationRelativeTo(null);
    }

    /*
     * 主程序
     * */
    public static void main(String[] args) throws IOException {

        MainFrame mainFrame = new MainFrame();
        mainFrame.setVisible(true);

    }
}

2.1.2 效果展示

2.1.3 小结

大体框架做好,考虑到后面还需要使用比较多的图片,因此接下来先建一个工具类,用来获取图片资源。

三、创建一个获取图片的工具类

3.1 具体代码

/*
 * 工具类,用来获取图片
 * */
public class ImageUtil {
    public static BufferedImage getImage(String name) throws IOException {

        return ImageIO.read(new BufferedInputStream(new FileInputStream("birdGame/flyBird/" + name)));
    }
}

3.2 小结

图片获取方式改为用工具类获取,只需要输入图片名+格式。后期方便减少重复代码的书写。

四、创建画布

使用 Jpanel 类,创建画布(相当于玻璃) ,就能在上面画游戏的画面了。后期还需要在上面添加鼠标/键盘监听。

4.1 具体代码

public class GameJPenal extends JPanel {
    /*
     * 各种参数应该设置在这
     * */
    BufferedImage bg; 

    /*
     * 构造方法用来完成数据的初始化
     * */
    public GameJPenal() throws IOException {
        bg = ImageUtil.getImage("bg_day.png");
    }

    /*
     * 开始游戏的方法
     * */
    public void start() {
        gameStart = true;
        Thread myThread = new Thread(new MyThread());
        myThread.start();
    }

    //绘制的方法
    @Override
    public void paint(Graphics g) {
        g.drawImage(bg, 0, 0, 288, 512, null);     //背景

    }
}

4.2 效果展示

先在main方法中创建对象,把画布添加到框架里面,注意要重新在最后设置可见,否者看不到背景

/*
     * 主程序
     * */
    public static void main(String[] args) throws IOException {

        MainFrame mainFrame = new MainFrame();

        GameJPenal gameJPenal = new GameJPenal();

        mainFrame.add(gameJPenal);  /* 画布添加到框架上 */

        mainFrame.setVisible(true);

        gameJPenal.requestFocus(); /* 请求屏幕焦点 ,否则无法实现键盘监听 */

    }

接下来就可以运行,效果如下

4.3 小结

这里需要注意一个点就是请求屏幕焦点:后期如果要做键盘监听的话必须有焦点,否则无法实现键盘控制

五、把地面画上去

5.1 代码

public class Ground {
    BufferedImage land;
    /*  x,y 是地面在画布上的坐标 */
    private int x;
    private int y;
    private final int SPEED = 4;  //控制地面移动的速度

    public Ground() throws IOException {
        land = ImageUtil.getImage("land.png");
        x = 0;
        y = 512 - land.getHeight();
    }

    /*
     * 地面移动的效果
     * */
    public void move() {
        if (x == (288 - land.getWidth())) {
            x = 0;
        }
        x-=SPEED;
    }

    /*
    * get方法
    * */
    public int getX() {
        return x;
    }

    public int getY() {
        return y;
    }
}

接下来就是把地面的图片用画笔画上去

g.drawImage(land.landImg, land.x, land.y, land.w, land.h, null);

六、创建一个新线程让画面动起来

先把变量添加到 GamePanel 类

Land land;    //地面
    Thread newThread;  //线程
    boolean gameStart; // 游戏状态变量,准备状态为 false ,游戏开始为 true
    boolean gameOver;  //状态变量, 游戏开始为false ,游戏结束为true

在GamePanel 构造器里面初始化变量,创建一个新线程,用死循环不断调用地面移动的方法,然后重画画面,实现移动的效果

这里还加了俩个游戏的状态变量,主要是为了方便实现游戏的准备画面和游戏结束后可以重新开始游戏:

boolean gameStart;  //游戏准备状态
boolean gameOver;   //游戏结束状态
/*
     * 新开一个线程
     * */
    class MyThread implements Runnable {
        @Override
        public void run() {
            while (true) {
                ground.move();
                c0.move();
                c1.move();
                bird.fly();
                bird.move();
                isGameOver();
                repaint();
                if (gameOver) {
                    return;
                }
                try {
                    Thread.sleep(20);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

小结:

这时候画面已经能动起来了,接下来就是把其它的对象创建出来添加进去:鸟 、 障碍物(柱子)

七、创建柱子类

和创建地面类似,需要有他的坐标点和高度,同时为了画面柱子的连续性,需要俩组不同的柱子,

/*
 * 柱子类
 * */
public class Column {

    private final int SPEED = 2;
    int w1;
    int h1;
    int x1;
    int y1;
    BufferedImage img1;

    int w2;
    int h2;
    int x2;
    int y2;
    BufferedImage img2;

    /*
     * 构造方法
     * 初始化对象*/
    public Column(int i) throws IOException {

        img1 = ImageUtil.getImage("pipe_down.png");
        w1 = img1.getWidth() / 2;
        h1 = img1.getHeight();
        x1 = 288 + i * 150;
        y1 = -100 - i * 20;

        img2 = ImageUtil.getImage("pipe_up.png");
        w2 = img2.getWidth() / 2;
        h2 = img2.getHeight();
        x2 = 288 + i * 150;
        y2 = h2 - i * 25 -20;
    }

    /*柱子移动的方法
     * */
    public void move() {

        if (x1 == -w1) {
            x1 = 288;
        }
        if (x2 == -w2) {
            x2 = 288;
        }
        x1 -= SPEED;
        x2 -= SPEED;
    }
}

八、实现柱子在画布上的移动

和地面的初始化一样,在画布上添加成员变量,进行初始化,接下来用画笔在画布上画出来,在线程里面的死循环调用它移动的方法,实现柱子的移动

小结:

接下来就是把小鸟添加到画布上来

九、创建小鸟类

小鸟的x轴位置其实是固定的,因此小鸟只需要能在y轴移动就行,这一部分可以通过鼠标活着键盘监听来控制

小鸟有一个扇翅膀的动作,通过把图片存在一个集合里面,通过循环,每次画一个图片,就能实现扇翅膀的效果

难点:小鸟的上下移动的方法的设计

这里通过设计一个类似抛物线的动作,每次按下键盘Up,就改变它的上抛的初速度,让小鸟往上飞,经过时间 t 开始做落体运动

public class Bird {
    private double v0;  /* 小鸟运动的初速度 */
    double t;  /* 往上运动的时间 */
    int s;   /* 往上运动的路程 */
    int x;
    int y;
    int g;   /* 重力 */
    BufferedImage img;
    ArrayList<BufferedImage> list;  /* 装三张不同动作的图片 */

    public Bird() throws IOException {
        g = 3;
        v0 = 5;
        t = 0.3;
        img = ImageUtil.getImage("bird1_1.png");
        x = 100;
        y = 200;
        list = new ArrayList<>();
        list.add(ImageUtil.getImage("bird1_0.png"));
        list.add(ImageUtil.getImage("bird1_1.png"));
        list.add(ImageUtil.getImage("bird1_2.png"));
    }

    /*
     * 鸟飞的动作,通过改变每次画不同动作的图片来实现
     * */
    int i = 0;
    public void fly() {
        if (i >= 3) {
            i = 0;
        }
        img = list.get(i);
        i++;
    }
    /*
     * 鸟的上抛移动
     * */
    public void moveUP() {
        v0 = 10;
    }
    /*
     * 鸟的落体运动*/
    public void move() {
        s= (int) (v0*t);
        y -= s;
        double v2 = v0 - g * t;
        v0 = v2;
    }
}

十、小鸟添加到画布

和柱子一样,不做赘述

效果如下:

十一、实现键盘监听

注意:实现加键盘监听需要画布获得焦点

方法1:main 方法中设置

gameJPenal.requestFocus();

方法2:直接在GamePanel 类设置

setFocusable(true);

主要代码:

this.addKeyListener(new KeyAdapter() {
            @Override
            public void keyPressed(KeyEvent e) {
                if (gameOver) {
                    if (e.getKeyCode() == KeyEvent.VK_UP) {
                        gameOver = false;
                        gameStart = false;
                        try {
                            ground = new Ground();
                            c0 = new Column(0);
                            c1 = new Column(1);
                            bird = new Bird();

                        } catch (IOException ioException) {
                            ioException.printStackTrace();
                        }
                    }

                } else if (gameStart) {
                    if (e.getKeyCode() == KeyEvent.VK_UP) {
                        bird.moveUP();
                    }
                } else {
                    start();
                }
            }
        });

十二、判断游戏结束的方法

判断游戏结束其实比较简单,通过检测小鸟的x, y 坐标以及小鸟图片的宽度与柱子的x , y 坐标加上柱子的宽度做一个碰撞检测

/*
     * 判定游戏是否结束的方法
     * */
    public void isGameOver() {
        //先判断是否落地
        if (bird.y <= 0 || bird.y >= 512 - ground.land.getHeight() - bird.img.getHeight()) {
            gameOver = true;
        }
        //判断是否撞柱子
        int bh = bird.img.getHeight();
        int bw = bird.img.getWidth();
        //c0.img1, c0.x1, c0.y1, c0.w1, c0.h1, null
        if (c0.x1 <= bird.x + bw && c0.x1 + c0.w1 >= bird.x && c0.y1 + c0.h1 >= bird.y) {
            gameOver = true;
        }
        if (c1.x1 <= bird.x + bw && c1.x1 + c1.w1 >= bird.x && c1.y1 + c1.h1 >= bird.y) {
            gameOver = true;
        }
        if (c0.x2 <= bird.x + bw && c0.x2 + c0.w2 >= bird.x && c0.y2 <= bird.y + bh) {
            gameOver = true;
        }
        if (c1.x2 <= bird.x + bw && c1.x2 + c1.w2 >= bird.x && c1.y2 <= bird.y + bh) {
            gameOver = true;
        }
    }
if (gameStart == false) {
            g.drawImage(imageStart, 50, 200, null);
        }
        if (gameOver == true) {
            g.drawImage(imageGameOver, 50, 200, null);

十三、游戏结束后回到准备状态

这里其实就是状态重置,写在在键盘监听事件里面,逻辑就是游戏结束,只要按了Up键,游戏就重置为准备状态。同时,在游戏 paint 方法中加一个判断,不同的状态对应不同的图片

if (gameOver) {
                    if (e.getKeyCode() == KeyEvent.VK_UP) {
                        gameOver = false;
                        gameStart = false;
                        try {
                            ground = new Ground();
                            c0 = new Column(0);
                            c1 = new Column(1);
                            bird = new Bird();
                            score = 0;
                        } catch (IOException ioException) {
                            ioException.printStackTrace();
                        }
                    }
                    repaint();

十四、统计分数

分数统计原理:小鸟的x坐标和柱子的( x+w)相等,分数就+1

if (bird.x == c0.x1 + c0.w1 || bird.x == c1.x1 + c1.w1) {
                    score++;
                }

总结

游戏结构并不复杂,只需要逐步实现每个功能即可。然后用到的主要是一些比较基础的知识,对于巩固基础知识还是有一定帮助的。

第一次写博客,可能不够精简,可读性不强。下次加油  。

到此这篇关于Java实战之飞翔的小鸟小游戏的文章就介绍到这了,更多相关java飞翔的小鸟内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • java面向对象之人机猜拳小游戏

    人机猜拳小游戏,只要用到的java面向对象的思维模式.本游戏中有游戏玩家和计算机两个参与者.玩家和计算机都有的属性是姓名和得分.共分为4个类.下图是游侠小程序控制台截图:     以下是源代码: Computer.java类 package com.whf.guess.game; /** * @author :辰 * @version * 创建时间:2017年2月24日 上午8:38:29 * */ public class Computer { String name = "电脑";

  • Java实现简单的贪吃蛇小游戏

    本文实例为大家分享了Java实现简单的贪吃蛇小游戏的具体代码,供大家参考,具体内容如下 1. 程序结构 程序结构图如图: 2. 程序设计思路 2.1 Data类 作用:连接statics文件夹,将静态资源包中的图片转化为图标 方便在面板上绘制. 实现:使用class.getResource(String path)方法. 代码如下: package com.snake; import javax.swing.*; import java.net.URL; public class Data {

  • java实现2048小游戏(含注释)

    本文实例为大家分享了java实现2048小游戏的具体代码,供大家参考,具体内容如下 实现文件 APP.java import javax.swing.*; public class APP { public static void main(String[] args) { new MyFrame(); } } 类文件 import javax.swing.*; import java.awt.event.ActionEvent; import java.awt.event.ActionList

  • Java实战入门之双色球彩票小游戏

    一.项目需求 二.项目思路 1.菜单制作 2.中奖号码生成 getNumber (随机数 Math.random) 3.购买号码和中奖号码比对 生成中奖等级 package com.test.mxl; import java.util.Scanner; public class Test { public static void main(String[] args) { int[] balls = new int[7]; int count = 0; boolean isBuy = false

  • java实战之猜字小游戏

    一.题目描述 二.思路 语法基础:StringBuilder 类似列表,可以更改元素. package Practice; public class tt { public static void main(String[] args) { String str = "banana"; System.out.println(str.indexOf('z')); // -1 System.out.println(str.indexOf('a', 2)); // 3 StringBuild

  • java实现简单的猜数字小游戏

    本文实例为大家分享了java实现简单的猜数字的具体代码,供大家参考,具体内容如下 题目描述: 猜数字(又称 Bulls and Cows )是一种古老的的密码破译类益智类小游戏,起源于20世纪中期,一般由两个人或多人玩,也可以由一个人和电脑玩.通常由两个人玩,一方出数字,一方猜.出数字的人要想好一个没有重复数字的4个数,不能让猜的人知道.猜的人就可以开始猜.每猜一个数字,出数者就要根据这个数字给出nAmB,其中A前面的数字n表示数字正确且位置也正确的数的个数,而B前的数字m表示数字正确但位置不正

  • java实战之飞机大战小游戏(源码加注释)

    一.工程文件 二.Main.java 主函数,实现类 package ui; //主函数实现 public class Main { public static void main(String[] args) { //创建窗体 GameFrame frame = new GameFrame(); //创建面板 GamePanel panel = new GamePanel(frame); //调用开始游戏的方法启动游戏 panel.action(); //将面板加入到窗体中 frame.add

  • Java实现2048小游戏(可直接运行)

    运行效果: 1.项目结构 2.代码 BaseData接口 package com.hsy.game; import java.awt.*; public interface BaseData { Font topicFont = new Font("微软雅黑", Font.BOLD, 50); Font scoreFont = new Font("微软雅黑", Font.BOLD, 28); Font normalFont = new Font("宋体&q

  • java简易小游戏制作代码

    java简易小游戏制作 游戏思路:设置人物移动,游戏规则,积分系统,随机移动的怪物,游戏胜负判定,定时器. 游戏内容部分 package 代码部分; import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; import java.awt.event.KeyList

  • Java实战之贪吃蛇小游戏(源码+注释)

    一.工程文件 二.Main.java package com.company; import javax.swing.*; public class Main { public static void main(String[] args) { //创建窗体对象 JFrame frame = new JFrame(); //创建窗体参数() frame.setBounds(10,10,900,720); //设置不允许更改大小 //frame.setResizable(false); //设置关

随机推荐