天天酷跑-C语言搭建童年游戏(easyx)

游戏索引

游戏名称:天天酷跑



游戏介绍:

本游戏是在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;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/643617.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【linux】Debian挂起和休眠

一、挂起和休眠 在Debian桌面系统中&#xff0c;挂起和休眠是两种不同的状态&#xff0c;它们之间有一些区别。 挂起&#xff08;Suspend&#xff09;是将当前系统的状态保存到RAM&#xff08;内存&#xff09;中&#xff0c;然后关闭所有硬件设备&#xff0c;除了RAM之外。在…

如何用H5+CSS+JS写一个简单的招聘网站

大家好&#xff0c;我是猿码叔叔&#xff0c;一个 Java 语言开发者。应网友要求&#xff0c;写一个简单的招聘页面。由于技术原因&#xff0c;页面相对简单&#xff0c;朋友们可以选择性的阅读&#xff0c;如果对您有帮助&#xff0c;也可直接拿去使用&#xff0c;因为接下来除…

数据分析的理念、流程、方法、工具(下)

四、用户分群 1、用户分群 用户分群是精细化运营的基础要求&#xff0c;也是数据分析的最基础方式。对用户进行分群&#xff0c;能帮助我们了解每个细分群体用户的变化情况&#xff0c;进而了解用户的整体现状及发展趋势。同时&#xff0c;由于运营资源本身有限&#xff0c;不…

技术变革下职业危机

方向一&#xff1a;技术变革 1.人工智能&#xff08;AI&#xff09;&#xff1a;AI技术的快速发展正在改变各个行业。AI在医疗诊断、金融分析、客户服务以及物流管理等方面都有广泛应用&#xff0c;提高了效率和准确性。但同时也引发了一些道德和道德问题&#xff0c;比如隐私…

玩法与画面全面升级,艾尔莎H311-PRO和你玩转《如龙8:无尽财富》

作为经典的日系开放式世界游戏系列&#xff0c;《如龙》至今已经推出了有十多部作品&#xff0c;它凭借着经典的日式RPG玩法吸引了不少忠实粉丝。早在2022年9月的时候&#xff0c;世嘉就已经公布了最新的正统续作《如龙8》&#xff0c;而在经历了一年半的等待以后&#xff0c;我…

jvs-rules(规则引擎)1.23功能更新说明,新增SQL变量、数据源等

规则引擎更新功能 新增: 1、新增SQL变量&#xff1a; SQL变量通常指的是在执行SQL查询时使用的动态变量。这些变量允许在查询中注入或更改某些值&#xff0c;以便根据不同的条件或输入执行不同的查询。 1.1 新增自定义SQL语言进行数据查询&#xff1b; 用户可以使用自定义的…

强化学习12——策略梯度算法学习

Q-learning、DQN算法是基于价值的算法&#xff0c;通过学习值函数、根据值函数导出策略&#xff1b;而基于策略的算法&#xff0c;是直接显示地学习目标策略&#xff0c;策略梯度算法就是基于策略的算法。 策略梯度介绍 将策略描述为带有参数 θ \theta θ 的连续函数&#…

Pycharm运行提示(运行‘Python测试(00.py内)‘(u)

为什么有时候我在pycharm中运行代码会出现图片中的问题&#xff1f; 我们该如何改过来&#xff1f; 很简单 点击文件-设置 点击Python集成工具&#xff0c;在默认测试运行程序里修改为Unittest即可 再次运行代码就会显示正常的运行 你的pycharm可能是英文 如何英文变中文&…

鸿蒙APP的应用场景

鸿蒙APP可以用于多种场合和设备类型&#xff0c;这是鸿蒙系统的分布式能力和多终端适配的优势。以下是一些鸿蒙APP的应用场景&#xff0c;希望对大家有所帮助。北京木奇移动技术有限公司&#xff0c;专业的软件外包开发公司&#xff0c;欢迎交流合作。 1.智能手机和平板电脑&am…

开源:两个免费的年会抽奖项目

前言 年会抽奖项目平常基本不用&#xff0c;只有到年终才会排上用场。开发的时长也不会给太久&#xff0c;而且也只是自家公司内部使用的&#xff0c;所以不需要部署&#xff0c;数据库后端甚至都可以省略&#xff1b;然后我就找了个开源的 符合我要求的年会抽奖项目进行二次开…

CSS 图片遮罩学习小节

概念&#xff1a;-webkit-mask-image是一项用于制作镂空图形和图形遮罩效果的CSS样式属性。 -webkit-mask-image 的值既可以是渐变色也可以是图片地址。 -webkit-mask-image 的起源很早&#xff0c;但兼容性不好&#xff0c;因此用途并不广泛。 效果如下&#xff1a; 底图&…

Spring Security 6 学习-1

什么是 Spring Security Spring Security文档 Spring Security中文文档 Spring Security 是 Spring 家族中的安全型开发框架&#xff0c;主要解决三大方面问题&#xff1a;认证&#xff08;你是谁&#xff09;、授权&#xff08;你能干什么&#xff09;、常见攻击保护&#xff…

深度强化学习Task3:A2C、A3C算法

本篇博客是本人参加Datawhale组队学习第三次任务的笔记 【教程地址】 文章目录 Actor-Critic 算法提出的动机Q Actor-Critic 算法A2C 与 A3C 算法广义优势估计A3C实现建立Actor和Critic网络定义智能体定义环境训练利用JoyRL实现多进程 练习总结 Actor-Critic 算法提出的动机 蒙…

Tableau1 安装基础知识

参考内容&#xff1a; 戴师兄-戴你玩转数据分析菜菜菊花酱数据分析课程 1 安装注意事项 若下次打开发现软件损坏&#xff0c;可以重新安装&#xff1b;后期激活码可以去淘宝上购买&#xff08;选择1key两机&#xff09;&#xff1b;若买了1key1机的密钥&#xff0c;需要在两台…

深度学习记录--mini-batch gradient descent

batch vs mini-batch gradient descent batch&#xff1a;段&#xff0c;块 与传统的batch梯度下降不同&#xff0c;mini-batch gradient descent将数据分成多个子集&#xff0c;分别进行处理&#xff0c;在数据量非常巨大的情况下&#xff0c;这样处理可以及时进行梯度下降&…

力扣精选算法100题——在排序数组中查找元素的第一个和最后一个位置(二分查找专题)

目录 第一步&#xff1a;了解题意 第二步&#xff1a;算法原理 &#x1f6a9;查找区间左端点值 ❗处理细节 循环条件&#xff1a; 求中点 &#x1f6a9;查找区间右端点值 ❗处理细节 循环条件 求中点 &#x1f6a9;总结 第三步&#xff1a;代码实现 第四步:总结模…

OpenHarmony 鸿蒙使用指南——概述

简介 OpenHarmony采用多内核&#xff08;Linux内核或者LiteOS&#xff09;设计&#xff0c;支持系统在不同资源容量的设备部署。当相同的硬件部署不同内核时&#xff0c;如何能够让设备驱动程序在不同内核间平滑迁移&#xff0c;消除驱动代码移植适配和维护的负担&#xff0c;…

技术驱动宠物健康:宠物在线问诊系统的高效搭建手册

在数字化时代&#xff0c;技术正在催生出许多创新的医疗服务&#xff0c;而宠物在线问诊系统便是其中一项引领潮流的创举。本文将为你提供一份高效搭建宠物在线问诊系统的手册&#xff0c;通过技术代码示例&#xff0c;让你轻松打造一套技术驱动的宠物健康管理系统。 1. 架构…

常用芯片学习——HC244芯片

HC573 三态输出八路缓冲器|线路驱动器 使用说明 SNx4HC244 八路缓冲器和线路驱动器专门设计用于提高三态存储器地址驱动器、时钟驱动器以及总线导向接收器和发送器的性能和密度。SNx4HC244 器件配备两个具有独立输出使能 (OE) 输入的 4 位缓冲器和驱动器。当 OE 为低电平时&a…

【java问题解决】-word转pdf踩坑

问题情境&#xff1a; 项目中采用word转pdf&#xff0c;最开始使用的pdf相关的apache的pdfbox和itextpdf&#xff0c;后面发现对于有图片背景的word转pdf的情景&#xff0c;word中的背景图会直接占用位置&#xff0c;导致正文不会正确落在背景图上。 解决方案&#xff1a; 采…