我们要做出这个样子的游戏
首先就要分析我们需要创建几个类,有鸟类、柱子类、地面类,然后就是游戏判定。我的思路就是,先创建这几个类,然后把这些类,对应的东西,画到游戏界面上,再确定游戏碰撞机制,当小鸟碰撞到地面和柱子的时候,就游戏结束。这就是游戏的整体思路。
接下来我们就要按照这个思路,编写代码。
一、游戏界面背景呈现
bg_image = ImageIO.read(BirdGame.class.getResource("bg.png"));
有了游戏界面背景,我们才能,继续编写。
二、柱子类
package com.flying.flybird_img;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Objects;
/**
* 柱子类
*/
public class Column {
private int x;//x 坐标
private int y;//y 坐标
private int width;//宽
private int height;//高
private BufferedImage image;//柱子图片
private int gap = 144;//上下柱子间隙
private int distanse = 266;//水平 两个柱子 距离
private int min;//柱子 纵坐标 最小值
private int max;//柱子 纵坐标 最大值
/**
*构造方法 初始化成员变量
*/
public Column() throws IOException {
this.x = BirdGame.GAME_WIDTH;
//读取 本地图片资源 给 image 赋值
image = ImageIO.read(Objects.requireNonNull(Ground.class.getResource("column.png")));
this.width = image.getWidth();
this.height = image.getHeight();
min = -(height / 2 - gap / 2) + 40;
//max = (BirdGame.HEIGHT - 146) - height / 2 - gap / 2;
max = 498 - (height / 2 + gap / 2) - 40;
y = (int) (Math.random() * (max - min) + min);
}
/**
* 定义柱子上下移动的方法
*/
public void step() {
x -= 1;
//越界
if (x < -width) {
x = BirdGame.GAME_WIDTH;
y = (int) (Math.random() * (max - min) + min);
}
}
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 getWidth() {
return width;
}
public void setWidth(int width) {
this.width = width;
}
public int getHeight() {
return height;
}
public void setHeight(int height) {
this.height = height;
}
public BufferedImage getImage() {
return image;
}
public void setImage(BufferedImage image) {
this.image = image;
}
public int getGap() {
return gap;
}
public void setGap(int gap) {
this.gap = gap;
}
public int getDistanse() {
return distanse;
}
public void setDistanse(int distanse) {
this.distanse = distanse;
}
}
三、地面类
package com.flying.flybird_img;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.BufferedReader;
import java.io.IOException;
import java.nio.Buffer;
/**
* 地面类
*/
public class Ground {
private int x;//x 坐标
private int y;//y 坐标
private int width;//宽
private int height;//高
private BufferedImage image;//地面图片
/**
*构造方法 初始化成员变量
*/
public Ground() throws IOException {
this.x = 0;
this.y = 644 - 146;
//读取 本地图片资源 给 image 赋值
image = ImageIO.read(Ground.class.getResource("ground.png"));
this.width = image.getWidth();
this.height = image.getHeight();
}
/**
* 定义地面走一步的方法
*/
public void step() {
x -= 1;
//越界
if (x <= -(this.width - BirdGame.GAME_WIDTH)) {
x = 0;
}
}
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 getWidth() {
return width;
}
public void setWidth(int width) {
this.width = width;
}
public int getHeight() {
return height;
}
public void setHeight(int height) {
this.height = height;
}
public BufferedImage getImage() {
return image;
}
public void setImage(BufferedImage image) {
this.image = image;
}
}
四、鸟类
package com.flying.flybird_img;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.IOException;
public class Bird {
private int x;//x 坐标
private int y;//y 坐标
private int width;//宽
private int height;//高
private BufferedImage image;//鸟图片
private BufferedImage[] images;//小鸟所有状态的图片
private double h = 0;//垂直方向下落的距离
private double g = 5;//重力加速度
private double v = 0;//初速度
private double t = 0.18;//下落时间
/**
* 构造方法 初始化成员变量
*/
public Bird() throws IOException {
images = new BufferedImage[8];
for (int i = 0; i < images.length; i++) {
images[i] = ImageIO.read(Bird.class.getResource(i + ".png"));
}
//读取 本地图片资源 给 image 赋值
image = images[0];
this.width = image.getWidth();
this.height = image.getHeight();
this.x = 166;
this.y = 222;
}
/**
* 定义小鸟向上飞的方法
*/
public void up() {
v = 10;
}
/**
* 定义小鸟下降的方法
*/
public void down() {
//小鸟 垂直方向 下落的距离
v = v - g * t;
h = v * t + g * t * t / 2;
y -= h;
}
/**
* 小鸟撞地面的方法
*
* @param ground
* @return
*/
public boolean hitGround(Ground ground) {
return this.y + this.height >= ground.getY();
}
/**
* 小鸟撞柱子的方法
*
* @return
*/
public boolean hitColumn(Column c) {
boolean b1 = this.x + this.width >= c.getX();
boolean b2 = this.x <= c.getX() + c.getWidth();
boolean b3 = this.y <= c.getY() + c.getHeight()/2 - c.getGap()/2;
boolean b4 = this.y + this.height >= c.getY() + c.getHeight()/2 + c.getGap()/2;
return b1 && b2 && (b3 || b4);
}
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 getWidth() {
return width;
}
public void setWidth(int width) {
this.width = width;
}
public int getHeight() {
return height;
}
public void setHeight(int height) {
this.height = height;
}
int index;
public BufferedImage getImage() {
return images[(index++) % images.length];
}
public void setImage(BufferedImage image) {
this.image = image;
}
public BufferedImage[] getImages() {
return images;
}
public void setImages(BufferedImage[] images) {
this.images = images;
}
}
五、游戏测试
柱子类、地面类、鸟类这三个类编写完成,就可以对游戏的主题进行编写。
package com.flying.flybird_img;
// 哥们儿 借我窗口用一下
import com.flying.flybird_img.Bird;
import com.flying.flybird_img.Column;
import com.flying.flybird_img.Ground;
import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.io.IOException;
/**
* 游戏启动类
* 同时充当 游戏的界面
* BirdGame 继承 JPanel 就具备了 面板的功能
* 由于BirdGame 是我们自定义的,所以我们可以在BirdGame 这个面板上随意作画
*/
public class BirdGame extends JPanel{
// 定义游戏界面的 宽高
public static final int GAME_WIDTH = 432;
public static final int GAME_HEIGHT = 644;
// 定义游戏状态
public static final int GAME_START = 0; // 开始状态
public static final int GAME_RUNNING = 1; // 运行状态
public static final int GAME_OVER = 2; // 结束状态
// 表示游戏当前状态 默认是开始状态
private int status = GAME_START;
private BufferedImage bg_image ; // 游戏界面的背景
private Ground ground ; // 地面对象
private Column column1 ;
private Column column2 ; // 柱子对象
private Bird bird ; // 小鸟对象
// 构造方法 初始化成员变量
public BirdGame() throws IOException {
bg_image = ImageIO.read(BirdGame.class.getResource("bg.png"));
ground = new Ground();
column1 = new Column();
column2 = new Column();
// 设置column2的 x 保证两根柱子水平间隔 244px
column2.setX( column1.getX() + column2.getDistanse());
bird = new Bird();
}
int i = 0;
/**
* 在画板上 绘制内容的方法
* 希望画板上有什么东西 在paint方法中 绘制即可
* @param g 画笔
*/
@Override
public void paint(Graphics g) {
g.drawImage(bg_image , 0, 0 , null);//画背景
paintColumn(g);// 画柱子
if (status == GAME_OVER){
g.drawImage(bird.getImages()[0], bird.getX() , bird.getY() , null);
}else {
paintBird(g);//画小鸟
}
paintGround(g);// 画地面
switch (status){
case GAME_START:
paintStart(g);
break;
case GAME_OVER:
paintGameOver(g);
}
String str = "分数 :";
g.drawString(str+(i++/100),20,20);
}
private void paintGameOver(Graphics g) {
try {
BufferedImage gameover = ImageIO.read(BirdGame.class.getResource("gameover.png"));
g.drawImage(gameover , 0 , 0 , null);
} catch (IOException e) {
e.printStackTrace();
}
}
private void paintStart(Graphics g) {
try {
BufferedImage start = ImageIO.read(BirdGame.class.getResource("start.png"));
g.drawImage(start , 0 , 0 , null);
} catch (IOException e) {
e.printStackTrace();
}
}
// 画小鸟的方法
private void paintBird(Graphics g) {
g.drawImage(bird.getImage() , bird.getX() , bird.getY() , null);
}
// 画柱子的方法
private void paintColumn(Graphics g) {
g.drawImage(column1.getImage() , column1.getX() , column1.getY() , null); // 1号柱子
g.drawImage(column2.getImage() , column2.getX() , column2.getY() , null); // 2号柱子
}
// 画地面的方法
private void paintGround(Graphics g){
g.drawImage(ground.getImage() , ground.getX() , ground.getY(), null);
}
// 游戏流程控制的总方法 : 即控制界面中 所有对象移动的方法
public void action() throws InterruptedException {
// 添加监听鼠标单击事件
this.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
switch (status){
case GAME_START:
status = GAME_RUNNING; // 切换为运行状态
break;
case GAME_RUNNING:
bird.up(); // 小鸟向上飞
break;
case GAME_OVER:
status = GAME_START ;// 切换为开始状态
try {
bird = new Bird();
column1 = new Column();
column2 = new Column();
// 设置column2的 x 保证两根柱子水平间隔 244px
column2.setX( column1.getX() + column2.getDistanse());
} catch (IOException ex) {
ex.printStackTrace();
}
}
// System.out.println("您单击了一次鼠标...");
}
});
while (true){
//根据游戏状态 控制对象的行为
switch (status){
case GAME_START:
ground.step();// 地面移动
break;
case GAME_RUNNING:
ground.step();// 地面移动
column1.step();
column2.step();// 柱子移动
bird.down(); // 小鸟自由落体
isGameOver(); // 检测游戏是否结束的方法
}
//重新绘制 即:调用paint()
repaint();
Thread.sleep(30);
}
}
// 检测游戏是否结束 : 小鸟是否撞上了 地面 或者柱子
private void isGameOver() {
if (bird.hitGround(ground) || bird.hitColumn(column1) || bird.hitColumn(column2)){
//说明撞上了 则将游戏状态设置 GAME_OVER
status = GAME_OVER;
}
}
// 程序的入口
public static void main(String[] args) throws Exception {
// 创建窗口对象
JFrame frame = new JFrame();
// 创建面板对象
BirdGame game = new BirdGame();
// 设置窗口的可见性 true表示显示在屏幕上
frame.setVisible(true);
// 设置宽高
frame.setSize(GAME_WIDTH, GAME_HEIGHT);
// 设置默认居中显示在屏幕上
frame.setLocationRelativeTo(null);
//固定窗口大小
frame.setResizable(false);
// 设置关闭窗口 同时退出程序
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// 将面板game 放在窗口frame上
frame.add(game);
// 调用action()
game.action();
}
}
六、游戏展示
上图分别展示的是 游戏开始、游戏运行、游戏结束的三个场景。