所谓游戏图像,就是不断绘制更新绘制更新的一个连续过程,所以我们的主函数为一个循环体。然后游戏代码分为 定义、初始化、更新数据、游戏结束判定几个过程。
该游戏运用exayx图形库运行,请读者自行在官网进行环境配置(此游戏仅作为读者参考,作者并非专业开发者,若有不当请给与批评指正)。
我们应该先找到游戏中使用的游戏素材,将找好的音乐、小鸟图片、背景等素材导入代码的文件夹中,以备调用,如图所示(图片对应的黑底白色图片是对应图片的掩码图,掩码图的使用目的是为了实现图像的透明,具体参见其他文章对掩码图的解释,百度就有,作者使用ps自行制作):
然后我们使用结构体定义游戏各个组件的数据,定义窗口大小,声明调用函数。
我们知道小鸟x坐标是不变的,其实只是图片中的地面(round.png)在不断向右边移动,所以小鸟的参数为坐标x,y、而且我们用一个g参数模拟重力,使得小鸟在不受控制的情况下不断下落,用结构体定义小鸟,而且你会发现,定义中还有一个IMAGE img2[3][2]数组,这个数组的作用是每个小鸟彩图对应一个其掩码图,如果不加上掩码图你会发现图像在运行的过程中给有黑框,会比较影响观感。
其他物体的参数也是如此,具体读者请参考代码,里面我标注的非常详细。
定义之后我们要先初始化,初始化的作用是把各个游戏部件的坐标、速度、游戏音乐播放的初始定义在一起,不管定义什么我们都要注意,一定要先行进行初始化!
初始化之后我们就可以开始写绘制函数,绘制函数的作用就是控制动画,让地图和小鸟动起来的前提是先要绘制图像,绘制函数的用法请参考代码。注意:绘制的图像图层与代码的先后有一定关系,读者可以自行根据需要进行调节。
之后我们就需要完成数据更新这一部分,我们知道,数据更新分为两部分,自动更新(动画自行演示,路面自己走动,小鸟煽动翅膀等等),另一部分为手动更新(鼠标操作之后小鸟往上飞),运用函数实现鼠标与计算机的交互,具体请参考代码。
最后我们需要进行游戏结束的判断,运用if语句,当小鸟的坐标与管道、地面、边界重叠时,让小鸟的垂直速度瞬间变大,这样就模拟了小鸟死亡掉落画面,同时停止播放音乐,播放死亡音乐。
文章只给读者提供一个大概思想,具体代码如下,请读者自行进行理解,注释标注得比较多,方便读者阅读。请多多支持作者,谢谢大家,有问题请给我留言,我会第一时间答复!
#include<stdio.h>
#include<graphics.h>
#include<easyx.h>
#include<time.h>
#include<mmsystem.h>
#include<windows.h>
#pragma comment(lib,"winmm.lib")//音乐
void GameInit();
void GameDraw();
void GameUpdata();
void hitFloor();
#define WIDTH 658
#define HIGHT 369 //窗口
unsigned long t1, t2; //定义时间
IMAGE backimg; //定义背景数据
struct round { //定义地面道路
int x, y;
int xv;
IMAGE img;
}round;
struct bird { //定义鸟
int x, y;
int vy;
int g;
int frame; //帧
IMAGE img2[3][2];
}bird;
struct pipe { //管道
int x1, y1;
int x2, y2;
int x3, y3;
int x4, y4;
int x5, y5;
int vx;
IMAGE img3[4];
}pipe;
int main()
{
GameInit(); //初始化
for (;;)
{
GameDraw(); //绘制界面
GameUpdata(); //数据更新
hitFloor(); //判断游戏结束函数
}
return 0;
}
//初始化函数
void GameInit()
{
//初始化bgm
mciSendString("open images/bg.mp3", 0, 0, 0);
mciSendString("play images/bg.mp3 repeat", 0, 0, 0);
srand(time(0));
//初始化窗口
initgraph(WIDTH, HIGHT);
//初始化图片
loadimage(&backimg, "images/background.png");
//初始化地面
loadimage(&round.img, "images/round.png");
round.x = 0;
round.y = 320;
round.xv = -1;
//初始化时间
t1 = GetTickCount();
t2 = GetTickCount();
//初始化小鸟
loadimage(&bird.img2[0][0], "images/bird00.png");
loadimage(&bird.img2[0][1], "images/bird01.png");
loadimage(&bird.img2[1][0], "images/bird10.png");
loadimage(&bird.img2[1][1], "images/bird11.png");
loadimage(&bird.img2[2][0], "images/bird20.png");
loadimage(&bird.img2[2][1], "images/bird21.png");
bird.x = 20;
bird.y = 100;
bird.vy = 0;
bird.g = 1;
int frame = 0; //帧数
//初始化管道
loadimage(&pipe.img3[0], "images/pipe00.png");
loadimage(&pipe.img3[1], "images/pipe01.png");
loadimage(&pipe.img3[2], "images/pipe10.png");
loadimage(&pipe.img3[3], "images/pipe11.png");
pipe.x1 = WIDTH;
pipe.y1 = rand() % 180; //第一根管道
pipe.x2 = WIDTH + 200;
pipe.y2 = rand() % 180; //第二根管道
pipe.x3 = WIDTH + 400;
pipe.y3 = rand() % 180; //第三根管道...
pipe.x4 = WIDTH + 600;
pipe.y4 = rand() % 180;
pipe.x5 = WIDTH + 800;
pipe.y5 = rand() % 180;
pipe.vx = -4; //管道移动速度
}
//界面绘制
void GameDraw()
{
BeginBatchDraw();
//绘制背景
putimage(0, 0, &backimg);
//绘制路面
putimage(round.x, round.y, &round.img);
//绘制管道
putimage(pipe.x1, pipe.y1 + 260, &pipe.img3[0], SRCAND);
putimage(pipe.x1, pipe.y1 + 260, &pipe.img3[1], SRCPAINT);
putimage(pipe.x1, pipe.y1 - 130, &pipe.img3[2], SRCAND);
putimage(pipe.x1, pipe.y1 - 130, &pipe.img3[3], SRCPAINT);
putimage(pipe.x2, pipe.y2 + 260, &pipe.img3[0], SRCAND);
putimage(pipe.x2, pipe.y2 + 260, &pipe.img3[1], SRCPAINT);
putimage(pipe.x2, pipe.y2 - 130, &pipe.img3[2], SRCAND);
putimage(pipe.x2, pipe.y2 - 130, &pipe.img3[3], SRCPAINT);
putimage(pipe.x3, pipe.y3 + 260, &pipe.img3[0], SRCAND);
putimage(pipe.x3, pipe.y3 + 260, &pipe.img3[1], SRCPAINT);
putimage(pipe.x3, pipe.y3 - 130, &pipe.img3[2], SRCAND);
putimage(pipe.x3, pipe.y3 - 130, &pipe.img3[3], SRCPAINT);
putimage(pipe.x4, pipe.y4 + 260, &pipe.img3[0], SRCAND);
putimage(pipe.x4, pipe.y4 + 260, &pipe.img3[1], SRCPAINT);
putimage(pipe.x4, pipe.y4 - 130, &pipe.img3[2], SRCAND);
putimage(pipe.x4, pipe.y4 - 130, &pipe.img3[3], SRCPAINT);
putimage(pipe.x5, pipe.y5 + 260, &pipe.img3[0], SRCAND);
putimage(pipe.x5, pipe.y5 + 260, &pipe.img3[1], SRCPAINT);
putimage(pipe.x5, pipe.y5 - 130, &pipe.img3[2], SRCAND);
putimage(pipe.x5, pipe.y5 - 130, &pipe.img3[3], SRCPAINT);
//绘制小鸟
putimage(bird.x, bird.y, &bird.img2[bird.frame][0], SRCPAINT);
putimage(bird.x, bird.y, &bird.img2[bird.frame][1], SRCAND);
EndBatchDraw();
}
//数据更新
void GameUpdata()
{
//手动更新(玩家操作)
MOUSEMSG msg = { 0 };
if (MouseHit()) //判断是否有鼠标消息
{
msg = GetMouseMsg(); //获取鼠标消息
if (msg.uMsg == WM_LBUTTONDOWN) //鼠标左键
{
bird.vy = -10;
}
else if (msg.uMsg == WM_RBUTTONDOWN)//鼠标右键
{
bird.vy = -10;
}
}
//自动更新
t2 = GetTickCount();//获取本地时间
if (t2 - t1 > 30) //地面移动,以及定义时间频度
{
round.x += round.xv;
if (round.x < -40)
{
round.x = 0; //刷新地面图像
}
if (++bird.frame >= 3)
{
bird.frame = 0; //更新小鸟(拍动翅膀)
}
bird.vy += bird.g; //模拟重力
bird.y += bird.vy; //小鸟下落
pipe.x1 += pipe.vx;
pipe.x2 += pipe.vx;
pipe.x3 += pipe.vx;
pipe.x4 += pipe.vx;
pipe.x5 += pipe.vx;
if (pipe.x1 < -96)
{
pipe.x1 = pipe.x2 + 659;
}
if (pipe.x2 < -96)
{
pipe.x2 = pipe.x3 + 659;
}
if (pipe.x3 < -96)
{
pipe.x3 = pipe.x4 + 659;
}
if (pipe.x4 < -96)
{
pipe.x4 = pipe.x5 + 659;
}
if (pipe.x5 < -96)
{
pipe.x5 = 760;
}
t1 = t2;
}
}
//游戏结束判定
void hitFloor()
{
if (bird.y <= 0 || bird.y >= 270)//碰到天花板和地板判定游戏结束
{
bird.vy = 110;
mciSendString("stop images/bg.mp3", 0, 0, 0);
mciSendString("close images/bg.mp3", 0, 0, 0);
mciSendString("open images/remake.mp3", 0, 0, 0);
mciSendString("play images/remake.mp3", 0, 0, 0);
}
if (bird.x >= pipe.x1 && bird.x <= pipe.x1 + 96 && bird.y <= pipe.y1 + 20)
{
if (bird.x >= pipe.x1 && bird.x <= pipe.x1 + 96 && bird.y >= pipe.y1 - 100)
{
bird.vy = 110;
mciSendString("stop images/bg.mp3", 0, 0, 0);
mciSendString("close images/bg.mp3", 0, 0, 0);
mciSendString("open images/remake.mp3", 0, 0, 0);
mciSendString("play images/remake.mp3", 0, 0, 0);
}
}
if (bird.x >= pipe.x2 && bird.x <= pipe.x2 + 96 && bird.y <= pipe.y2 + 20)
{
if (bird.x >= pipe.x2 && bird.x <= pipe.x2 + 96 && bird.y >= pipe.y2 - 100)
{
bird.vy = 110;
mciSendString("stop images/bg.mp3", 0, 0, 0);
mciSendString("close images/bg.mp3", 0, 0, 0);
mciSendString("open images/remake.mp3", 0, 0, 0);
mciSendString("play images/remake.mp3", 0, 0, 0);
}
}
if (bird.x >= pipe.x3 && bird.x <= pipe.x3 + 96 && bird.y <= pipe.y3 + 20)
{
if (bird.x >= pipe.x3 && bird.x <= pipe.x3 + 96 && bird.y >= pipe.y3 - 100)
{
bird.vy = 110;
mciSendString("stop images/bg.mp3", 0, 0, 0);
mciSendString("close images/bg.mp3", 0, 0, 0);
mciSendString("open images/remake.mp3", 0, 0, 0);
mciSendString("play images/remake.mp3", 0, 0, 0);
}
}
if (bird.x >= pipe.x4 && bird.x <= pipe.x4 + 96 && bird.y <= pipe.y4 + 20)
{
if (bird.x >= pipe.x4 && bird.x <= pipe.x4 + 96 && bird.y >= pipe.y4 - 100)
{
bird.vy = 110;
mciSendString("stop images/bg.mp3", 0, 0, 0);
mciSendString("close images/bg.mp3", 0, 0, 0);
mciSendString("open images/remake.mp3", 0, 0, 0);
mciSendString("play images/remake.mp3", 0, 0, 0);
}
}
if (bird.x >= pipe.x5 && bird.x <= pipe.x5 + 96 && bird.y <= pipe.y5 + 20)
{
if (bird.x >= pipe.x5 && bird.x <= pipe.x5 + 96 && bird.y >= pipe.y5 - 100)
{
bird.vy = 110;
mciSendString("stop images/bg.mp3", 0, 0, 0);
mciSendString("close images/bg.mp3", 0, 0, 0);
mciSendString("open images/remake.mp3", 0, 0, 0);
mciSendString("play images/remake.mp3", 0, 0, 0);
}
}
}
游戏运行画面: