飞翔小鸟思路及代码
程序员文章站
2022-04-07 17:29:52
...
昨天跳着看视频把飞翔小鸟做出来了,下面分享一下我的思路。
先放成品图
和上一篇飞机大战的思路相似:
1.先把窗体做出把背景图放在面板中
2.把游戏背景中地面移动实现
3.把柱子在面板中实现进场及移动
4.把小鸟放在面板中
5.鼠标监听控制小鸟飞行轨迹
6.写判断小鸟与柱子碰撞和与地面碰撞的方法
7.添加计分和游戏结束游戏开始的画面
上面步骤最难的是写判断碰撞的方法…
——————————————————————————————————————————
首先是窗体类:
public class GameFrame extends JFrame{
public static void main(String[] args) {
GameFrame frame=new GameFrame();
GamePanel panel =new GamePanel();
//显示窗体
frame.setVisible(true);
//向窗体内添加一块画板
frame.add(panel);
}
public GameFrame() {
setTitle("飞翔小鸟");// 设置标题
setSize(432, 644);//窗体尺寸
setLocationRelativeTo(null);// 相对于屏幕左上角居中
setResizable(false);// 设置不允许玩家拖动界面
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//设置Logo图标 img/0.png
setIconImage(ImageUtil.getImage("/img/0.png"));
}
}
这是一个获取图片字节流的工具类:
public class ImageUtil {
public static BufferedImage getImage(String path) {
try {
BufferedImage image = ImageIO.read(ImageUtil.class.getResource(path));
return image;
} catch (IOException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
return null;
}
}
地面类:
public class Ground {
/*
* 定义地方的x,y坐标和宽高
*/
int x;
int y;
int w;
int h;
BufferedImage img;
//地面的构造器用来构建地面对象
public Ground() {
img=ImageUtil.getImage("/img/ground.png");
h=img.getHeight();
w=img.getWidth();
x=0;
y=644-h;
}
public void Move() {
//让地面能够一直往左边移动
if(x<=-(w-432)) {
x=25; //初始化x为25 刷新时没有明显的断层
}else {
x--;
}
}
}
这个是柱子类:
public class Column {
/*
* 定义地方的x,y坐标和宽高
*/
int x;
int y;
int w;
int h;
Random ran = new Random();
BufferedImage img;
// 安全间隙
int gap;
// 构造器初始化构造柱子对象(i表示第几根柱子)
public Column(int i) {
img = ImageUtil.getImage("/img/column.png");
h = img.getHeight() / 2;
w = img.getWidth() / 2;
x = 320 + (i - 1) * 245;
y = -ran.nextInt(h + 146 - 644 + 1);
// 初始化安全间隙
gap = 75;
}
// 柱子移动
public void Move() {
if (x <= -w) {
x = 432 + w;
y = -ran.nextInt(h + 146 - 644 + 1);
} else {
x--;
}
}
}
这个是小鸟类(判断碰撞方法写在这里):
public class Bird {
/*
* 定义地方的x,y坐标和宽高
*/
int x;
int y;
int w;
int h;
// 初速度
double v0;
// 时间间隔(往上移动的时间)
double t;
// 距离
double s;
// 重力
double g;
Random ran = new Random();
BufferedImage img;
List<BufferedImage> list;
public Bird() {
img = ImageUtil.getImage("/img/0.png");
w = img.getWidth() / 2;
h = img.getHeight() / 2;
x = 100;
y = 200;
// 初始化初速度
v0 = 2;
// 时间
t = 0.15;
// 距离
s = 0;
// 重力
g = 8;
// 初始化装图片的容器
list = new ArrayList<BufferedImage>();
// 向容器中添加图片
for (int i = 0; i < 8; i++) {
list.add(ImageUtil.getImage("/img/" + i + ".png"));
}
}
int index = 0;
// 小鸟飞行时图片的切换效果
public void fly() {
if (index < 8) {
img = list.get(index);
index++;
} else {
index = 0;
}
}
// 小鸟移动方法
public void move() {
// 计算小鸟上抛的距离
s = v0 * t;
// 得到小鸟上抛到最高点时的y坐标
y = (int) (y - s);
// 计算出小鸟到达最高点时的速度
double v2 = v0 - g * t;
// 最高点的速度就是小鸟下落时的初速度
v0 = v2;
}
public void moveUp() {
v0 = 15;
}
// 判断是否碰撞到天花板和地面
public boolean hit() {
if (y <= 0 || y >= 644 - 146 - h) {
return true;
}
return false;
}
// 判断是否碰撞柱子
public boolean hit(Column column) {
if (x >= column.x - w && x <= column.x + column.w) {
if (y > column.h / 2 + column.y - column.gap / 2 && y < column.h / 2 + column.y + column.gap / 2 - h) {
return false;// 安全通过
}
return true;// 撞到了
}
return false;// 没撞到
}
}
最后是画板类:
public class GamePanel extends JPanel {
BufferedImage bg;//背景图
/*
* 声明地面和柱子的对象
*/
Ground ground;
Column column1;
Column column2;
Bird bird;//声明小鸟对象
/*
* 接收三个碰撞条件的变量
*/
boolean bool1 ;
boolean bool2;
boolean bool3;
// 游戏准备状态
boolean start;//是否start
boolean GameOver;//是否Gameover
int socre;//分数
public GamePanel() {
bg = ImageUtil.getImage("/img/bg.png");
ground = new Ground();
column1 = new Column(1);
column2 = new Column(2);
bird = new Bird();
// 监听鼠标
MouseAdapter md = new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
// TODO 自动生成的方法存根
super.mouseClicked(e);
/*
* 当游戏为未开始时,点击鼠标为开始,执行start中的线程任务
*/
if (start == false) {
start = true;
start();
} else if(GameOver){//当游戏结束时,点击鼠标为未开始,Gameover为否,并初始化画板中的各个对象
start=false;
GameOver=false;
ground = new Ground();
//初始化柱子对象
column1 = new Column(1);//x = 300
//初始化第二根柱子
column2 = new Column(2);//x = 545
//初始化鸟对象
bird = new Bird();
System.out.println("你的得分为 : "+socre);
socre=0;
repaint();
}else{//游戏进行时,点击鼠标执行moveUp()方法
bird.moveUp();
}
}
};
addMouseListener(md);
addMouseMotionListener(md);
}
// 游戏开始的方法
public void start() {
MyThread mt = new MyThread();
// 将线程所有执行的任务装入到线程对象中
Thread t = new Thread(mt);
// 将线程纳入线程调度
t.start();// 告诉CPU可以给我这个线程分配时间片段了
}
@Override
public void paint(Graphics g) {
super.paint(g);
g.drawImage(bg, 0, 0, null);// 添加背景
g.drawImage(column1.img, column1.x, column1.y, column1.w, column1.h, null);// 添加第一根柱子
g.drawImage(column2.img, column2.x, column2.y, column2.w, column2.h, null);// 添加第二根柱子
g.drawImage(ground.img, ground.x, ground.y, null);// 添加地面
g.drawImage(bird.img, bird.x, bird.y, bird.w, bird.h, null);// 添加第二根柱子
/*
* 当游戏为未开始时,把准备页面画上去
*/
if(start==false) {
g.drawImage(ImageUtil.getImage("/img/start.png"), 0, 0, null);
}
/*
* 当游戏为结束时,把结束页面面画上去
*/
if(GameOver) {
g.drawImage(ImageUtil.getImage("/img/gameover.png"), 0, 0, null);
}
//画板中字体设置
Font f=new Font("宋体",Font.BOLD,18);
g.setFont(f);
g.setColor(Color.white);
g.drawString("分数 :"+ socre, 20, 30);
}
//线程类
class MyThread implements Runnable {
//写在run()方法中,就可以用线程的方法同时进行判断
@Override
public void run() {
/*
* 用死循环方式不断运行对象的方法
*/
while (true) {
ground.Move();
column1.Move();
column2.Move();
bird.fly();
bird.move();
bool1 = bird.hit();
bool2 = bird.hit(column1);
bool3 = bird.hit(column2);
if (bool1||bool2||bool3) {
GameOver = true;// 窗体内的对象全部静止
break;// 结束循环
}
if(bird.x==column1.x+column1.w||bird.x==column2.x+column2.w) {
socre++;//分数加一
}
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
repaint();//刷新画面
}
}
}
}
需要素材或者源码的可以在下方留言哦…
上一篇: 俄罗斯方块小游戏制作:
下一篇: Unity C# 椭圆形范围检测