①素材准备

在开发此项目之前,我们需要去先下载一些关于飞翔的小鸟素材图片

小鸟的飞翔图片

地面背景图片

子图

以及开始结束图片

②代码构思

本项目主要针对JAVA刚学完想巩固练习,却没有项目着手的同学,用的都是一些基础性的知识

运用到的知识点:

1.面向对象:封装继承多态

2.数组

3.常用类Math

4.swing组件:图形界面工具

5.鼠标监听

6.IO流

7.多线程

一、逻辑步骤分析:

1.先实现窗口的制作,并且将背景图放入窗口面板

2.设计地面类,实现游戏背景地面移动

3.设计柱子类,实现游戏背景柱子移动

4.设计小鸟类,在类中添加小鸟相关方法

初始化小鸟相关参数, 判断小鸟是否碰撞柱子与地面

5.把小鸟放在面板中

6.鼠标监听控制小鸟飞行的轨迹

7.添加计分和游戏结束游戏开始的画面

代码分类:

由上述的分析,我们可以大致分析计划创建4个类

1.小鸟类:设置小鸟参数,添加小鸟判断方法

package game;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.IOException;

class Bird {

    BufferedImage image;  // 图片
    int x, y;  // 位置
    int width, height;   // 宽高
    int size;  // 大小(用于碰撞检测)
    double g;  // 重力加速度
    double t;  // 位移的间隔时间
    double v0;  // 最初上抛速度
    double speed;  // 当前上抛速度
    double s;  // 经过t时间之后的位移
    double alpha;  // 小鸟的倾角(弧度)

    BufferedImage[] images;  // 一组图片,记录小鸟的动画帧
    int index;  // 动画帧数组的下标

    // 初始化小鸟
    public Bird() throws IOException {
        image = ImageIO.read(getClass().getResource("/resources/0.png"));
        width = image.getWidth();
        height = image.getHeight();
        x = 132;
        y = 280;
        size = 40;

        // 初始化位移参数
        g = 4;
        v0 = 20;
        t = 0.25;
        speed = v0;
        s = 0;
        alpha = 0;

        // 初始化动画帧参数
        images = new BufferedImage[8];
        for(int i=0; i<8; i++){
            images[i] = ImageIO.read(getClass().getResource("/resources/"+ i +".png"));
        }
        index = 0;
    }

    // 飞行动作 (变化一帧)
    public void fly(){
        index ++;
        image = images[(index / 12) % 8];
    }

    // 移动一步
    public void step(){
        double v0 = speed;
        s = v0 * t + g * t * t /2;  // 计算上抛运动位移
        y = y - (int)s;  // 计算鸟的坐标位置
        double v = v0 -g * t;  // 计算下次移动速度
        speed = v;
        alpha = Math.atan(s / 8);  //计算倾角(反正切函数)
    }

    // 向上飞行
    public void flappy(){
        speed = v0;   // 重置速度
    }

    // 检测小鸟是否碰撞到地面
    public boolean hit(Ground ground){
        boolean hit = y + size / 2 > ground.y;
        if(hit){
            y = ground.y - size / 2;
            alpha = -3.14159265358979323 / 2;
        }
        return hit;
    }

    // 检测小鸟是否撞到柱子
    public boolean hit(Column column){
        // 先检查是否在柱子的范围内
        if (x > column.x - column.width / 2 - size / 2
                && x < column.x + column.width / 2 + size / 2){
            // 再检查是否在柱子的缝隙中
            if (y > column.y - column.gap / 2 + size / 2
                    && y < column.y + column.gap /2 - size / 2){
                return false;
            }
            return true;
        }
        return false;
    }
}

2.柱子类:设置柱子参数,添加柱子移动方法

package game;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Random;

class Column {

    BufferedImage image;  // 图片
    int x, y;  // 位置
    int width, height;  // 宽高
    int gap;  // 柱子之间的缝隙
    int distance;  // 柱子之间的距离
    Random random = new Random();  // 随机数工具

    // 初始化第N个柱子
    public Column(int n) throws IOException {
        image = ImageIO.read(getClass().getResource("/resources/column.png"));
        width = image.getWidth();
        height = image.getHeight();
        gap = 144;
        distance = 245;
        x = 550 + (n-1) * distance;
        y = random.nextInt(218) + 132;
    }

    // 柱子向左移动一步
    public void step(){
        x--;
        if (x == -width/2){
            x = distance * 2 - width / 2;
            y = random.nextInt(218) + 132;
        }
    }
}

3.地面类:设置地面参数,添加地面移动方法

package game;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.IOException;

class Ground {
    BufferedImage image;  // 图片
    int x, y;  // 位置
    int width, height;  // 宽和高

    // 初始化地面
    public Ground() throws IOException {
        image = ImageIO.read(getClass().getResource("/resources/ground.png"));
        width = image.getWidth();
        height = image.getHeight();
        x = 0;
        y = 500;
    }

    // 地面向左移动
    public void step(){
        x--;
        if(x == -109){
            x = 0;
        }
    }
}

4.测试类:添加开始结束、鼠标监听等方法

public class Test {
    public static void main(String[] args){
        Test.output();
    }
    public static void output(){
        int[] nums=new int[100];
        nums[0]=1;
        for(int i=1;i<100;i++){
            nums[i]=nums[i-1]+i;
        }
        for(int i=0;i<100;i++){
            if(nums[i]%4==0&&nums[i]%14==0){
                System.out.println("这是a"+i+":"+nums[i]);
            }
        }
    }

}

二、具体步骤建立

1.建立名flappyBird的的Java⼯程。

在⼯程下的src⽬录下新建game和resources包最后,将该⼯程所需的图⽚拷贝⾄resources包下,将代码拷贝进game包中。

2.构建⼯程的结构

⾸先,新建BirdGame类,然后新建Groud类,表⽰游戏中的地⾯;新建Column表⽰游戏中的柱⼦;新建Bird类表⽰游戏中的鸟,这些类继承Jpanel类,都继承⾃Jpanel类。

Jpanel是Java图形界⾯化(GUI)⼯具包swing中的⾯板容器类,可以理解为画板,包含在javax.swing包中,是⼀种轻量级容器,可以加⼊到JFrame窗体中。

3.为BirdGame类添加属性

其中,background属性是游戏背景贴图。

4.为Ground类添加属性

其中,image属性为地⾯的贴图。

5.为Column类添加属性

其中,image属性表⽰柱⼦贴图。

6.为Bird类添加属性

image属性表⽰Bird类的贴图,x,y表⽰鸟的中⼼位置,width和height表⽰鸟图⽚的宽度和⾼度。在本实训项⽬中,⼩鸟的⼤⼩⽤⼀个正⽅

形区域来表⽰,size即表⽰该正⽅形的边长,⽤于后续的碰撞检测。

7.BirdGame类添加构造⽅法,初始化属性

通过程序代码⼤家可以看出实例化Column类的时候,出现了编译错误,这是因为还没有为Column类编写⼀个带参数的构造器。

8.为Column类添加构造⽅法,初始化属性

下⾯介绍⼀下x、y坐标的计算⽅式,第⼀个柱⼦的x坐标为x= 432+118=550,第⼆根主⼦的x坐标为x=550+245,因此,柱⼦的x轴坐

标可以总结为x = 550+245*(n-1),其中n表⽰第⼏根柱⼦。

可以看出,柱⼦y的坐标范围在132⾄350之间随机分布,使⽤Random类的nextInt⽅法⽣成[0-218)之间的随机数,然后再加上132,这

样就能得到132⾄350之间的随机数了。

9.为Bird类添加构造⽅法,初始化属性

10.为Ground类添加构造⽅法,初始化属性

11.编写main⽅法

在main⽅法中,设置窗⼝的⼤⼩、居中、点击窗⼝的右上⾓“X”关闭窗⼝以及设置窗⼝可见,代码如图20所⽰。

12.绘制界⾯

在BirdGame类中重写paint⽅法,绘制界⾯。⾸先绘制地⾯使⽤Graphics的drawImage⽅法,绘制背景界⾯的时候,绘制的起点坐标是(0,0)。然后,绘制2个柱⼦。

绘制两个柱⼦的时候,绘制的起点坐标与Column类的属性x,y的值不同,需要做⼀些更改。

13.运⾏

运⾏BirdFrame类。

实现地⾯的运动

实现柱⼦的移动

实现鸟的运动

经过时间t的位移s的计算公式:

s = v0 * t + g * t * t / 2;

经过时间t后⼩鸟的纵坐标位置y1的计算公式为:

y1 = y - s;

经过t时间后,⼩鸟的运⾏速度v为:

v = v0 - g * t ;

14.实现鸟的动画处理。

使⽤数组,存储要显⽰的图⽚,共计8张,鸟每运动⼀次换⼀张图⽚,以达到鸟的动画效果。fly⽅法实现了鸟的飞翔。⼀个数对8取余,能够得到0到7之间的数字,正好是images数组中的下标,index/12的⽬的是 使鸟的挥动翅膀次数变慢,即切换照⽚的频率变慢。接着,在BirdGame类的action⽅法中,调⽤Bird类的fly⽅法和step⽅法。运⾏后,会发现鸟可以动起来了。最后,计算倾⾓。假设⽔平移动的位移固定为8,那么倾⾓ = 反正切s/8调⽤Java API提供的反正切⽅法atam,计算倾⾓。

接着,在BirdGame类的paint中,为达到鸟的飞翔效果,使⽤Java API,使⼩鸟旋转

15.实现⿏标监听事件

要实现⿏标的按下事件,步骤如下:

1. 使⽤“匿名内部类”声明事件

2. 处理⽅法。即在BirdGame类的action⽅法声明事件的处理⽅法;

2、⾸先,在Bird类中添加flappy以实现鸟的飞翔。然后,在处理⽅法中,调⽤Bird类的flappy⽅法。

3、注册事件监听。即在BirdGame类的action⽅法中,注册监听事件。

16.实现计分

要实现计分,需要进⾏以下操作:

1、在BirdGame类中增加属性score,⽤于计分,score初始化为0。

2、在BirdGame类的action⽅法的主循环中,添加逻辑判断。当柱⼦的x坐标与鸟的x坐标重合时,则加1分。

3、在BirdGame类的paint⽅法中将分数画出来。

17.实现鸟的碰撞检测

1、实现鸟碰撞地⾯。

1)为BirdGame类增加boolean变量gameOver,该变量⽤于标识游戏是否结束,如果gameOver的值为true,则表⽰游戏结束了;如果

gameOver的值为false,则表⽰游戏没有结束。gameOver的默认值设置为fasle。

2)当检测到碰到地⾯的时候,即gameOver的值为TRUE。在循环中检测是否碰到地⾯。在Bird类中增加⽅法hit(Ground)检测鸟是否

碰地⾯。当鸟的y坐标减去size/2⼤于等于地⾯的y坐标时,则与地⾯发⽣碰撞。

3)修改BirdGame类的action⽅法中的主循环,当游戏没有结束的时,执⾏鸟和柱⼦的移动。也就是说,如果游戏结束了,鸟和柱⼦就不

移动了。

4)在BirdGame类的paint⽅法添加gameOver的值为true时,显⽰游戏结束界⾯

⼩鸟与柱⼦发⽣碰撞的x的坐标计算⼊如下:

x1 = column.x - width/2 - size/2;

x2 = column.x + width/2 + size/2;

当鸟的x坐标⼤于x1(x > x1)并且⼩于x2(x < x2)时与柱⼦发⽣碰撞。但是如果在缝隙中,则不发⽣碰撞。

⼩鸟在柱⼦的缝隙中时y坐标计算如下:

y1 = column.y - gap/2 + size/2;

y2 = column.y + gap/2 - size/2;

当鸟的y坐标⼤于y1(y>y1)并且⼩于y2(y<y2)时,鸟在缝隙中。

在Bird类添加hit(column)⽅法,⽤于判断鸟是否碰撞柱⼦

修改BirdGame类的action⽅法完成上述代码,即完成了判断鸟的碰撞功能。

18.实现游戏的开始、结束及重新开始

三、项目的运行结果

1.代码运行后游戏的具体实现:

2.界面能够基本达到原先预期,,界面会出现GeT Ready!的字样。本游戏通过鼠标进行控制。点击鼠标游戏就会开始。

3.点击鼠标左键游戏开始后,每点击鼠标一次鼠标小鸟就会上升一次,每经过一根柱子左上角的数字就会加一,碰到柱子后游戏就会结束,结束界面就会出现GAMEOVER字样提醒你此次游戏已经结束,再次点击中间的符号游戏就会再次开始。自此本次的程序设计基本完成。

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐