游戏索引
游戏名称:天天酷跑
游戏介绍:
本游戏是在B站博主<程序员Rock>的视频指导下完成
想学的更详细的小伙伴可以移步到<程序员Rock>视频
【程序员Rock】C语言项目:手写天天酷跑丨大一课程设计首选项目,手把手带你用C语言游戏开发
游戏效果展示#
天天酷跑
游戏模块:
<1>安装easyx图形库
<2>创建项目
<3>导入素材
<4>创建游戏开始界面
<5>循环滚动背景实现
<6>创建人物实现奔跑<7>实现人物的跳跃和下蹲
<8>创建障碍物
<9>实现人物的血条
<10>人物和障碍物的碰撞
<11>实现游戏的积分
<12>游戏输赢的判定
目录
游戏索引
写代码前的准备工作
搭建项目环境easyx:
导入游戏素材 :
修改项目属性:
导入我们的辅助项目:
tools.h
tools.cpp
导入操作#
实现游戏开始界面
游戏的定义与声明
游戏的初始化
实现游戏背景展示
图片背景的显示
图片移动的实现
实现用户的按键操作
实现人物的展示
编辑
奔跑人物的显示
人物的跳跃和下蹲的实现
渲染障碍物
显示障碍物
更新障碍物的位置
随机生成小乌龟
人物与障碍物的碰撞检测
人物血量的显示
游戏分数的显示
游戏输赢的判定
游戏赢的判定
游戏输的判定
游戏主函数
全部代码的实现
素材已上传至百度网盘:
百度网盘 请输入提取码提取码:ABCD
写代码前的准备工作
搭建项目环境easyx:
要想在我们的窗口实现图片交互
应该给编译器安装 easyx 图形库
这边我用图片展示详细的安装操作
(1)我们先在网页找到官网
(2)然后点击下载
(3)将 easyx 安装到目标编译器
(4)出现安装成功就代表可以使用了
接下来我们就可以写放心写代码啦!!!
导入游戏素材 :
在当前项目的目录下创建文件夹,并把解压好的文件 res 拷贝进去
修改项目属性:
<1>点击项目找到项目属性
<2>将字符集改成多字符集
这里图片操作的时候需要
<3>将编译器对SDL的检查关掉
导入我们的辅助项目:
tools.h
#pragma once #include <graphics.h>//返回距离上一次调用间隔的时间(单位:ms),第一次调用时返回0 int getDelay(); void putimagePNG(int picture_x, int picture_y, IMAGE* picture);// 适用于 y <0 以及y>0的任何情况 void putimagePNG2(int x, int y, IMAGE* picture); void putimagePNG2(int x, int y, int winWidth, IMAGE* picture);// 判断两个矩形是否相交 bool rectIntersect(int a1X, int a1Y, int a2X, int a2Y,int b1X, int b1Y, int b2X, int b2Y);void preLoadSound(const char* name); void playSound(const char* name);void drawBloodBar(int x, int y, int width, int height, int lineWidth, int boardColor, int emptyColor, int fillColor, float percent);
tools.cpp
#include <stdio.h> #include <Windows.h> #include "tools.h"#include <mmsystem.h>//播放音乐 #pragma comment(lib, "winmm.lib")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;} }// 载入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 ; αp=sa/255 , FP=sr , BP=dr| ((sg * sa / 255 + dg * (255 - sa) / 255) << 8) //αp=sa/255 , FP=sg , BP=dg| (sb * sa / 255 + db * (255 - sa) / 255); //αp=sa/255 , FP=sb , BP=db}}} }// 适用于 y <0 以及x<0的任何情况 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 以及y>0的任何情况 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); }//设A[x01,y01,x02,y02] B[x11,y11,x12,y12]. 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 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 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 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); }
导入操作#
<1>点击项目添加现有项
<2>选定我们要添加的辅助项目选择添加就好啦
实现游戏开始界面
按钮放置的位置我们可以通过 画图软件 或者 微信截图 来获取
void startUI() {// 添加背景音乐mciSendString("play res/bg.mp3 repeat", 0, 0, 0);IMAGE imgMenu, imgMenu1;int flag = 0;loadimage(&imgMenu, "res/Menu1.png");loadimage(&imgMenu1, "res/menu.png");while (1) {BeginBatchDraw();putimage(0, 0, &imgMenu);putimagePNG(474, 150, &imgMenu1);ExMessage msg;if (peekmessage(&msg)) {//判断是否有左键按下if (msg.message == WM_LBUTTONDOWN &&msg.x > 474 && msg.x < 720 && msg.y>150 && msg.y < 170) {//按键点击的范围flag = 1;}}//判断鼠标按下后有没有松开else if (msg.message == WM_LBUTTONUP && flag == 1) {mciSendString("close res/bg.mp3", 0, 0, 0);EndBatchDraw();return;}EndBatchDraw();} }
游戏的定义与声明
//这里采用宏定义为的是更好的维护 #define WIN_WIDTH 1012 //窗口的宽度 #define WIN_HEIGHT 396 //窗口的高度 #define OBSTACLE_COUNT 10 //障碍物数量 #define WIN_SCORE 20 //获胜的分数IMAGE imaBgs[3]; //图片类型的指针 int bgX[3]; //背景图片 int bgspeed[3] = { 1,2,4 }; //背景移动的速度进行控制IMAGE bgHeros[12]; //人物帧数-图片张数 int HeroX; //人物坐标 int HeroY; int HeroIndex; //玩家奔跑的图片帧序号//判断人物的跳跃和下蹲 bool heroJump; bool herodown;int jumpHeightMax; int jumpHeightOff;//跳跃偏移量int update; //表示是否需要马上刷新画面int heroBlood; int score;//枚举障碍物,计算障碍物的种类 typedef enum {TORTOISE,//乌龟 LION, //狮子HOOK1, //挡板HOOK2,HOOK3,HOOK4,OBSTACLE_TYPE_COUNT //直接表示障碍物的个数 }obstacle_type; obstacle_type type;vector<vector<IMAGE>> obstacleImags; //动态二维数组存放各个障碍物的图片typedef struct obstacle {obstacle_type type; //障碍物类型int imaIndex; //当前显示图片的序号int x, y; //障碍物的坐标int speed; //障碍物速度int power; //杀伤力bool exist; //存在检测bool hited; //碰撞检测bool passed; //通过检测 } obstacle_t;obstacle_t obstacles[OBSTACLE_COUNT];int lastObsIndex;IMAGE imgHeroDown[2]; IMAGE imgSZ[10];
游戏的初始化
void init() {//创建游戏界面initgraph(WIN_WIDTH, WIN_HEIGHT);//循环来读取用数组来接收char name[64];for (int i = 0; i < 3; i++) {sprintf(name, "res/bg%03d.png", i + 1);loadimage(&imaBgs[i], name);//加载背景资源 bgX[i] = 0;}//加载人物奔跑的图片帧数for (int i = 0; i < 12; i++) {sprintf(name, "res/hero%d.png", i + 1);loadimage(&bgHeros[i], name);}//设置人物奔跑的位置HeroX = WIN_WIDTH * 0.5 - bgHeros[0].getwidth() * 0.5;HeroY = 345 - bgHeros[0].getheight();HeroIndex = 0;heroJump = false;jumpHeightMax = 345 - bgHeros[0].getheight() - 120;//跳跃的最大高度jumpHeightOff = -4; update = true;//加载小乌龟IMAGE imgTort;loadimage(&imgTort, "res/t1.png"); //加载乌龟图片,这里只用了一张vector<IMAGE>imgTortArray; //定义乌龟障碍图片空数组imgTortArray.push_back(imgTort); //将imgTort尾插到空数组,若多个图片可利用循环添加见LIONobstacleImags.push_back(imgTortArray);//将乌龟图片数组尾插到上面的二维数组中//加载小狮子IMAGE imaLion;vector<IMAGE> imaLionArray;for (int i = 0; i < 6; i++) {sprintf(name, "res/p%d.png", i + 1);loadimage(&imaLion, name);imaLionArray.push_back(imaLion);}obstacleImags.push_back(imaLionArray);//初始化障碍物池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;for (int i = 0; i < 4; i++) {vector<IMAGE> imgHookArray;sprintf(name, "res/sz/h%d.png", i + 1);loadimage(&imgH, name, 70, 260, true);imgHookArray.push_back(imgH);obstacleImags.push_back(imgHookArray);}//血量heroBlood = 100;//预加载音效preLoadSound("res/hit.mp3");lastObsIndex = -1;//分数初始化score = 0;//加载数字图片for (int i = 0; i < 10; i++) {sprintf(name, "res/sz/%d.png", i);loadimage(&imgSZ[i], name);} }
实现游戏背景展示
图片背景的显示
void updateBg() {putimagePNG2(bgX[0], 0, &imaBgs[0]);putimagePNG2(bgX[1], 119, &imaBgs[1]);putimagePNG2(bgX[2], 330, &imaBgs[2]); }
图片移动的实现
void fly() {for (int i = 0; i < 3; i++) {bgX[i] -= bgspeed[i]; //调整背景移速if (bgX[i] < -WIN_WIDTH) {bgX[i] = 0;}} }
实现用户的按键操作
void keyEvent() {char ch;if (_kbhit()) //如果有按键按下kbhit返回true{ ch = _getch(); //getch()不需要按空格就可以直接读取if (ch == 'w'||ch == 'W') {jump(); }else if (ch == 's' || ch == 'S') {down();}} }
实现人物的展示
奔跑人物的显示
void updateHero() {if (!herodown) {putimagePNG2(HeroX, HeroY, &bgHeros[HeroIndex]);//显示奔跑人物}else {int y = 345 - imgHeroDown[HeroIndex].getheight();putimagePNG2(HeroX, y, &imgHeroDown[HeroIndex]);//显示下蹲人物} }
人物的跳跃和下蹲的实现
void jump()//跳跃分装函数 {heroJump = true; //启动跳跃功能update = true; //若启动跳跃开关则立马刷新启动功能 }void down()//下蹲分装函数 {herodown = true;update = true;HeroIndex = 0; }void fly() {//实现跳跃if (heroJump) {if (HeroY < jumpHeightMax) {jumpHeightOff = 4; }HeroY += jumpHeightOff;if (HeroY > 345 - bgHeros[0].getheight()) {heroJump = false; jumpHeightOff = -4; }}//实现下蹲else if (herodown) {static int count = 0;count++;int delays[2] = { 8,30 };if (count >= delays[HeroIndex]) {count = 0;HeroIndex++;if (HeroIndex == 2) {HeroIndex = 0;herodown = false;}}}else {HeroIndex = (HeroIndex + 1) % 12;//跳跃时腿不动}
渲染障碍物
显示障碍物
void updateEnemy() {//渲染障碍物for (int i = 0; i < OBSTACLE_COUNT; i++){if (obstacles[i].exist) {putimagePNG2(obstacles[i].x, obstacles[i].y, WIN_WIDTH, &obstacleImags[obstacles[i].type][obstacles[i].imaIndex]);}} }
更新障碍物的位置
// 更新障碍物的坐标 for (int i = 0; i < OBSTACLE_COUNT; i++) {if (obstacles[i].exist) {obstacles[i].x -= obstacles[i].speed + bgspeed[2];if (obstacles[i].x < -obstacleImags[obstacles[i].type][0].getwidth() * 2) {obstacles[i].exist = false;}int len = obstacleImags[obstacles[i].type].size(); obstacles[i].imaIndex = (obstacles[i].imaIndex + 1) % len;} }
随机生成小乌龟
//随机生成小乌龟static int frameCount = 0; //静态出函数不会销毁static int torToiseFre = 50;frameCount++;if (frameCount > torToiseFre) {//帧数够计数器,就生成小乌龟frameCount = 0; torToiseFre = 50 + rand() % 60;creatObstacle();}
人物与障碍物的碰撞检测
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 = 30; if (!herodown) { //非下蹲状态a1x = HeroX + off;a1y = HeroY + off;a2x = HeroX + bgHeros[HeroIndex].getwidth() - off;a2y = HeroY + bgHeros[HeroIndex].getheight();}else{a1x = HeroX + off;a1y = 345 - imgHeroDown[HeroIndex].getheight();a2x = HeroX + imgHeroDown[HeroIndex].getwidth() - off;a2y = 345;}//障碍物的区域IMAGE img = obstacleImags[obstacles[i].type][obstacles[i].imaIndex];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() - off;if (rectIntersect(a1x, a1y, a2x, a2y, b1x, b1y, b2x, b2y)) {heroBlood -= obstacles[i].power;playSound("res/hit.mp3");obstacles[i].hited = true;}}} }
人物血量的显示
void updateBloodBar() {drawBloodBar(10, 10, 200, 10, 2, BLUE, DARKGRAY, RED, heroBlood / 100.0); }
游戏分数的显示
void checkScore() {//每躲避一个障碍物就加一分for (int i = 0; i < OBSTACLE_COUNT; i++) {if (obstacles[i].exist &&obstacles[i].passed == false &&obstacles[i].hited == false &&obstacles[i].x + obstacleImags[obstacles[i].type][0].getwidth() < HeroX){score++;obstacles[i].passed = true;}} }void updateScore() {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;} }
游戏输赢的判定
游戏赢的判定
void checkWin() {if (score >= WIN_SCORE){FlushBatchDraw();mciSendString("play res/win.mp3", 0, 0, 0);Sleep(2000);loadimage(0, "res/Menu1.png");FlushBatchDraw(); mciSendString("stop Music.mp3", 0, 0, 0);system("pause");mciSendString("play Music.mp3 repeat", 0, 0, 0);heroBlood = 100;score = 0;} }
游戏输的判定
void checkOver() {if (heroBlood <= 0){loadimage(0, "res/Maclk.png");FlushBatchDraw();mciSendString("stop res/Maclk.mp3", 0, 0, 0);system("pause");//暂停之后,若选择直接开始下一局heroBlood = 100;score = 0;mciSendString("play res/Maclk.mp3 repeat", 0, 0, 0);} }
游戏主函数
双缓冲绘图:
BeginBatchDraw() - 开始双缓冲
EndBatchDraw() - 结束双缓冲
双缓冲区:打印一个的同时显示另一个,不断重复这个过程,避免了屏幕闪耀问题
int main(void) {init(); startUI();mciSendString("play Music.mp3 repeat", 0, 0, 0);int timer = 0;while (1) {keyEvent(); //按键接收timer += getDelay();if (timer > 30) {timer = 0;update = true; //30次刷新一次,帧休眠,不然速度太快}if (update) {update = false; BeginBatchDraw();updateBg(); //渲染游戏背景updateHero(); //渲染人物图片updateEnemy(); //渲染障碍物updateBloodBar();updateScore(); //渲染分数图片checkWin(); //检查游戏是否胜利EndBatchDraw();checkOver(); //检查游戏是否结束checkScore(); //计算得分fly(); //实现人物跳跃,下蹲,障碍物的移动效果}}system("pause");return 0; }
全部代码的实现
#include<stdio.h> #include<graphics.h> #include"tools.h" #include<conio.h> #include<vector> using namespace std;#define WIN_WIDTH 1012 #define WIN_HEIGHT 396 #define OBSTACLE_COUNT 10 #define WIN_SCORE 20 IMAGE imaBgs[3]; int bgX[3]; int bgspeed[3] = { 1,2,4 }; IMAGE bgHeros[12]; int HeroX; int HeroY; int HeroIndex; bool heroJump; bool herodown;int jumpHeightMax; int jumpHeightOff;int update; int heroBlood; int score;typedef enum {TORTOISE,LION, HOOK1, HOOK2,HOOK3,HOOK4,OBSTACLE_TYPE_COUNT }obstacle_type; obstacle_type type;vector<vector<IMAGE>> obstacleImags; typedef struct obstacle {obstacle_type type; int imaIndex; int x, y; int speed; int power; bool exist; bool hited; bool passed; } obstacle_t;obstacle_t obstacles[OBSTACLE_COUNT];int lastObsIndex;IMAGE imgHeroDown[2]; IMAGE imgSZ[10];void init() {initgraph(WIN_WIDTH, WIN_HEIGHT);char name[64];for (int i = 0; i < 3; i++) {sprintf(name, "res/bg%03d.png", i + 1);loadimage(&imaBgs[i], name);bgX[i] = 0;}for (int i = 0; i < 12; i++) {sprintf(name, "res/hero%d.png", i + 1);loadimage(&bgHeros[i], name);}HeroX = WIN_WIDTH * 0.5 - bgHeros[0].getwidth() * 0.5;HeroY = 345 - bgHeros[0].getheight();HeroIndex = 0;heroJump = false;jumpHeightMax = 345 - bgHeros[0].getheight() - 120;jumpHeightOff = -4; update = true;IMAGE imgTort;loadimage(&imgTort, "res/t1.png"); vector<IMAGE>imgTortArray; imgTortArray.push_back(imgTort); obstacleImags.push_back(imgTortArray);IMAGE imaLion;vector<IMAGE> imaLionArray;for (int i = 0; i < 6; i++) {sprintf(name, "res/p%d.png", i + 1);loadimage(&imaLion, name);imaLionArray.push_back(imaLion);}obstacleImags.push_back(imaLionArray);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;for (int i = 0; i < 4; i++) {vector<IMAGE> imgHookArray;sprintf(name, "res/sz/h%d.png", i + 1);loadimage(&imgH, name, 70, 260, true);imgHookArray.push_back(imgH);obstacleImags.push_back(imgHookArray);}heroBlood = 100;preLoadSound("res/hit.mp3");lastObsIndex = -1;score = 0;for (int i = 0; i < 10; i++) {sprintf(name, "res/sz/%d.png", i);loadimage(&imgSZ[i], name);} }void creatObstacle() {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].hited = false;obstacles[i].imaIndex = 0;obstacles[i].type = (obstacle_type)(rand() % 3);if (lastObsIndex >= 0 &&obstacles[lastObsIndex].type >= HOOK1 &&obstacles[lastObsIndex].type <= 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);}obstacles[i].x = WIN_WIDTH; obstacles[i].y = 350 - obstacleImags[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;}else if (obstacles[i].type >= HOOK1 && obstacles[i].type <= HOOK4) {obstacles[i].speed = 0;obstacles[i].power = 20;obstacles[i].y = 0; }obstacles[i].passed == false; }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 = 30; if (!herodown) { a1x = HeroX + off;a1y = HeroY + off;a2x = HeroX + bgHeros[HeroIndex].getwidth() - off;a2y = HeroY + bgHeros[HeroIndex].getheight();}else{a1x = HeroX + off;a1y = 345 - imgHeroDown[HeroIndex].getheight();a2x = HeroX + imgHeroDown[HeroIndex].getwidth() - off;a2y = 345;}IMAGE img = obstacleImags[obstacles[i].type][obstacles[i].imaIndex];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() - off;if (rectIntersect(a1x, a1y, a2x, a2y, b1x, b1y, b2x, b2y)) {heroBlood -= obstacles[i].power;playSound("res/hit.mp3");obstacles[i].hited = true;}}} }void fly() {for (int i = 0; i < 3; i++) {bgX[i] -= bgspeed[i]; if (bgX[i] < -WIN_WIDTH) {bgX[i] = 0;}}if (heroJump) {if (HeroY < jumpHeightMax) {jumpHeightOff = 4; }HeroY += jumpHeightOff;if (HeroY > 345 - bgHeros[0].getheight()) {heroJump = false; jumpHeightOff = -4; }}else if (herodown) {static int count = 0;count++;int delays[2] = { 8,30 };if (count >= delays[HeroIndex]) {count = 0;HeroIndex++;if (HeroIndex == 2) {HeroIndex = 0;herodown = false;}}}else {HeroIndex = (HeroIndex + 1) % 12;}static int frameCount = 0; static int torToiseFre = 50;frameCount++;if (frameCount > torToiseFre) {frameCount = 0; torToiseFre = 50 + rand() % 60;creatObstacle();}for (int i = 0; i < OBSTACLE_COUNT; i++) {if (obstacles[i].exist) {obstacles[i].x -= obstacles[i].speed + bgspeed[2];if (obstacles[i].x < -obstacleImags[obstacles[i].type][0].getwidth() * 2) {obstacles[i].exist = false;}int len = obstacleImags[obstacles[i].type].size(); obstacles[i].imaIndex = (obstacles[i].imaIndex + 1) % len;}}checkHit(); }void updateBg() {putimagePNG2(bgX[0], 0, &imaBgs[0]);putimagePNG2(bgX[1], 119, &imaBgs[1]);putimagePNG2(bgX[2], 330, &imaBgs[2]); }void jump() {heroJump = true; update = true; }void down() {herodown = true;update = true;HeroIndex = 0; }void keyEvent() {char ch;if (_kbhit()) { ch = _getch(); if (ch == 'w'||ch == 'W') {jump(); }else if (ch == 's' || ch == 'S') {down();}} }void updateEnemy() {for (int i = 0; i < OBSTACLE_COUNT; i++){if (obstacles[i].exist) {putimagePNG2(obstacles[i].x, obstacles[i].y, WIN_WIDTH, &obstacleImags[obstacles[i].type][obstacles[i].imaIndex]);}} }void updateHero() {if (!herodown) {putimagePNG2(HeroX, HeroY, &bgHeros[HeroIndex]);}else {int y = 345 - imgHeroDown[HeroIndex].getheight();putimagePNG2(HeroX, y, &imgHeroDown[HeroIndex]);} }void updateBloodBar() {drawBloodBar(10, 10, 200, 10, 2, BLUE, DARKGRAY, RED, heroBlood / 100.0); }void checkOver() {if (heroBlood <= 0){loadimage(0, "res/Maclk.png");FlushBatchDraw();mciSendString("stop res/Maclk.mp3", 0, 0, 0);system("pause");heroBlood = 100;score = 0;mciSendString("play res/Maclk.mp3 repeat", 0, 0, 0);} }void checkScore() {for (int i = 0; i < OBSTACLE_COUNT; i++) {if (obstacles[i].exist &&obstacles[i].passed == false &&obstacles[i].hited == false &&obstacles[i].x + obstacleImags[obstacles[i].type][0].getwidth() < HeroX){score++;obstacles[i].passed = true;}} }void updateScore() {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;} }void checkWin() {if (score >= WIN_SCORE){FlushBatchDraw();mciSendString("play res/win.mp3", 0, 0, 0);Sleep(2000);loadimage(0, "res/Menu1.png");FlushBatchDraw(); mciSendString("stop Music.mp3", 0, 0, 0);system("pause");mciSendString("play Music.mp3 repeat", 0, 0, 0);heroBlood = 100;score = 0;} }void startUI() {mciSendString("play res/bg.mp3 repeat", 0, 0, 0);IMAGE imgMenu, imgMenu1;int flag = 0;loadimage(&imgMenu, "res/Menu1.png");loadimage(&imgMenu1, "res/menu.png");while (1) {BeginBatchDraw();putimage(0, 0, &imgMenu);putimagePNG(474, 150, &imgMenu1);ExMessage msg;if (peekmessage(&msg)) {if (msg.message == WM_LBUTTONDOWN &&msg.x > 474 && msg.x < 720 && msg.y>150 && msg.y < 170) {flag = 1;}}else if (msg.message == WM_LBUTTONUP && flag == 1) {mciSendString("close res/bg.mp3", 0, 0, 0);EndBatchDraw();return;}EndBatchDraw();} }int main(void) {init(); startUI();mciSendString("play Music.mp3 repeat", 0, 0, 0);int timer = 0;while (1) {keyEvent();timer += getDelay();if (timer > 30) {timer = 0;update = true; }if (update) {update = false; BeginBatchDraw();updateBg(); updateHero();updateEnemy();updateBloodBar();updateScore();checkWin();EndBatchDraw();checkOver();checkScore();fly();}}system("pause");return 0; }