网站建设需求表模板,做网站违法吗,网赌网站国外空间,公司建网站会计分录天天酷跑项目的开发
项目前言 项目是基于Windows#xff0c;easyX图形库进行开发的#xff0c; 开发环境#xff1a;Visual Studio 2022 项目技术最低要求#xff1a; 常量#xff0c;变量#xff0c;数组#xff0c;循环#xff0c;函数。 文章目录 天天酷跑项目的…天天酷跑项目的开发
项目前言 项目是基于WindowseasyX图形库进行开发的 开发环境Visual Studio 2022 项目技术最低要求 常量变量数组循环函数。 文章目录 天天酷跑项目的开发项目前言游戏背景的实现实现玩家的奔跑实现人物的跳跃获取玩家的输入 优化帧等待随机出现小乌龟障碍使用结构体优化障碍使用结构体后重新初始化游戏 实现下蹲技能添加柱子障碍物碰撞检测实现血条判断游戏结束 添加背景音乐 添加初始界面优化死亡BUG跨越障碍后计算得分判断游戏胜利源代码 游戏背景的实现
使用initgraph()初始化界面加载背景资源
写好游戏的图像化界面的框架 由于easyX不支持透明图片的的贴图所以我们要自己写一个透明贴图的函数这里给出3个
// 适用于 y 0 以及y0的任何情况
void putimagePNG2(int x, int y, IMAGE* picture);
void putimagePNG2(int x, int y, int winWidth, IMAGE* picture);
void putimagePNG(int picture_x, int picture_y, IMAGE* picture);
// 适用于 y 0 以及x0的任何情况
void putimagePNG2(int x, int y, IMAGE* picture) {IMAGE imgTmp;if (y 0) {SetWorkingImage(picture);getimage(imgTmp, 0, -y,picture-getwidth(), picture-getheight() y);SetWorkingImage();y 0;picture imgTmp;}if (x 0) {SetWorkingImage(picture);getimage(imgTmp, -x, 0, picture-getwidth() x, picture-getheight());SetWorkingImage();x 0;picture imgTmp;}putimagePNG(x, y, picture);
}// 适用于 y 0 以及y0的任何情况
void putimagePNG2(int x, int y, int winWidth, IMAGE* picture) {IMAGE imgTmp;if (y 0) {SetWorkingImage(picture);getimage(imgTmp, 0, -y,picture-getwidth(), picture-getheight() y);SetWorkingImage();y 0;picture imgTmp;}if (x 0) {SetWorkingImage(picture);getimage(imgTmp, -x, 0, picture-getwidth() x, picture-getheight());SetWorkingImage();x 0;picture imgTmp;}else if (x winWidth) {return;}else if (x winWidth - picture-getwidth()) {SetWorkingImage(picture);getimage(imgTmp, 0, 0, winWidth - x, picture-getheight());SetWorkingImage();picture imgTmp;}putimagePNG(x, y, picture);
}// 载入PNG图并去透明部分
void putimagePNG(int picture_x, int picture_y, IMAGE* picture) //x为载入图片的X坐标y为Y坐标
{DWORD* dst GetImageBuffer(); // GetImageBuffer()函数用于获取绘图设备的显存指针EASYX自带DWORD* draw GetImageBuffer();DWORD* src GetImageBuffer(picture); //获取picture的显存指针int picture_width picture-getwidth(); //获取picture的宽度EASYX自带int picture_height picture-getheight(); //获取picture的高度EASYX自带int graphWidth getwidth(); //获取绘图区的宽度EASYX自带int graphHeight getheight(); //获取绘图区的高度EASYX自带int dstX 0; //在显存里像素的角标// 实现透明贴图 公式 Cpαp*FP(1-αp)*BP 贝叶斯定理来进行点颜色的概率计算for (int iy 0; iy picture_height; iy){for (int ix 0; ix picture_width; ix){int srcX ix iy * picture_width; //在显存里像素的角标int sa ((src[srcX] 0xff000000) 24); //0xAArrggbb;AA是透明度int sr ((src[srcX] 0xff0000) 16); //获取RGB里的Rint sg ((src[srcX] 0xff00) 8); //Gint sb src[srcX] 0xff; //Bif (ix 0 ix graphWidth iy 0 iy graphHeight dstX graphWidth * graphHeight){dstX (ix picture_x) (iy picture_y) * graphWidth; //在显存里像素的角标int dr ((dst[dstX] 0xff0000) 16);int dg ((dst[dstX] 0xff00) 8);int db dst[dstX] 0xff;draw[dstX] ((sr * sa / 255 dr * (255 - sa) / 255) 16) //公式 Cpαp*FP(1-αp)*BP αpsa/255 , FPsr , BPdr| ((sg * sa / 255 dg * (255 - sa) / 255) 8) //αpsa/255 , FPsg , BPdg| (sb * sa / 255 db * (255 - sa) / 255); //αpsa/255 , FPsb , BPdb}}}
}
//定义相关的变量
IMAGE imgBgs[3]; // 背景图片
int bgX[3]; //背景图片的x坐标
int bgSpeed[3] { 1, 2, 4 };//三重背景以不同速度行驶
三张背景图片需要载入 //直接在初始化中加载到内存char name[64];for (int i 0; i 3; i) {// res/bg001.png res/bg002.png res/bg003.png sprintf(name, res/bg%03d.png, i 1);loadimage(imgBgs[i], name);bgX[i] 0;}注这里的图片在main.cpp文件夹中的res文件夹下。
再在updateBg的函数中进行渲染 putimagePNG2(bgX[0], 0, imgBgs[0]);putimagePNG2(bgX[1], 119, imgBgs[1]);putimagePNG2(bgX[2], 330, imgBgs[2]);编译如果遇到C4996错误只需要在项目属性c/c中关掉SDL检查即可。 如果出现loadimage()的错误可能是字符集的问题只需要在项目属性-高级-字符集-使用多字节字符集即可 看一下执行结果。 如果不使用透明贴图函数 图片成功渲染但是在实际的游戏中背景是会移动的且遵守基本的物理。
接下来我们需要移动背景。远处的移动慢中处更快最近处看起来最快所以速度可以取int bgSpeed[3] { 1, 2, 4 };
void moveBg() {for (int i 0; i 3; i) {bgX[i] - bgSpeed[i];if (bgX[i] -WIN_WIDTH) {bgX[i] 0;}}在main函数中载入死循环 这样背景就可以无休止的移动了
int main(void) {init();while (1) {BeginBatchDraw();updateBg();EndBatchDraw();moveBg();Sleep(30);}
//使用beginbatchdraw 和endbatchdraw进行优化渲染。}实现玩家的奔跑
IMAGE imgHeros[12];//玩家的帧图片
int heroX; //玩家的x坐标
int heroY; //玩家的y坐标
int heroIndex; //玩家奔跑的图片帧序号初始化的时候也初始化玩家 // 加载Hero奔跑的图片帧素材for (int i 0; i 12; i) {// res/hero1.png ... res/hero12.pngsprintf(name, res/hero%d.png, i 1);loadimage(imgHeros[i], name);}// 设置玩家的初始位置heroX WIN_WIDTH * 0.5 - imgHeros[0].getwidth() * 0.5;heroY 345 - imgHeros[0].getheight();heroIndex 0;在Main函数中给hero贴图 putimagePNG2(heroX, heroY, imgHeros[heroIndex]);更改人物帧图片让人物看起来会动 heroIndex (heroIndex 1) % 12;RUN 实现人物的跳跃
初始化函数中 heroJump false;
jumpHeightMax 345 - imgHeros[0].getheight() - 120;
heroJumpOff -4;bool heroJump; //表示玩家正在跳跃
int jumpHeightMax;
int heroJumpOff;int jump()
{// 实现跳跃if (heroJump) {if (heroY jumpHeightMax) {heroJumpOff 4;}heroY heroJumpOff;if (heroY 345 - imgHeros[0].getheight()) {heroJump false;heroJumpOff -4;}}else { //不跳跃heroIndex (heroIndex 1) % 12;}
}void jump() {heroJump true;
}获取玩家的输入
// 处理用户按键的输入
void keyEvent() {char ch;if (_kbhit()) { //如果有按键按下_kbhit()返回 true ch _getch(); // _getch()不需要按下回车即可直接读取if (ch ) {jump();}}
}
main()
int main(void) {init();while (1) {keyEvent();BeginBatchDraw();updateBg();putimagePNG2(heroX, heroY, imgHeros[heroIndex]);EndBatchDraw();moveBg();HeroIndex();jump(heroJump);Sleep(15);}}优化帧等待
bool update; //表示是否需要马上刷新画面init()尾部 update true;
void jump() {heroJump true;update true;
}int getDelay() {static unsigned long long lastTime 0;unsigned long long currentTime GetTickCount();if (lastTime 0) {lastTime currentTime;return 0;}else {int ret currentTime - lastTime;lastTime currentTime;return ret;}
}main函数主体
int main(void) {int timer 0;init();while (1) {keyEvent();timer getDelay();//10if (timer 30) {timer 0;update true;}if (update){update false;BeginBatchDraw();updateBg();putimagePNG2(heroX, heroY, imgHeros[heroIndex]);EndBatchDraw();moveBg();HeroIndex();jump(heroJump);} }return 0;
}
随机出现小乌龟障碍
定义乌龟相关的变量
IMAGE imgTortoise; //小乌龟
int torToiseX; //小乌龟的水平坐标
int torToiseY; //小乌龟的垂直坐标
bool torToiseExist; //当前窗口是否有小乌龟在init()函数中初始化乌龟 // 加载小乌龟素材loadimage(imgTortoise, res/t1.png);torToiseExist false;torToiseY 345 - imgTortoise.getheight() 5;定义一个函数创建小乌龟
void creatTortoise() {// 创建小乌龟static int frameCount 0;static int torToiseFre 100;frameCount;if (frameCount torToiseFre) {frameCount 0;if (!torToiseExist) {torToiseExist true;torToiseX WIN_WIDTH;torToiseFre 200 rand() % 300;}}if (torToiseExist) {torToiseX - bgSpeed[2];if (torToiseX -imgTortoise.getwidth()) {torToiseExist false;}}
}
创建函数对乌龟进行渲染
void updateEnemy() {// 渲染小乌龟if (torToiseExist) {putimagePNG2(torToiseX, torToiseY, WIN_WIDTH, imgTortoise);}
}再把creattortorise 在main函数中调用if语句中 update false;BeginBatchDraw();updateBg();putimagePNG2(heroX, heroY, imgHeros[heroIndex]);updateEnemy();EndBatchDraw();moveBg();HeroIndex();creatTortoise();jump(heroJump);
使用结构体优化障碍
添加头文件\#include vector
#define OBSTACLE_COUNT 10
typedef enum {TORTOISE, //乌龟 0LION, //狮子 1OBSTACLE_TYPE_COUNT // 2
} obstacle_type;vectorvectorIMAGEobstacleImgs; //存放所有障碍物的各个图片typedef struct obstacle {obstacle_type type; //障碍物的类型 int imgIndex; //当前显示的图片的序号int x, y; //障碍物的坐标int speed;int power; //杀伤力bool exist;
}obstacle_t;
使用结构体后重新初始化游戏
obstacle_t obstacles[OBSTACLE_COUNT];
// 游戏的初始化
void init() {// 创建游戏窗口initgraph(WIN_WIDTH, WIN_HEIGHT);// 加载背景资源char name[64];for (int i 0; i 3; i) {// res/bg001.png res/bg002.png res/bg003.png sprintf(name, res/bg%03d.png, i 1);loadimage(imgBgs[i], name);bgX[i] 0;}// 加载Hero奔跑的图片帧素材for (int i 0; i 12; i) {// res/hero1.png ... res/hero12.pngsprintf(name, res/hero%d.png, i 1);loadimage(imgHeros[i], name);}// 设置玩家的初始位置heroX WIN_WIDTH * 0.5 - imgHeros[0].getwidth() * 0.5;heroY 345 - imgHeros[0].getheight();heroIndex 0;heroJump false;jumpHeightMax 345 - imgHeros[0].getheight() - 120;heroJumpOff -4;update true;IMAGE imgTort;loadimage(imgTort, res/t1.png);vectorIMAGE imgTortArray;imgTortArray.push_back(imgTort);obstacleImgs.push_back(imgTortArray);IMAGE imgLion;vectorIMAGE imgLionArray;for (int i 0; i 6; i) {sprintf(name, res/p%d.png, i 1);loadimage(imgLion, name);imgLionArray.push_back(imgLion);}obstacleImgs.push_back(imgLionArray);// 初始化障碍物池for (int i 0; i OBSTACLE_COUNT; i) {obstacles[i].exist false;}
}创建函数初始化障碍物我们将用此函数创建所有的障碍物
void createObstacle() {int i;for (i 0; i OBSTACLE_COUNT; i) {if (obstacles[i].exist false) {break;}}if (i OBSTACLE_COUNT) {return;}obstacles[i].exist true;obstacles[i].imgIndex 0;obstacles[i].type (obstacle_type)(rand() % OBSTACLE_TYPE_COUNT);obstacles[i].x WIN_WIDTH;obstacles[i].y 345 5 - obstacleImgs[obstacles[i].type][0].getheight();if (obstacles[i].type TORTOISE) {obstacles[i].speed 0;obstacles[i].power 5; //自己修改}else if (obstacles[i].type LION) {obstacles[i].speed 4;obstacles[i].power 20;}
}再写一个函数进行创建障碍物的数据计算
void createObstacleData() {static int frameCount 0;static int enemyFre 50;frameCount;if (frameCount enemyFre) {frameCount 0;enemyFre 50 rand() % 50; // 50..99createObstacle();}// 更新所有障碍物的坐标for (int i 0; i OBSTACLE_COUNT; i) {if (obstacles[i].exist) {obstacles[i].x - obstacles[i].speed bgSpeed[2];if (obstacles[i].x -obstacleImgs[obstacles[i].type][0].getwidth() * 2) {obstacles[i].exist false;}int len obstacleImgs[obstacles[i].type].size();obstacles[i].imgIndex (obstacles[i].imgIndex 1) % len;}}
}
在对敌人初始化
void updateEnemy() {// 渲染小乌龟//if (torToiseExist) {// putimagePNG2(torToiseX, torToiseY, WIN_WIDTH, imgTortoise);//}for (int i 0; i OBSTACLE_COUNT; i) {if (obstacles[i].exist) {putimagePNG2(obstacles[i].x, obstacles[i].y, WIN_WIDTH,obstacleImgs[obstacles[i].type][obstacles[i].imgIndex]);}}
}一下是main函数的主体 if (update){update false;BeginBatchDraw();updateBg();putimagePNG2(heroX, heroY, imgHeros[heroIndex]);updateEnemy();EndBatchDraw();updateEnemy();moveBg();HeroIndex();createObstacleData();jump(heroJump);}实现下蹲技能
IMAGE imgHeroDown[2];
bool heroDown; //表示玩家是否处于下蹲状态init()中对其初始化
// 初始化障碍物池for (int i 0; i OBSTACLE_COUNT; i) {obstacles[i].exist false;}// 加载下蹲素材loadimage(imgHeroDown[0], res/d1.png);loadimage(imgHeroDown[1], res/d2.png);heroDown false;
我们写一个heroupdown函数集成up和down方便进行管理
void heroupdown()
{// 实现跳跃if (heroJump) {if (heroY jumpHeightMax) {heroJumpOff 4;}heroY heroJumpOff;if (heroY 345 - imgHeros[0].getheight()) {heroJump false;heroJumpOff -4;}}else if (heroDown) {static int count 0;int delays[2] { 4, 10 };count;if (count delays[heroIndex]) {count 0;heroIndex;if (heroIndex 2) {heroIndex 0;heroDown false;}}}else { //不跳跃heroIndex (heroIndex 1) % 12;}
}
void down() {update true;heroDown true;heroIndex 0;
}在接受键盘进行响应
void keyEvent() {char ch;if (_kbhit()) { //如果有按键按下_kbhit()返回 true ch _getch(); // _getch()不需要按下回车即可直接读取if (ch ) {jump();}else if (ch a) {down();}}
}void updateHero() {if (!heroDown) {putimagePNG2(heroX, heroY, imgHeros[heroIndex]);}else {int y 345 - imgHeroDown[heroIndex].getheight();putimagePNG2(heroX, y, imgHeroDown[heroIndex]);}}main函数主体
int main(void) {int timer 0;init();while (1) {keyEvent();timer getDelay();//10if (timer 20) {timer 0;update true;}if (update){update false;BeginBatchDraw();updateBg();//putimagePNG2(heroX, heroY, imgHeros[heroIndex]);updateHero(); updateEnemy();EndBatchDraw();moveBg();heroupdown();createObstacleData();}}return 0;
}
添加柱子障碍物
老规矩 加载-初始化
typedef enum {TORTOISE, //乌龟 0LION, //狮子 1OBSTACLE_TYPE_COUNT // 2HOOK1, //勾子HOOK2,HOOK3,HOOK4,
} obstacle_type;
void createObstacle() {srand((unsigned)time(NULL));int i;for (i 0; i OBSTACLE_COUNT; i) {if (obstacles[i].exist false) {break;}}if (i OBSTACLE_COUNT) {return;}obstacles[i].exist true;obstacles[i].imgIndex 0;//obstacles[i].type (obstacle_type)(rand() % OBSTACLE_TYPE_COUNT);obstacles[i].type (obstacle_type)(rand() % 3);obstacles[i].x WIN_WIDTH;obstacles[i].y 345 5 - obstacleImgs[obstacles[i].type][0].getheight();if (obstacles[i].type HOOK1) {obstacles[i].type (obstacle_type)((int)(obstacles[i].type) rand() % 4);}if (obstacles[i].type TORTOISE) {obstacles[i].speed 0;obstacles[i].power 5; //自己修改}else if (obstacles[i].type LION) {obstacles[i].speed 4;obstacles[i].power 20;}else if (obstacles[i].type HOOK1 obstacles[i].type HOOK4) {obstacles[i].speed 0;obstacles[i].power 20;obstacles[i].y 0;}}
碰撞检测
typedef struct obstacle {obstacle_type type; //障碍物的类型int imgIndex; //当前显示的图片的序号int x, y; //障碍物的坐标int speed;int power; //杀伤力bool exist;bool hited;//是否撞击
}obstacle_t;
void preLoadSound(const char* name) {char cmd[512];sprintf_s(cmd, sizeof(cmd), open %s alias %s-1, name, name);mciSendString(cmd, 0, 0, 0);sprintf_s(cmd, sizeof(cmd), open %s alias %s-2, name, name);mciSendString(cmd, 0, 0, 0);
}
bool rectIntersect(int x01, int y01, int x02, int y02,int x11, int y11, int x12, int y12)
{int zx abs(x01 x02 - x11 - x12);int x abs(x01 - x02) abs(x11 - x12);int zy abs(y01 y02 - y11 - y12);int y abs(y01 - y02) abs(y11 - y12);return (zx x zy y);
}
void playSound(const char* name) {static int index 1;char cmd[512];if (index 1) {sprintf_s(cmd, sizeof(cmd), play %s-1, name);mciSendString(cmd, 0, 0, 0);sprintf_s(cmd, sizeof(cmd), close %s-2, name);mciSendString(cmd, 0, 0, 0);sprintf_s(cmd, sizeof(cmd), open %s alias %s-2, name, name);mciSendString(cmd, 0, 0, 0);index;}else if (index 2) {sprintf_s(cmd, sizeof(cmd), play %s-2, name);mciSendString(cmd, 0, 0, 0);sprintf_s(cmd, sizeof(cmd), close %s-1, name);mciSendString(cmd, 0, 0, 0);sprintf_s(cmd, sizeof(cmd), open %s alias %s-1, name, name);mciSendString(cmd, 0, 0, 0);index 1;}
}
void checkHit()
{for (int i 0; i OBSTACLE_COUNT; i){if (obstacles[i].exist obstacles[i].hited false){int a1x, a1y, a2x, a2y;int off 20;if (!heroDown)//非下蹲 奔跑 跳跃{a1x heroX off;a1y heroY off;a2x heroX imgHeros[heroIndex].getwidth() - off;a2y heroY imgHeros[heroIndex].getheight();}else { //下蹲状态a1x heroX off;a1y 345 - imgHeroDown[heroIndex].getheight();a2x heroX imgHeroDown[heroIndex].getwidth() - off;a2y 345;}IMAGE img obstacleImgs[obstacles[i].type][obstacles[i].imgIndex];int b1x obstacles[i].x off;int b1y obstacles[i].y off;int b2x obstacles[i].x img.getwidth() - off;int b2y obstacles[i].y img.getheight() - 10;if (rectIntersect(a1x, a1y, a2x, a2y, b1x, b1y, b2x, b2y)){heroBlood - obstacles[i].power;playSound(res/hit.mp3);obstacles[i].hited true;}}}} 实现血条
优化下蹲
int delays[2] { 6, 10 };
改成 int delays[2] { 8, 30 };
头文件
#include mmsystem.h #pragma comment(lib, “winmm.lib”)
void updateBloodBar() {drawBloodBar(10, 10, 200, 10, 2, BLUE, DARKGRAY, RED, heroBlood / 100.0);
}void drawBloodBar(int x, int y, int width, int height, int lineWidth, int boardColor, int emptyColor, int fillColor, float percent) {LINESTYLE lineStyle;getlinestyle(lineStyle);int lineColor getlinecolor();int fileColor getfillcolor();if (percent 0) {percent 0;}setlinecolor(BLUE);setlinestyle(PS_SOLID | PS_ENDCAP_ROUND, lineWidth);setfillcolor(emptyColor);fillrectangle(x, y, x width, y height);setlinestyle(PS_SOLID | PS_ENDCAP_FLAT, 0);setfillcolor(fillColor);setlinecolor(fillColor);if (percent 0) {fillrectangle(x 0.5 * lineWidth, y lineWidth * 0.5, x width * percent, y height - 0.5 * lineWidth);}setlinecolor(lineColor);setfillcolor(fillColor);setlinestyle(lineStyle);
}void init() {// 创建游戏窗口initgraph(WIN_WIDTH, WIN_HEIGHT);// 加载背景资源char name[64];for (int i 0; i 3; i) {// res/bg001.png res/bg002.png res/bg003.png sprintf(name, res/bg%03d.png, i 1);loadimage(imgBgs[i], name);bgX[i] 0;}// 加载Hero奔跑的图片帧素材for (int i 0; i 12; i) {// res/hero1.png ... res/hero12.pngsprintf(name, res/hero%d.png, i 1);loadimage(imgHeros[i], name);}// 设置玩家的初始位置heroX WIN_WIDTH * 0.5 - imgHeros[0].getwidth() * 0.5;heroY 345 - imgHeros[0].getheight();heroIndex 0;heroJump false;jumpHeightMax 345 - imgHeros[0].getheight() - 120;heroJumpOff -4;update true;IMAGE imgTort;loadimage(imgTort, res/t1.png);vectorIMAGE imgTortArray;imgTortArray.push_back(imgTort);obstacleImgs.push_back(imgTortArray);IMAGE imgLion;vectorIMAGE imgLionArray;for (int i 0; i 6; i) {sprintf(name, res/p%d.png, i 1);loadimage(imgLion, name);imgLionArray.push_back(imgLion);}obstacleImgs.push_back(imgLionArray);// 初始化障碍物池for (int i 0; i OBSTACLE_COUNT; i) {obstacles[i].exist false;}// 加载下蹲素材loadimage(imgHeroDown[0], res/d1.png);loadimage(imgHeroDown[1], res/d2.png);heroDown false;// 加载“柱子”障碍物IMAGE imgH;vectorIMAGE imgHookArray;for (int i 0; i 4; i) {sprintf_s(name, sizeof(name), res/h%d.png, i 1); //帧图片不够补帧loadimage(imgH, name, 63, 260, true);imgHookArray.push_back(imgH);obstacleImgs.push_back(imgHookArray);imgHookArray.pop_back();}heroBlood 100;// 预加载音效preLoadSound(res/hit.mp3);}
main updateBloodBar();
判断游戏结束 添加背景音乐 添加初始界面
用屁股想 是初始化函数中 mciSendString(play res/bg.mp3, 0, 0, 0);if (rectIntersect(a1x, a1y, a2x, a2y, b1x, b1y, b2x, b2y)) {heroBlood - obstacles[i].power;printf(血量剩余 %d\n, heroBlood);playSound(res/hit.mp3);obstacles[i].hited true;}void checkOver() {if (heroBlood 0) {loadimage(0, res/over.png);FlushBatchDraw();mciSendString(stop res/bg.mp3, 0, 0, 0);system(pause);// 暂停之后充币复活或者直接开始下一局heroBlood 100;mciSendString(play res/bg.mp3, 0, 0, 0);}
}int main(void) {int timer 0;init();// 显示初始画面loadimage(0, res/over.png);system(pause);while (1) {keyEvent();timer getDelay();//10if (timer 20) {timer 0;update true;}if (update){update false;BeginBatchDraw();updateBg();updateHero(); updateEnemy();updateBloodBar();EndBatchDraw();moveBg();heroupdown();createObstacleData();checkHit();checkOver();}}return 0;
}
优化死亡BUG
int lastObsIndex; //last obstacle indexvoid createObstacle() {srand((unsigned)time(NULL));int i;for (i 0; i OBSTACLE_COUNT; i) {if (obstacles[i].exist false) {break;}}if (i OBSTACLE_COUNT) {return;}obstacles[i].exist true;obstacles[i].imgIndex 0;//obstacles[i].type (obstacle_type)(rand() % OBSTACLE_TYPE_COUNT);obstacles[i].type (obstacle_type)(rand() % 3);obstacles[i].x WIN_WIDTH;obstacles[i].y 345 5 - obstacleImgs[obstacles[i].type][0].getheight();if (lastObsIndex HOOK1 lastObsIndex HOOK4 obstacles[i].type LION obstacles[lastObsIndex].x (WIN_WIDTH - 500)) {obstacles[i].type TORTOISE;}lastObsIndex i;if (obstacles[i].type HOOK1) {obstacles[i].type (obstacle_type)((int)(obstacles[i].type) rand() % 4);}if (obstacles[i].type TORTOISE) {obstacles[i].speed 0;obstacles[i].power 5; //自己修改}else if (obstacles[i].type LION) {obstacles[i].speed 4;obstacles[i].power 20;}else if (obstacles[i].type HOOK1 obstacles[i].type HOOK4) {obstacles[i].speed 0;obstacles[i].power 20;obstacles[i].y 0;}}
跨越障碍后计算得分
int score; //分数lastObsIndex -1;score 0;void checkScore() {for (int i 0; i OBSTACLE_COUNT; i) {if (obstacles[i].exist obstacles[i].passed false obstacles[i].x obstacleImgs[obstacles[i].type][0].getwidth() heroX) {score;obstacles[i].passed true;printf(score: %d\n, score);}}
}typedef struct obstacle {obstacle_type type; //障碍物的类型int imgIndex; //当前显示的图片的序号int x, y; //障碍物的坐标int speed;int power; //杀伤力bool exist;bool hited;bool passed;
}obstacle_t;int main(void) {int timer 0;init();// 显示初始画面loadimage(0, res/over.png);system(pause);while (1) {keyEvent();timer getDelay();//10if (timer 20) {timer 0;update true;}if (update){update false;BeginBatchDraw();updateBg();updateHero(); updateEnemy();updateBloodBar();EndBatchDraw();moveBg();heroupdown();createObstacleData();checkHit();checkOver();checkScore();}}return 0;
}void updateScore() {// 50 50 5 5-0 5 char str[8];sprintf(str, %d, score);int x 20;int y 25;for (int i 0; str[i]; i) {int sz str[i] - 0;putimagePNG(x, y, imgSZ[sz]);x imgSZ[sz].getwidth() 5;}
} updateBloodBar();updateScore();EndBatchDraw();checkOver();checkScore();判断游戏胜利
写main函数中的位置 这里不再赘述
#define WIN_SCORE 100
void checkWin() {if (score WIN_SCORE) {FlushBatchDraw();mciSendString(play res/win.mp3, 0, 0, 0);Sleep(2000);loadimage(0, res/win.png);FlushBatchDraw();mciSendString(stop res/bg.mp3, 0, 0, 0);system(pause);heroBlood 100;score 0;mciSendString(play res/bg.mp3 repeat, 0, 0, 0);}
}
源代码
#include stdio.h
#include graphics.h
#include conio.h
#include vector
#include time.h
#include mmsystem.h
#pragma comment(lib, winmm.lib)#define WIN_SCORE 100
#define WIN_WIDTH 1012
#define WIN_HEIGHT 396
#define OBSTACLE_COUNT 10using namespace std;IMAGE imgHeros[12];
IMAGE imgBgs[3];
IMAGE imgHeroDown[2];
int bgX[3];
int bgSpeed[3] { 1, 2, 4 };
int heroX;
int heroY;
int heroIndex;
bool heroJump;
int jumpHeightMax;
int heroJumpOff;
bool update;
bool heroDown;
int heroBlood;
int score;
int lastObsIndex;typedef enum {TORTOISE, //乌龟 0LION, //狮子 1 HOOK1, //勾子HOOK2,HOOK3,HOOK4,OBSTACLE_TYPE_COUNT ,
} obstacle_type;vectorvectorIMAGEobstacleImgs; //存放所有障碍物的各个图片typedef struct obstacle {obstacle_type type; //障碍物的类型int imgIndex; //当前显示的图片的序号int x, y; //障碍物的坐标int speed;int power; //杀伤力bool exist;bool hited;bool passed;
}obstacle_t;obstacle_t obstacles[OBSTACLE_COUNT];void preLoadSound(const char* name);
void drawBloodBar(int x, int y, int width, int height, int lineWidth, int boardColor, int emptyColor, int fillColor, float percent);void init();
void moveBg();
void jump();
void heroupdown();
int getDelay();
void keyEvent();
void updateBg();
void updateEnemy();
void jump(bool herJump);
bool rectIntersect(int a1X, int a1Y, int a2X, int a2Y,int b1X, int b1Y, int b2X, int b2Y);
void updateEnemy();
void updateBloodBar();
void createObstacleData();
void createObstacle();void putimagePNG2(int x, int y, IMAGE* picture);
void putimagePNG2(int x, int y, int winWidth, IMAGE* picture);
void putimagePNG(int picture_x, int picture_y, IMAGE* picture);
void HeroIndex();
void playSound(const char* name);void preLoadSound(const char* name) {char cmd[512];sprintf_s(cmd, sizeof(cmd), open %s alias %s-1, name, name);mciSendString(cmd, 0, 0, 0);sprintf_s(cmd, sizeof(cmd), open %s alias %s-2, name, name);mciSendString(cmd, 0, 0, 0);
}void drawBloodBar(int x, int y, int width, int height, int lineWidth, int boardColor, int emptyColor, int fillColor, float percent) {LINESTYLE lineStyle;getlinestyle(lineStyle);int lineColor getlinecolor();int fileColor getfillcolor();if (percent 0) {percent 0;}setlinecolor(BLUE);setlinestyle(PS_SOLID | PS_ENDCAP_ROUND, lineWidth);setfillcolor(emptyColor);fillrectangle(x, y, x width, y height);setlinestyle(PS_SOLID | PS_ENDCAP_FLAT, 0);setfillcolor(fillColor);setlinecolor(fillColor);if (percent 0) {fillrectangle(x 0.5 * lineWidth, y lineWidth * 0.5, x width * percent, y height - 0.5 * lineWidth);}setlinecolor(lineColor);setfillcolor(fillColor);setlinestyle(lineStyle);
}bool rectIntersect(int x01, int y01, int x02, int y02,int x11, int y11, int x12, int y12)
{int zx abs(x01 x02 - x11 - x12);int x abs(x01 - x02) abs(x11 - x12);int zy abs(y01 y02 - y11 - y12);int y abs(y01 - y02) abs(y11 - y12);return (zx x zy y);
}void playSound(const char* name) {static int index 1;char cmd[512];if (index 1) {sprintf_s(cmd, sizeof(cmd), play %s-1, name);mciSendString(cmd, 0, 0, 0);sprintf_s(cmd, sizeof(cmd), close %s-2, name);mciSendString(cmd, 0, 0, 0);sprintf_s(cmd, sizeof(cmd), open %s alias %s-2, name, name);mciSendString(cmd, 0, 0, 0);index;}else if (index 2) {sprintf_s(cmd, sizeof(cmd), play %s-2, name);mciSendString(cmd, 0, 0, 0);sprintf_s(cmd, sizeof(cmd), close %s-1, name);mciSendString(cmd, 0, 0, 0);sprintf_s(cmd, sizeof(cmd), open %s alias %s-1, name, name);mciSendString(cmd, 0, 0, 0);index 1;}
}void putimagePNG(int picture_x, int picture_y, IMAGE* picture) //x为载入图片的X坐标y为Y坐标
{DWORD* dst GetImageBuffer(); // GetImageBuffer()函数用于获取绘图设备的显存指针EASYX自带DWORD* draw GetImageBuffer();DWORD* src GetImageBuffer(picture); //获取picture的显存指针int picture_width picture-getwidth(); //获取picture的宽度EASYX自带int picture_height picture-getheight(); //获取picture的高度EASYX自带int graphWidth getwidth(); //获取绘图区的宽度EASYX自带int graphHeight getheight(); //获取绘图区的高度EASYX自带int dstX 0; //在显存里像素的角标// 实现透明贴图 公式 Cpαp*FP(1-αp)*BP 贝叶斯定理来进行点颜色的概率计算for (int iy 0; iy picture_height; iy){for (int ix 0; ix picture_width; ix){int srcX ix iy * picture_width; //在显存里像素的角标int sa ((src[srcX] 0xff000000) 24); //0xAArrggbb;AA是透明度int sr ((src[srcX] 0xff0000) 16); //获取RGB里的Rint sg ((src[srcX] 0xff00) 8); //Gint sb src[srcX] 0xff; //Bif (ix 0 ix graphWidth iy 0 iy graphHeight dstX graphWidth * graphHeight){dstX (ix picture_x) (iy picture_y) * graphWidth; //在显存里像素的角标int dr ((dst[dstX] 0xff0000) 16);int dg ((dst[dstX] 0xff00) 8);int db dst[dstX] 0xff;draw[dstX] ((sr * sa / 255 dr * (255 - sa) / 255) 16) //公式 Cpαp*FP(1-αp)*BP αpsa/255 , FPsr , BPdr| ((sg * sa / 255 dg * (255 - sa) / 255) 8) //αpsa/255 , FPsg , BPdg| (sb * sa / 255 db * (255 - sa) / 255); //αpsa/255 , FPsb , BPdb}}}
}// 适用于 y 0 以及x0的任何情况
void putimagePNG2(int x, int y, IMAGE* picture) {IMAGE imgTmp;if (y 0) {SetWorkingImage(picture);getimage(imgTmp, 0, -y,picture-getwidth(), picture-getheight() y);SetWorkingImage();y 0;picture imgTmp;}if (x 0) {SetWorkingImage(picture);getimage(imgTmp, -x, 0, picture-getwidth() x, picture-getheight());SetWorkingImage();x 0;picture imgTmp;}putimagePNG(x, y, picture);
}// 适用于 y 0 以及y0的任何情况
void putimagePNG2(int x, int y, int winWidth, IMAGE* picture) {IMAGE imgTmp;if (y 0) {SetWorkingImage(picture);getimage(imgTmp, 0, -y,picture-getwidth(), picture-getheight() y);SetWorkingImage();y 0;picture imgTmp;}if (x 0) {SetWorkingImage(picture);getimage(imgTmp, -x, 0, picture-getwidth() x, picture-getheight());SetWorkingImage();x 0;picture imgTmp;}else if (x winWidth) {return;}else if (x winWidth - picture-getwidth()) {SetWorkingImage(picture);getimage(imgTmp, 0, 0, winWidth - x, picture-getheight());SetWorkingImage();picture imgTmp;}putimagePNG(x, y, picture);
}void jump() {heroJump true;update true;
}void down() {update true;heroDown true;heroIndex 0;
}void heroupdown()
{// 实现跳跃if (heroJump) {if (heroY jumpHeightMax) {heroJumpOff 4;}heroY heroJumpOff;if (heroY 345 - imgHeros[0].getheight()) {heroJump false;heroJumpOff -4;}}else if (heroDown) {static int count 0;int delays[2] { 8, 30 };count;if (count delays[heroIndex]) {count 0;heroIndex;if (heroIndex 2) {heroIndex 0;heroDown false;}}}else { //不跳跃heroIndex (heroIndex 1) % 12;}
}void updateBloodBar() {drawBloodBar(10, 10, 200, 10, 2, BLUE, DARKGRAY, RED, heroBlood / 100.0);
}
void moveBg() {for (int i 0; i 3; i) {bgX[i] - bgSpeed[i];if (bgX[i] -WIN_WIDTH) {bgX[i] 0;}}
}void createObstacleData() {static int frameCount 0;static int enemyFre 50;frameCount;if (frameCount enemyFre) {frameCount 0;enemyFre 50 rand() % 50; // 50..99createObstacle();}// 更新所有障碍物的坐标for (int i 0; i OBSTACLE_COUNT; i) {if (obstacles[i].exist) {obstacles[i].x - obstacles[i].speed bgSpeed[2];if (obstacles[i].x -obstacleImgs[obstacles[i].type][0].getwidth() * 2) {obstacles[i].exist false;}int len obstacleImgs[obstacles[i].type].size();obstacles[i].imgIndex (obstacles[i].imgIndex 1) % len;}}
}
void checkHit()
{for (int i 0; i OBSTACLE_COUNT; i){if (obstacles[i].exist obstacles[i].hited false){int a1x, a1y, a2x, a2y;int off 20;if (!heroDown)//非下蹲 奔跑 跳跃{a1x heroX off;a1y heroY off;a2x heroX imgHeros[heroIndex].getwidth() - off;a2y heroY imgHeros[heroIndex].getheight();}else { //下蹲状态a1x heroX off;a1y 345 - imgHeroDown[heroIndex].getheight();a2x heroX imgHeroDown[heroIndex].getwidth() - off;a2y 345;}IMAGE img obstacleImgs[obstacles[i].type][obstacles[i].imgIndex];int b1x obstacles[i].x off;int b1y obstacles[i].y off;int b2x obstacles[i].x img.getwidth() - off;int b2y obstacles[i].y img.getheight() - 10;if (rectIntersect(a1x, a1y, a2x, a2y, b1x, b1y, b2x, b2y)) {heroBlood - obstacles[i].power;printf(血量剩余 %d\n, heroBlood);playSound(res/hit.mp3);obstacles[i].hited true;}}}}void checkOver() {if (heroBlood 0) {loadimage(0, res/over.png);FlushBatchDraw();mciSendString(stop res/bg.mp3, 0, 0, 0);system(pause);// 暂停之后充币复活或者直接开始下一局heroBlood 100;mciSendString(play res/bg.mp3, 0, 0, 0);}
}void createObstacle() {srand((unsigned)time(NULL));int i;for (i 0; i OBSTACLE_COUNT; i) {if (obstacles[i].exist false) {break;}}if (i OBSTACLE_COUNT) {return;}obstacles[i].exist true;obstacles[i].imgIndex 0;//obstacles[i].type (obstacle_type)(rand() % OBSTACLE_TYPE_COUNT);obstacles[i].type (obstacle_type)(rand() % 3);obstacles[i].x WIN_WIDTH;obstacles[i].y 345 5 - obstacleImgs[obstacles[i].type][0].getheight();if (lastObsIndex HOOK1 lastObsIndex HOOK4 obstacles[i].type LION obstacles[lastObsIndex].x (WIN_WIDTH - 500)) {obstacles[i].type TORTOISE;}lastObsIndex i;if (obstacles[i].type HOOK1) {obstacles[i].type (obstacle_type)((int)(obstacles[i].type) rand() % 4);}if (obstacles[i].type TORTOISE) {obstacles[i].speed 0;obstacles[i].power 5; //自己修改}else if (obstacles[i].type LION) {obstacles[i].speed 4;obstacles[i].power 20;}else if (obstacles[i].type HOOK1 obstacles[i].type HOOK4) {obstacles[i].speed 0;obstacles[i].power 20;obstacles[i].y 0;}}//渲染游戏背景
void updateBg()
{putimagePNG2(bgX[0], 0, imgBgs[0]);putimagePNG2(bgX[1], 119, imgBgs[1]);putimagePNG2(bgX[2], 330, imgBgs[2]);
}
//处理用户按键的输入
//void keyEvent() {
// char ch;
//
// if (_kbhit()) { //如果有按键按下_kbhit()返回 true
// ch _getch(); // _getch()不需要按下回车即可直接读取
// if (ch ) {
// jump();
// }
// }
//}// 处理用户按键的输入
void keyEvent() {char ch;if (_kbhit()) { //如果有按键按下_kbhit()返回 true ch _getch(); // _getch()不需要按下回车即可直接读取if (ch ) {jump();}else if (ch s) {down();}}
}void jump(bool heroJump)
{// 实现跳跃if (heroJump) {if (heroY jumpHeightMax) {heroJumpOff 4;}heroY heroJumpOff;if (heroY 345 - imgHeros[0].getheight()) {heroJump false;heroJumpOff -4;}}else { //不跳跃heroIndex (heroIndex 1) % 12;}update true;
}void updateEnemy() {for (int i 0; i OBSTACLE_COUNT; i) {if (obstacles[i].exist) {putimagePNG2(obstacles[i].x, obstacles[i].y, WIN_WIDTH,obstacleImgs[obstacles[i].type][obstacles[i].imgIndex]);}}
}
// 游戏的初始化
void init() {// 创建游戏窗口initgraph(WIN_WIDTH, WIN_HEIGHT);// 加载背景资源char name[64];for (int i 0; i 3; i) {// res/bg001.png res/bg002.png res/bg003.png sprintf(name, res/bg%03d.png, i 1);loadimage(imgBgs[i], name);bgX[i] 0;}// 加载Hero奔跑的图片帧素材for (int i 0; i 12; i) {// res/hero1.png ... res/hero12.pngsprintf(name, res/hero%d.png, i 1);loadimage(imgHeros[i], name);}// 设置玩家的初始位置heroX WIN_WIDTH * 0.5 - imgHeros[0].getwidth() * 0.5;heroY 345 - imgHeros[0].getheight();heroIndex 0;heroJump false;jumpHeightMax 345 - imgHeros[0].getheight() - 120;heroJumpOff -4;update true;IMAGE imgTort;loadimage(imgTort, res/t1.png);vectorIMAGE imgTortArray;imgTortArray.push_back(imgTort);obstacleImgs.push_back(imgTortArray);IMAGE imgLion;vectorIMAGE imgLionArray;for (int i 0; i 6; i) {sprintf(name, res/p%d.png, i 1);loadimage(imgLion, name);imgLionArray.push_back(imgLion);}obstacleImgs.push_back(imgLionArray);// 初始化障碍物池for (int i 0; i OBSTACLE_COUNT; i) {obstacles[i].exist false;}// 加载下蹲素材loadimage(imgHeroDown[0], res/d1.png);loadimage(imgHeroDown[1], res/d2.png);heroDown false;// 加载“柱子”障碍物IMAGE imgH;vectorIMAGE imgHookArray;for (int i 0; i 4; i) {sprintf_s(name, sizeof(name), res/h%d.png, i 1); //帧图片不够补帧loadimage(imgH, name, 63, 260, true);imgHookArray.push_back(imgH);obstacleImgs.push_back(imgHookArray);imgHookArray.pop_back();}heroBlood 100;// 预加载音效preLoadSound(res/hit.mp3);lastObsIndex -1;score 0;}void checkScore() {for (int i 0; i OBSTACLE_COUNT; i) {if (obstacles[i].exist obstacles[i].passed false obstacles[i].x obstacleImgs[obstacles[i].type][0].getwidth() heroX) {score;obstacles[i].passed true;printf(score: %d\n, score);}}
}void updateHero() {if (!heroDown) {putimagePNG2(heroX, heroY, imgHeros[heroIndex]);}else {int y 345 - imgHeroDown[heroIndex].getheight();putimagePNG2(heroX, y, imgHeroDown[heroIndex]);}}void HeroIndex()
{heroIndex (heroIndex 1) % 12;
}void checkWin() {if (score WIN_SCORE) {FlushBatchDraw();mciSendString(play res/win.mp3, 0, 0, 0);Sleep(2000);loadimage(0, res/win.png);FlushBatchDraw();mciSendString(stop res/bg.mp3, 0, 0, 0);system(pause);heroBlood 100;score 0;mciSendString(play res/bg.mp3 repeat, 0, 0, 0);}
}int getDelay() {static unsigned long long lastTime 0;unsigned long long currentTime GetTickCount();if (lastTime 0) {lastTime currentTime;return 0;}else {int ret currentTime - lastTime;lastTime currentTime;return ret;}
}int main(void) {int timer 0;init();// 显示初始画面loadimage(0, res/over.png);system(pause);while (1) {keyEvent();timer getDelay();//10if (timer 20) {timer 0;update true;}if (update){update false;BeginBatchDraw();updateBg();updateHero(); updateEnemy();updateBloodBar();checkWin();EndBatchDraw();moveBg();heroupdown();createObstacleData();checkHit();checkOver();checkScore();}}return 0;
}