游戏索引
游戏名称:天天酷跑
游戏介绍:
本游戏是在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里的R int sg = ((src[srcX] & 0xff00) >> 8); //G int sb = src[srcX] & 0xff; //B if (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尾插到空数组,若多个图片可利用循环添加见LION 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 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; }