Flappy Bird游戏 C语言实现

Posted 丶chuchu丶

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Flappy Bird游戏 C语言实现相关的知识,希望对你有一定的参考价值。

目录

一、准备工作

二、初识图形化界面

先来做一个窗口

接下来创建一个小球

接下来创建一个矩形

三、设置参数

四、设置速度 

小球的运动

画面的运动

判断输赢

五、完整代码


 大家是否玩过上面这款游戏呢?想要自己做出来并不难,跟着我来用手吧。

(参考童晶老师的《C和C++游戏趣味编程》)


一、准备工作

编译器使用VS2019,但需要下载一个图形库Easy—X

由于此图形库是C++的,所以我们要以C++文件来进行编写,C++文件内也可以使用C语言。

EasyX 下载地址https://easyx.cn/
怎样安装 EasyX? - EasyXhttps://easyx.cn/setup#:~:text=1.%20%E5%8F%8C%E5%87%BB%E4%B8%8B%E8%BD%BD%E7%9A%84%20EasyX%20%E5%AE%89%E8%A3%85%E5%8C%85%EF%BC%8C%E5%9C%A8%E2%80%9CWindows%20%E5%B7%B2%E4%BF%9D%E6%8A%A4%E4%BD%A0%E7%9A%84%E7%94%B5%E8%84%91%E2%80%9D%E6%8F%90%E7%A4%BA%E7%AA%97%E4%B8%AD%EF%BC%8C%E7%82%B9%E2%80%9C%E6%9B%B4%E5%A4%9A%E4%BF%A1%E6%81%AF%E2%80%9D%EF%BC%8C%E5%86%8D%E7%82%B9%E2%80%9C%E4%BB%8D%E8%A6%81%E8%BF%90%E8%A1%8C%E2%80%9D%EF%BC%8C%E8%BF%99%E6%97%B6%EF%BC%8C%E5%8F%AF%E4%BB%A5%E7%9C%8B%E5%88%B0%20EasyX%20%E7%9A%84%E5%AE%89%E8%A3%85%E7%A8%8B%E5%BA%8F%E3%80%82%202.,EasyX%20%E5%AE%89%E8%A3%85%E7%A8%8B%E5%BA%8F%E4%BC%9A%E6%A3%80%E6%B5%8B%E5%88%B0%E5%BD%93%E5%89%8D%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F%E4%B8%AD%E5%AE%89%E8%A3%85%E7%9A%84%20Visual%20Studio%20%E7%89%88%E6%9C%AC%E3%80%82%20%E5%9C%A8%E5%AF%B9%E5%BA%94%E7%9A%84%20VS%20%E7%89%88%E6%9C%AC%E5%8F%B3%E4%BE%A7%E7%82%B9%E5%87%BB%E2%80%9C%E5%AE%89%E8%A3%85%E2%80%9D%E5%8D%B3%E5%8F%AF%E3%80%82

二、初识图形化界面

先来做一个窗口

#include <graphics.h>
#include <conio.h>
#include <stdio.h>

int main()
{
	initgraph(600, 600);
	_getch();
	closegraph();
	return 0;
}

可能很多函数、头文件不认识。记住这样用就行,不理解没关系。

 这样我们就创建了一个600×600的图形界面

接下来创建一个小球

#define _CRT_SECURE_NO_WARNINGS 1
#include <graphics.h>
#include <conio.h>
#include <stdio.h>

int main()
{
	initgraph(600, 600);
	fillcircle(300,300,100);
	_getch();
	closegraph();
	return 0;
}

我们运用fillcircle( )函数,第一个值参数是X坐标,第二个参数是Y坐标,第三个参数是半径

这里讲解一下横纵坐标的定义:

接下来创建一个矩形

#include <graphics.h>
#include <conio.h>
#include <stdio.h>

int main()
{
	initgraph(600, 600);
	fillrectangle(200,0,400,400);
	_getch();
	closegraph();
	return 0;
}

我们使用fillrectangle( )函数,前两个参数是矩形左上角坐标,后两个参数是矩形右下角坐标

三、设置参数

有了上面基础,下面我们一步一步来做。

首先我们要选定好我们窗口大小小球大小以及方块障碍物大小

我们想要小球动起来,需要给他初速度重力加速度,方块同理。

在平面上就可以理解为它们的横纵坐标移动

我们先设置基本参数,详情见注释 

float w, h, g;//游戏画面宽高与重力加速度
float ball_x, ball_y, ball_vy, r;//小球圆心坐标,y方向速度和半径
float rect1_x1, rect1_y1, rect1_x2, rect1_y2, rect1_vx;//上方块的横纵坐标
//因为画面向左移动,我们只要让方块向左移就可以实现,所以需要x方向速度
float rect2_x1, rect2_y1, rect2_x2, rect2_y2, rect2_vx;//下方块的横纵坐标
float rect_h = 130;//因为随机方块高度的需要,单独设置一个高度
int score;//得分

 再给参数赋值

    //下面给具体参数
	w = 600;
	h = 400;
	g = 0.6;
	initgraph(w, h);//创建一个窗口

	//小球参数
	r = 20;
	ball_x = w / 4;//让小球在画面左边1/4处
	ball_y = h - r;//让小球贴地,离地面一个半径距离
	ball_vy = 0;

	//上方块参数
	rect1_x1 = w * 3 / 4;//方块在画面3/4处
	rect1_y1 = 0;//上方块左上角y坐标为0
	rect1_x2 = rect1_x1 + 30;//+30就是指宽度为30
	rect1_y2 = rect1_y1 + rect_h;//高度为130

	//下方块参数
	rect2_x1 = w * 3 / 4;
	rect2_y1 = h - rect_h;//下方块的左上角y坐标离右下角差一个高度
	rect2_x2 = rect2_x1 + 30;
	rect2_y2 = h;//下方块贴地

	//速度
	rect1_vx = rect2_vx = -3;

最后我们来看一下效果

fillcircle(ball_x, ball_y, r);
fillrectangle(rect1_x1, rect1_y1, rect1_x2, rect1_y2);
fillrectangle(rect2_x1, rect2_y1, rect2_x2, rect2_y2);
_getch();
closegraph();

四、设置速度 

小球的运动

画面一直在动,就需要循环。接下来的我们就放在一个死循环里进行。

首先我们先让小球动起来,用_kbhit() 来收集按键,_getch()接收,如代码:

while (1)
{
	if(_kbhit())//当按键时
	{
		char input = _getch();//获得输入字符
		if (input == ' ')//按下空格时
		{
			ball_vy = -15;//给小球一个向上的初速度
		}
	}
}

有了速度不够,速度要换成路程才行,平面上体现为小球的坐标更新

当小球落到地面时,我们把速度变为0,并且纵坐标变为h - r就能实现小球在地面上。

现在我们来看下效果。

while (1)
{
	//当摁下空格,小球向上跳跃,给一个反向速度
	if(_kbhit())
	{
		char input = _getch();
		if (input == ' ')
		{
			ball_vy = -17;
		}
	}
    
    if (ball_y >= h - r)//当小球落到地面时
	{
		ball_vy = 0;//速度变为0
		ball_y = h - r;//规范其y坐标,防止落到地面下。
	}

	ball_vy = ball_vy + g;//y方向初速度为0,再加上一个重力加速度
	ball_y = ball_y + ball_vy;//根据小球y方向速度更新y坐标

	cleardevice();//在每次循环清一次屏,不然会出现小球的轨迹
	fillcircle(ball_x, ball_y, r);
	fillrectangle(rect1_x1, rect1_y1, rect1_x2, rect1_y2);
	fillrectangle(rect2_x1, rect2_y1, rect2_x2, rect2_y2);
	Sleep(10);//让小球暂停10ms,不然小球一眨眼就没了
}
closegraph();

画面的运动

画面的运动可以看作方块向左移,那么我们就要给方块的x坐标更新。

rect1_x1 = rect1_x1 + rect_vx;
rect2_x1 = rect2_x1 + rect_vx;

但是方块到了最左边,我们还需要让它出现在右边,并且此时得分+1

重新出现的方块我们需要一个新的随机高度,增加趣味性。

别忘了把方块左移速度提升上去,增加游戏难度。

//更新两个方块的位置坐标
rect1_x1 += rect_vx;
rect1_x2 += rect_vx;
rect2_x1 += rect_vx;
rect2_x2 += rect_vx;

if (rect1_x1 <= 0 && rect2_x1 <= 0)//方块来到最左边
{
	//让他们出现在最右侧
	rect1_x1 = rect2_x1 = w - 30;
	rect1_x2 = rect2_x2 = w;
	score += 1;//得分+1
	rect_h = rand() % int(h / 4) + h / 4;//设置随即高度,高度不超过画面的1/4
	//设置随即高度
	rect2_y1 = h - rect_h;
	rect1_y2 = rect_h;
			
	if (score > 0)
		rect_vx -= 0.1;//如果速度一直大于0,左移速度加大。当得分为0速度还原。
}

看一下效果:

这里我的参数有些不合理,大家可以自行更改,原理就是这样。

判断输赢

如果碰到方块的边缘,那么得分变为0速度还原。否则继续。

这里是六种死法,所以我们需要六个条件判断。

if (((ball_x + r >= rect2_x1)
	&&(ball_y + r >= h - rect_h)
	&&(ball_x - r <= rect2_x2))//碰到下方块
	||((ball_x + r >= rect1_x1)
	&&(ball_y - r <= rect_h)
	&&(ball_x - r <= rect1_x2))//碰到上方块
	)
{
	Sleep(100);//给个慢速回放,看看怎么死的
	score = 0;//得分归0
}

 结尾咱给来一份打印成绩,代码如下,暂且了解就行:

TCHAR s[20];
_stprintf(s, _T("%d"), score);
settextstyle(40, 0, _T("宋体"));
outtextxy(50, 30, s);

五、完整代码

以下是自己选了合适的参数,并添加了一些元素。

大家也可以参照自行修改。

#include <graphics.h>
#include <conio.h>
#include <stdio.h>
#include <stdlib.h>

int main()
{
	float w, h, g;//游戏画面宽高与重力加速度
	float ball_x, ball_y, ball_vy, r;//小球圆心坐标,y方向速度和半径
	float rect1_x1, rect1_y1, rect1_x2, rect1_y2, rect_vx;//上方块的横纵坐标
	//因为画面向左移动,我们只要让方块向左移就可以实现,所以需要x方向速度
	float rect2_x1, rect2_y1, rect2_x2, rect2_y2;//下方块的横纵坐标
	float rect_h = 125;//因为随机方块高度的需要,单独设置一个高度
	int score = 0;//得分

	//下面给具体参数
	w = 600;
	h = 400;
	g = 0.4;
	initgraph(w, h);//创建一个窗口

	//小球参数
	r = 18;
	ball_x = w / 4;//让小球在画面左边1/4处
	ball_y = h - r;//让小球贴地,离地面一个半径距离
	ball_vy = 0;

	//上方块参数
	rect1_x1 = w * 3 / 4;//方块在画面3/4处
	rect1_y1 = 0;//上方块左上角y坐标为0
	rect1_x2 = rect1_x1 + 30;//+30就是指宽度为30
	rect1_y2 = rect1_y1 + rect_h;//高度为130

	//下方块参数
	rect2_x1 = w * 3 / 4;
	rect2_y1 = h - rect_h;//下方块的左上角y坐标离右下角差一个高度
	rect2_x2 = rect2_x1 + 30;
	rect2_y2 = h;//下方块贴地

	//速度
	rect_vx = -2.5;

	while (1)
	{
		//当摁下空格,小球向上跳跃,给一个反向速度
		if(_kbhit())
		{
			char input = _getch();
			if (input == ' ')
			{
				ball_vy = -8;
			}
		}

		ball_vy = ball_vy + g;//y方向初速度为0,再加上一个重力加速度
		ball_y = ball_y + ball_vy;//根据小球y方向速度更新y坐标

		if (ball_y >= h - r)
		{
			ball_vy = 0;
			ball_y = h - r;
		}

		//更新两个方块的位置坐标
		rect1_x1 += rect_vx;
		rect1_x2 += rect_vx;
		rect2_x1 += rect_vx;
		rect2_x2 += rect_vx;

		if (rect1_x1 <= 0 && rect2_x1 <= 0)//方块来到最左边
		{
			//让他们出现在最右侧
			rect1_x1 = rect2_x1 = w - 30;
			rect1_x2 = rect2_x2 = w;
			score += 1;//得分+1
			rect_h = rand() % int(h / 5.5) + h / 5.5;//设置随即高度
			
			rect1_y2 = rect_h;
			rect2_y1 = h - rect_h;
			
			if (score > 0)
				rect_vx -= 0.1;//如果速度一直大于0,左移速度加大。
		}

		if (((ball_x + r >= rect2_x1)
			&&(ball_y + r >= h - rect_h)
			&&(ball_x - r <= rect2_x2))//碰到下方块
			||((ball_x + r >= rect1_x1)
			&&(ball_y - r <= rect_h)
			&&(ball_x - r <= rect1_x2))//碰到上方块
			||(ball_y + r >= h - 10)//碰到底部
			)
		{
			Sleep(100);//给个慢速回放,看看怎么死的
			score = 0;//得分归0
			rect_vx = -3;//碰到就速度还原
		}

		if (ball_y - r <= 10)//如果碰到顶部,直接回到底部,分数为0
		{
			ball_vy += 100 * g;
			ball_y += ball_vy;
			score = 0;
		}

		cleardevice();
		
		//绘制小球
		setfillcolor(GREEN);//填上绿色
		fillcircle(ball_x, ball_y - 10, r);
		
		//绘制方块
		setfillcolor(BROWN);//填上棕色
		fillrectangle(rect1_x1, rect1_y1, rect1_x2, rect1_y2);
		fillrectangle(rect2_x1, rect2_y1, rect2_x2, rect2_y2);
		
		setfillcolor(RED);
		fillrectangle(0, 0, w, 10);
		fillrectangle(0, h - 10, w, h);

		//打印分数
		TCHAR s[20];
		_stprintf(s, _T("%d"), score);
		settextstyle(40, 0, _T("宋体"));
		outtextxy(50, 30, s);
		Sleep(10);
	}
	closegraph();

	return 0;
}

如果你能看到这,希望对您有所帮助,我会继续写一些有趣的游戏,欢迎关注。

以上是关于Flappy Bird游戏 C语言实现的主要内容,如果未能解决你的问题,请参考以下文章

vb写程序:flappy bird

python3.5 的flappy bird pygame编的

flappy bird如何制作

微信小游戏_flappy_bird

强化学习DQN:Flappy Bird实例分析

自主学习Flappy Bird游戏