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

2024-01-22 08:04

本文主要是介绍天天酷跑-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;
}

这篇关于天天酷跑-C语言搭建童年游戏(easyx)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/632352

相关文章

科研绘图系列:R语言扩展物种堆积图(Extended Stacked Barplot)

介绍 R语言的扩展物种堆积图是一种数据可视化工具,它不仅展示了物种的堆积结果,还整合了不同样本分组之间的差异性分析结果。这种图形表示方法能够直观地比较不同物种在各个分组中的显著性差异,为研究者提供了一种有效的数据解读方式。 加载R包 knitr::opts_chunk$set(warning = F, message = F)library(tidyverse)library(phyl

搭建Kafka+zookeeper集群调度

前言 硬件环境 172.18.0.5        kafkazk1        Kafka+zookeeper                Kafka Broker集群 172.18.0.6        kafkazk2        Kafka+zookeeper                Kafka Broker集群 172.18.0.7        kafkazk3

透彻!驯服大型语言模型(LLMs)的五种方法,及具体方法选择思路

引言 随着时间的发展,大型语言模型不再停留在演示阶段而是逐步面向生产系统的应用,随着人们期望的不断增加,目标也发生了巨大的变化。在短短的几个月的时间里,人们对大模型的认识已经从对其zero-shot能力感到惊讶,转变为考虑改进模型质量、提高模型可用性。 「大语言模型(LLMs)其实就是利用高容量的模型架构(例如Transformer)对海量的、多种多样的数据分布进行建模得到,它包含了大量的先验

【IPV6从入门到起飞】5-1 IPV6+Home Assistant(搭建基本环境)

【IPV6从入门到起飞】5-1 IPV6+Home Assistant #搭建基本环境 1 背景2 docker下载 hass3 创建容器4 浏览器访问 hass5 手机APP远程访问hass6 更多玩法 1 背景 既然电脑可以IPV6入站,手机流量可以访问IPV6网络的服务,为什么不在电脑搭建Home Assistant(hass),来控制你的设备呢?@智能家居 @万物互联

国产游戏崛起:技术革新与文化自信的双重推动

近年来,国产游戏行业发展迅猛,技术水平和作品质量均得到了显著提升。特别是以《黑神话:悟空》为代表的一系列优秀作品,成功打破了过去中国游戏市场以手游和网游为主的局限,向全球玩家展示了中国在单机游戏领域的实力与潜力。随着中国开发者在画面渲染、物理引擎、AI 技术和服务器架构等方面取得了显著进展,国产游戏正逐步赢得国际市场的认可。然而,面对全球游戏行业的激烈竞争,国产游戏技术依然面临诸多挑战,未来的

pico2 开发环境搭建-基于ubuntu

pico2 开发环境搭建-基于ubuntu 安装编译工具链下载sdk 和example编译example 安装编译工具链 sudo apt install cmake gcc-arm-none-eabi libnewlib-arm-none-eabi libstdc++-arm-none-eabi-newlib 注意cmake的版本,需要在3.17 以上 下载sdk 和ex

C语言 | Leetcode C语言题解之第393题UTF-8编码验证

题目: 题解: static const int MASK1 = 1 << 7;static const int MASK2 = (1 << 7) + (1 << 6);bool isValid(int num) {return (num & MASK2) == MASK1;}int getBytes(int num) {if ((num & MASK1) == 0) {return

MiniGPT-3D, 首个高效的3D点云大语言模型,仅需一张RTX3090显卡,训练一天时间,已开源

项目主页:https://tangyuan96.github.io/minigpt_3d_project_page/ 代码:https://github.com/TangYuan96/MiniGPT-3D 论文:https://arxiv.org/pdf/2405.01413 MiniGPT-3D在多个任务上取得了SoTA,被ACM MM2024接收,只拥有47.8M的可训练参数,在一张RTX

如何确定 Go 语言中 HTTP 连接池的最佳参数?

确定 Go 语言中 HTTP 连接池的最佳参数可以通过以下几种方式: 一、分析应用场景和需求 并发请求量: 确定应用程序在特定时间段内可能同时发起的 HTTP 请求数量。如果并发请求量很高,需要设置较大的连接池参数以满足需求。例如,对于一个高并发的 Web 服务,可能同时有数百个请求在处理,此时需要较大的连接池大小。可以通过压力测试工具模拟高并发场景,观察系统在不同并发请求下的性能表现,从而

C语言:柔性数组

数组定义 柔性数组 err int arr[0] = {0}; // ERROR 柔性数组 // 常见struct Test{int len;char arr[1024];} // 柔性数组struct Test{int len;char arr[0];}struct Test *t;t = malloc(sizeof(Test) + 11);strcpy(t->arr,