(创作不易,感谢有你,你的支持,就是我前行的最大动力,如果看完对你有帮助,请留下您的足迹)
今天我们来尝试一下用easyx窗口创建飞翔的小鸟游戏
(相关游戏图片我已在末尾给出,欢迎大家保存收藏)
首先与之前的打砖块游戏一样,先引用相关头文件,这里的头文件在我之前的博客中都有讲到,大家可以打开我之前的头文件进行查阅
#include #include //便于引入easyx窗口及其函数 #include //按键控制 #include //便于生成随机函数 #include//这是包含多媒体设备接口头文件 #pragma comment(lib,"winmm.lib")//加载静态库
为了使游戏动画变得更加逼真 ,我上网查阅了很多图片,如果与需要,大家可以联系我,我可以发给大家
定义相关图片(关于图片操作如果有明白的可以查阅http://t.csdn.cn/YJX2h)
IMAGE background;//背景图片 IMAGE bigbird[2];//两张鸟的照片 IMAGE endimg[2];//结束照片 IMAGE down[2];//上边管道的照片 IMAGE up[2];//下边管道的照片
void load()//加载相关图片 { loadimage(&background, "../background.bmp");//加载图片 loadimage(&bigbird[0], "./birdy.bmp",48,48);//照片大小 loadimage(&bigbird[1], "./bird.bmp",48,48); loadimage(&endimg[0], "./end.bmp"); loadimage(&endimg[1], "./end.bmp"); loadimage(&down[0], "./downy.bmp"); loadimage(&down[1], "./down.bmp"); loadimage(&up[0], "./upy.bmp");//管道宽度为52,高度为320 loadimage(&up[1], "./up.bmp"); }
接下来就是对鸟的相关数据进行定义了
struct bird { int x;//鸟的x,y坐标 int y; int speed;//鸟的速度 }; struct bird mybird = { 70,1,70 };
接下来就是对鸟进行绘制 ,这里我们用两张图片对鸟进行绘制,这样的话才能更好得实现动态图画,减少图片背景的影响
void drawbird(int x, int y)//画鸟 { putimage(x, y, &bigbird[0], SRCAND);//SRCAND贴掩码图 putimage(x, y, &bigbird[1], SRCPAINT);//SRCPAINT贴背景图 }
然后就是如何控制鸟,这里的每一个函数我之前在easyx基础中都有讲到,这里我就不多做解释了,如果有需要,可以查阅我之前的easyx键盘控制博客(http://t.csdn.cn/KkFwU)
void keybird()//控制鸟 { char input = _getch(); if (input == 72)//暂停功能,便于暂停游戏 { while (_getch() != 72); } switch (input)//移动鸟 { case ' ': mybird.y -= mybird.speed; CreateThread(NULL, NULL, playMusic, NULL, NULL, NULL);//开辟多线程,防止音乐使游戏变卡 break; default: break; } }
这里我们讲到的多线程,是因为在运行过程中音乐的存在会使游戏变得卡顿,所以在此之前我们先创建一个多线程
DWORD WINAPI playMusic(LPVOID pVoid) { mciSendString("open ./jump.mp3", 0, 0, 0);//打开音乐 mciSendString("play ./jump.mp3 wait", 0, 0, 0);//播放音乐 mciSendString("close ./jump.mp3", 0, 0, 0);//关闭音乐 return 0; }
接下来就是对管道进行定义
struct pillar//定义管道 { int x1 = 288; int x2 = 288 + 190; int y1 = rand() % 250; int y2 = rand() % 250; int vx = -2; }pillar;
//碰撞边界或者管道 int hitfloor() { if (mybird.y <= 0 || mybird.y > 512|| (mybird.x>=pillar.x1&&mybird.x<=(pillar.x1+52)&&(mybird.y<=(pillar.y1+20)||mybird.y>=(pillar.y1+160)))|| (mybird.x >= pillar.x2 && mybird.x <= (pillar.x2 + 52) && (mybird.y <= (pillar.y2 + 20) || mybird.y >= (pillar.y2 + 160)))) return 1; return 0; }
//结束动画 void gameover() { int x = 60; int y = 608; while (y >= 240) { putimage(0, 0, &background); putimage(x, y, &endimg[0], SRCAND); putimage(x, y, &endimg[1], SRCPAINT); y -= 50; Sleep(50); } HWND hwnd = GetHWnd();//获得窗口句柄 MessageBox(hwnd, "gameover", "提示", MB_OK);//弹出窗口 }
在上面我们加载了相关的图片,现在我们将其进行输出
void drawpillar()//输出相关图片 { putimage(pillar.x1, pillar.y1-300, &down[0], SRCAND); putimage(pillar.x1, pillar.y1-300, &down[1], SRCPAINT); putimage(pillar.x1, pillar.y1 + 160, &up[0], SRCAND); putimage(pillar.x1, pillar.y1 + 160, &up[1], SRCPAINT); putimage(pillar.x2, pillar.y2 - 300, &down[0], SRCAND); putimage(pillar.x2, pillar.y2 - 300, &down[1], SRCPAINT); putimage(pillar.x2, pillar.y2 + 160, &up[0], SRCAND); putimage(pillar.x2, pillar.y2 + 160, &up[1], SRCPAINT); }
接下来就是管道的移动以及不断循环了,因为我们上面只定义了两组管道,所以需要不断循环才能实现管道的不断输出
void movepillar()//移动管道 { pillar.x1 += pillar.vx; pillar.x2 += pillar.vx; if (pillar.x1 <= -52)//管道循坏处理 pillar.x1 = pillar.x2 + 190; if (pillar.x2 < -52) pillar.x2 = pillar.x1 + 190; }
最后就是将其集中在主函数之中,主函数的相关细节在我之前的easyx基础中均有涉及,欢迎大家查阅
int main() { srand((unsigned int)time(NULL));//生成随机数种子 initgraph(288,608);//创建主窗口 load(); while (1) { cleardevice();//清屏函数,防止图片加载卡顿 putimage(0, 0, &background);//输出图片,坐标,地址 drawbird(mybird.x, mybird.y); drawpillar(); movepillar(); if (hitfloor()) { gameover(); break; } mybird.y += 10; //如果不加kbhit,图像在不按键时就不会动 if (_kbhit())//判断是否有按键,有按键才处理,无按键就不处理 { keybird(); } Sleep(50); } getchar();//防止闪退 closegraph(); return 0; }
总体代码就是这样,如果大家发现bug或者有更好的方法 ,欢迎大家一起来讨论
#define _CRT_SECURE_NO_WARNINGS 1 #include<stdio.h> #include<graphics.h> //便于引入easyx窗口及其函数 #include<conio.h> //按键控制 #include<time.h> #include<mmsystem.h>//这是包含多媒体设备接口头文件 #pragma comment(lib,"winmm.lib")//加载静态库 IMAGE background;//背景图片 IMAGE bigbird[2];//两张鸟的照片 IMAGE endimg[2];//结束照片 IMAGE down[2];//上边柱子的照片 IMAGE up[2];//下边柱子的照片 //定义鸟的变量 struct bird { int x;//鸟的x,y坐标 int y; int speed;//鸟的速度 }; struct bird mybird = { 70,1,70 }; void load()//加载相关图片 { loadimage(&background, "../background.bmp");//加载图片 loadimage(&bigbird[0], "./birdy.bmp",48,48);//照片大小 loadimage(&bigbird[1], "./bird.bmp",48,48); loadimage(&endimg[0], "./endy.bmp"); loadimage(&endimg[1], "./end.bmp"); loadimage(&down[0], "./downy.bmp"); loadimage(&down[1], "./down.bmp"); loadimage(&up[0], "./upy.bmp");//管道宽度为52,高度为320 loadimage(&up[1], "./up.bmp"); } void drawbird(int x, int y)//画鸟 { putimage(x, y, &bigbird[0], SRCAND);//SRCAND贴掩码图 putimage(x, y, &bigbird[1], SRCPAINT);//SRCPAINT贴背景图 } DWORD WINAPI playMusic(LPVOID pVoid) { mciSendString("open ./jump.mp3", 0, 0, 0);//打开音乐 mciSendString("play ./jump.mp3 wait", 0, 0, 0);//播放音乐 mciSendString("close ./jump.mp3", 0, 0, 0);//关闭音乐 return 0; } void keybird()//控制鸟 { char input = _getch(); if (input == 72)//暂停功能 { while (_getch() != 72); } switch (input)//移动鸟 { case ' ': mybird.y -= mybird.speed; CreateThread(NULL, NULL, playMusic, NULL, NULL, NULL);//开辟多线程,防止音乐使游戏变卡 break; default: break; } } struct pillar//定义柱子 { int x1 = 288; int x2 = 288 + 190; int y1 = rand() % 250; int y2 = rand() % 250; int vx = -2; }pillar; //碰撞边界 int hitfloor() { if (mybird.y <= 0 || mybird.y > 512|| (mybird.x>=pillar.x1&&mybird.x<=(pillar.x1+52)&&(mybird.y<=(pillar.y1+20)||mybird.y>=(pillar.y1+160)))|| (mybird.x >= pillar.x2 && mybird.x <= (pillar.x2 + 52) && (mybird.y <= (pillar.y2 + 20) || mybird.y >= (pillar.y2 + 160)))) return 1; return 0; } //结束动画 void gameover() { int x = 60; int y = 608; while (y >= 240) { putimage(0, 0, &background); putimage(x, y, &endimg[0], SRCAND); putimage(x, y, &endimg[1], SRCPAINT); y -= 50; Sleep(50); } HWND hwnd = GetHWnd();//获得窗口句柄 MessageBox(hwnd, "gameover", "提示", MB_OK);//弹出窗口 } void drawpillar()//输出相关图片 { putimage(pillar.x1, pillar.y1-300, &down[0], SRCAND); putimage(pillar.x1, pillar.y1-300, &down[1], SRCPAINT); putimage(pillar.x1, pillar.y1 + 160, &up[0], SRCAND); putimage(pillar.x1, pillar.y1 + 160, &up[1], SRCPAINT); putimage(pillar.x2, pillar.y2 - 300, &down[0], SRCAND); putimage(pillar.x2, pillar.y2 - 300, &down[1], SRCPAINT); putimage(pillar.x2, pillar.y2 + 160, &up[0], SRCAND); putimage(pillar.x2, pillar.y2 + 160, &up[1], SRCPAINT); } void movepillar()//移动管道 { pillar.x1 += pillar.vx; pillar.x2 += pillar.vx; if (pillar.x1 <= -52)//管道循坏处理 { pillar.x1 = pillar.x2 + 190; pillar.y1 = rand() % 250;//使每一次管道的位置都不一样 } if (pillar.x2 < -52) { pillar.x2 = pillar.x1 + 190; pillar.y2 = rand() % 250; } } int main() { srand((unsigned int)time(NULL));//生成随机数种子 initgraph(288,608);//创建主窗口 load(); while (1) { cleardevice(); putimage(0, 0, &background);//输出图片,坐标,地址 drawbird(mybird.x, mybird.y); drawpillar(); movepillar(); if (hitfloor()) { gameover(); break; } mybird.y += 10; //如果不加kbhit,图像在不按键时就不会动 if (_kbhit())//判断是否有按键,有按键才处理,无按键就不处理 { keybird(); } Sleep(50); } getchar();//防止闪退 closegraph(); return 0; }
加油
游戏相关代码的掩码图和背景图: