1.头文件、全局变量和结构体

a.玩家结构体

b.枚举玩家三种状态:奔跑、跳跃、滑行

c.障碍物结构体

d.障碍物结点

e.枚举出障碍物类型

#include<stdio.h>
#include<easyx.h>
#include<conio.h>
#include<assert.h>
#include<vector>
#include"tools.h"#pragma comment(lib,"Winmm.lib")using namespace std;
#define WIN_WIDTH 1012
#define WIN_HEIGHT 396
#define OBSTACLE_COUNT 10IMAGE img_bk[3];
IMAGE people_run[12];//人物跑步图片
IMAGE people_leap[12];//人物跑步图片
IMAGE people_slide[2];//人物滑行int bk_x[3];//背景坐标
int bk_y;
int bk_speed[3] = { 1,4,8 };//背景运动速度
int obst_count;//增加障碍物时计数
bool update;//是否立即刷新
bool switch_kb;//是否需要打开按键开关
int scored;//得分//枚举人物状态,奔跑,跳跃,滑行
enum PEOPLE_STATE
{run,leap,slide
};
//人物结构体
struct People
{int x;int y;int frame_run;//跑步时帧int motion_state;//人物运动状态int leap_height;//跳跃高度int frame_leap;//人物跳跃帧int jump_offset;//人物跳跃偏移量int frame_slide;//人物滑行帧int slide_distance;//人物滑行距离int exist;
}player;
//障碍物结点
struct Node
{struct Obstacle* obstacle_t;struct Node* next;
};
//障碍物类型枚举
enum OBSTACLE_TYPE
{tortoise,lion,fire,hock1,hock2,hock3,hock4,obstacle_type_count
};//障碍物结构体
struct Obstacle
{OBSTACLE_TYPE type;//障碍物类型int x;//坐标int y;int frame_index;//图片帧bool exist;//判断是否存在int speed;//运动速度
};vector<vector<IMAGE>>obstacleImgs;//用C++的动态数组void LoadObstImg();
struct Obstacle* InitOb();
void PrintObImg(struct Obstacle* p_ob);
void MoveOb(struct Obstacle* p_ob);
struct Node* CreateList();
struct Node* CreateNode(Obstacle* p_ob);
void InsertNode(struct Node* p_head, struct Obstacle* p_ob);
void PrintList(struct Node* p_head);
void UpdateOb();
bool CheckCollision(struct Obstacle* p_ob);struct Node* list = NULL;

2.制作背景和玩家

a.加载资源和数据初始化

b.背景绘制以及运动

c.玩家三种状态绘制与运动

d.键盘响应

e.判断玩家与障碍物碰撞

//加载图片
void LoadImg()
{//加载背景char bk_path[20] = {0};//背景图片路径for (int i = 0; i < 3; i++){sprintf(bk_path, "resource/bg%03d.png", i + 1);loadimage(&img_bk[i], bk_path);}//加载背景音乐mciSendString("open resource/bg.mp3 alias bgm", NULL, 0, NULL);mciSendString("play bgm repeat", NULL, 0, NULL);//加载人物char people_path1[20] = { 0 };//人物奔跑图片路径for (int i = 0; i < 12; i++){sprintf(people_path1, "resource/hero%d.png", i + 1);loadimage(&people_run[i], people_path1);}char people_path2[20] = { 0 };//人物跳跃图片路径for (int i = 0; i < 12; i++){sprintf(people_path1, "resource/g%02d.png", i + 1);loadimage(&people_leap[i], people_path1);}char people_path3[20] = { 0 };//人物滑行图片路径for (int i = 0; i < 2; i++){sprintf(people_path3, "resource/d%d.png", i + 1);loadimage(&people_slide[i], people_path3);}LoadObstImg();
}//初始化数据
void InitData()
{//加载窗口initgraph(WIN_WIDTH, WIN_HEIGHT,1);//背景X坐标初始为0bk_x[3] = { 0 };update = false;switch_kb = true;player.x = WIN_WIDTH*0.5 - people_run[0].getwidth()*0.5;player.y = 360 - people_run[0].getheight();player.frame_run = 0;player.motion_state = run;player.frame_leap = 0;player.leap_height = 100;player.jump_offset = -10;player.frame_slide = 0;player.slide_distance = 0;player.exist = true;scored = 0;list = CreateList();//将头结点地址赋予listfor (int i = 0; i < OBSTACLE_COUNT; i++){InsertNode(list, InitOb());}
}//打印图片
void PrintdImg()
{//打印背景图片putimagePNG2(bk_x[0], 0, &img_bk[0]);putimagePNG2(bk_x[1], 119, &img_bk[1]);putimagePNG2(bk_x[2], 330, &img_bk[2]);//打印人物奔跑图片if (run == player.motion_state){putimagePNG2(player.x, player.y, &people_run[player.frame_run]);//人物奔跑帧改变player.frame_run = (player.frame_run + 1) % 12;}//打印人物跳跃图片if (leap == player.motion_state){putimagePNG2(player.x, player.y, &people_leap[player.frame_leap]);}//打印人物滑行图片if (slide == player.motion_state)//如果是滑行就打印{player.y = 360 - people_slide[player.frame_slide].getheight();//打印当前图片帧的高度putimagePNG2(player.x, player.y, &people_slide[player.frame_slide]);}//绘制跑步分数settextcolor(BLACK);settextstyle(20, 25, "黑体");setbkmode(TRANSPARENT);char count[40];sprintf(count, "%d", scored);outtextxy(10, 20, count);outtextxy(textwidth(count)+10, 20, "分");}//图片更新运动
void Update()
{for (int i = 0; i < 3; i++){bk_x[i] -= bk_speed[i];//当背景图片运动一个窗口距离时,重新回到原点if (bk_x[i] <= -WIN_WIDTH){bk_x[i] = 0;}}scored++;//得分//人物跳跃运动if (leap == player.motion_state){if (player.y < player.leap_height)//如果人物高度小于要求高度时,偏移量为正{player.jump_offset = 10;}player.y += player.jump_offset;//如果人物高度大于要求高度时,偏移量为负if (player.frame_leap != 12){player.frame_leap++;//跳跃图片帧改变}if (player.y >= 360 - people_run[0].getheight()){player.motion_state = run;player.jump_offset = -10;player.frame_leap = 0;player.frame_run = 0;player.frame_slide = 0;player.y = 360 - people_run[0].getheight();}}//人物滑行动作if (slide == player.motion_state ){if (0 == player.frame_slide && player.slide_distance >= 4){player.frame_slide += 1;}player.slide_distance++;//滑行距离if (20 == player.slide_distance){player.frame_slide = 0;player.motion_state = run;player.frame_run = 0;player.slide_distance = 0;player.y = 360 - people_run[0].getheight();}}//检测是否碰撞,碰撞了人物和障碍物一起后移。struct Node* p_check = list->next;int one = 0;//用于标记当向前一步之后,while循环不再向前移动while (p_check!=NULL){if (p_check->obstacle_t->exist == false){p_check = p_check->next;continue;}if (CheckCollision(p_check->obstacle_t)){player.x -= p_check->obstacle_t->speed;if (player.x <= -people_run->getwidth()){player.exist = false;}return;}else{if (one<=0 && player.x <= WIN_WIDTH * 0.5 - people_run[0].getwidth() * 0.5){player.x += 2;//当人物不在当初位置时向前移动one++;}}p_check = p_check->next;}
}//按键响应
void KbControl()
{char keyboard = {0};if (_kbhit()){update = true;keyboard = getch();switch (keyboard){case ' ':if (slide == player.motion_state)//滑行时可以跳跃,但是Y坐标不在奔跑时高度,需要重新初始化{player.y = 360 - people_run[0].getheight();}player.motion_state = leap;break;case 80:if (player.motion_state != leap)//跳跃时不允许滑行{player.motion_state = slide;}break;default:break;}}
}

3.制作障碍物

a.创建障碍物链表

b.加载资源

c.障碍物运动和绘制d

d.碰撞检测

//加载障碍物图片
void LoadObstImg()
{char obstacle_path[20];IMAGE img_tortoise;vector<IMAGE>tortoiseArr;for (int i = 0; i < 7; i++){sprintf(obstacle_path, "resource/t%d.png", i + 1);loadimage(&img_tortoise, obstacle_path);tortoiseArr.push_back(img_tortoise);}obstacleImgs.push_back(tortoiseArr);IMAGE img_lion;vector<IMAGE>lionArr;for (int i = 0; i < 6; i++){sprintf(obstacle_path, "resource/p%d.png", i + 1);loadimage(&img_lion, obstacle_path);lionArr.push_back(img_lion);}obstacleImgs.push_back(lionArr);IMAGE img_fire;vector<IMAGE>fireArr;for (int i = 0; i < 9; i++){sprintf(obstacle_path, "resource/fire%d.png", i + 1);loadimage(&img_fire, obstacle_path, 46, 68, true);fireArr.push_back(img_fire);}obstacleImgs.push_back(fireArr);IMAGE img_hock;for (int i = 0; i < 4; i++){vector<IMAGE>hockArr;sprintf(obstacle_path, "resource/h%d.png", i + 1);loadimage(&img_hock, obstacle_path,84,260,true);hockArr.push_back(img_hock);obstacleImgs.push_back(hockArr);}
}
//初始化障碍物
struct Obstacle* InitOb()
{//srand((unsigned int)time(NULL));struct Obstacle* p_ob = (struct Obstacle*)malloc(sizeof(struct Obstacle));assert(p_ob);p_ob->exist = false;return p_ob;
}
//打印障碍物
void PrintObImg(struct Obstacle* p_ob)
{putimagePNG2(p_ob->x, p_ob->y, &obstacleImgs[p_ob->type][p_ob->frame_index]);
}
//障碍物运动
void MoveOb(struct Obstacle* p_ob)
{p_ob->x -= p_ob->speed;
}
//创建头节点
struct Node* CreateList()
{struct Node* p_head = (struct Node*)malloc(sizeof(struct Node));assert(p_head);p_head->obstacle_t = NULL;p_head->next = NULL;return p_head;
}
//创建结点
struct Node* CreateNode(Obstacle* p_ob)
{struct Node* p_node = (struct Node*)malloc(sizeof(struct Node));assert(p_node);p_node->obstacle_t = p_ob;p_node->next = NULL;return p_node;
}
//连接结点
void InsertNode(struct Node* p_head, struct Obstacle* p_ob)
{struct Node* p_newnode = CreateNode(p_ob);p_newnode->next = p_head->next;p_head->next = p_newnode;
}
//打印结点
void PrintList(struct Node* p_head)
{struct Node* p_move = p_head->next;while (p_move != NULL){if (false == p_move->obstacle_t->exist){p_move = p_move->next;continue;}PrintObImg(p_move->obstacle_t);MoveOb(p_move->obstacle_t);//减缓障碍物帧率static int currFrame = 0;static int frame = 5;currFrame++;if (currFrame >= frame){currFrame = 0;int len = obstacleImgs[p_move->obstacle_t->type].size();//获取一种障碍物的图片数量p_move->obstacle_t->frame_index = (p_move->obstacle_t->frame_index + 1) % len;}if (-obstacleImgs[p_move->obstacle_t->type][p_move->obstacle_t->frame_index].getwidth() >= p_move->obstacle_t->x){p_move->obstacle_t->x = WIN_WIDTH;p_move->obstacle_t->exist = false;}p_move = p_move->next;}
}
//更新障碍物状态类型位置
void UpdateOb()
{//srand((unsigned int)(time(NULL)));struct Node* p_curr = list->next;while (p_curr != NULL){if (true == p_curr->obstacle_t->exist){p_curr = p_curr->next;continue;}p_curr->obstacle_t->exist = (bool)(rand() % 2);//随机产生障碍物的存在与否if (true == p_curr->obstacle_t->exist){p_curr->obstacle_t->type = (OBSTACLE_TYPE)(rand() % 4);//随机产生障碍物类型if (hock1 == p_curr->obstacle_t->type){p_curr->obstacle_t->type = (OBSTACLE_TYPE)(p_curr->obstacle_t->type + (rand() % 4));}p_curr->obstacle_t->frame_index = 0;p_curr->obstacle_t->x = WIN_WIDTH;p_curr->obstacle_t->y = 360 - obstacleImgs[p_curr->obstacle_t->type][p_curr->obstacle_t->frame_index].getheight();if (lion == p_curr->obstacle_t->type){p_curr->obstacle_t->speed = 10;}else if (tortoise == p_curr->obstacle_t->type){p_curr->obstacle_t->speed = 8;p_curr->obstacle_t->frame_index = rand() % 7;}else if (fire == p_curr->obstacle_t->type){p_curr->obstacle_t->speed = 8;p_curr->obstacle_t->frame_index = rand() % 7;}else if (p_curr->obstacle_t->type >= hock1 && p_curr->obstacle_t->type <= hock4){p_curr->obstacle_t->speed = 8;p_curr->obstacle_t->y = 0;}return;}p_curr = p_curr->next;}
}
//判断碰撞
bool CheckCollision(struct Obstacle* p_ob)
{int x01 = player.x + 25;int y01 = player.y;int x02 = 0;int y02 = 0;if (run == player.motion_state){x02 = player.x + people_run->getwidth() - 20;y02 = player.y + people_run->getheight();}else if (leap == player.motion_state){x02 = player.x + people_leap->getwidth() - 20;y02 = player.y + people_leap->getheight();}else if (slide == player.motion_state){x02 = player.x + people_slide->getwidth() - 20;y02 = player.y + people_slide->getheight();}int x11 = p_ob->x;int x12 = p_ob->x + obstacleImgs[p_ob->type][p_ob->frame_index].getwidth();int y11 = p_ob->y;int y12 = p_ob->y + obstacleImgs[p_ob->type][p_ob->frame_index].getheight();int zx = abs(abs(x01) + x02 - x11 - x12);int x = abs(x02 - x01) + abs(x12 - x11);int zy = abs(y01 + y02 - y11 - y12);int y = abs(y02 - y01) + abs(y12 - y11);return (x >= zx && y >= zy);
}

4.游戏运行

//游戏运行
void RunGame()
{srand(unsigned int(time(NULL)));while (player.exist == true){if (timer(40, 0)){update = true;}KbControl();if (update){static int currTime = 0;static int Time = 40 + rand() % 60;currTime++;if (currTime >= Time){currTime = 0;UpdateOb();}update = false;BeginBatchDraw();PrintdImg();PrintList(list);FlushBatchDraw();Update();}}
}int main(void)
{LoadImg();InitData();RunGame();getchar();closegraph();return 0;
}

5.tools用于透明贴图

#include <stdio.h>
#include <Windows.h>#include <mmsystem.h>
#pragma comment(lib, "winmm.lib")
// 载入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);
}

本游戏开发基于rock老师视频内容(视频学习网站上都能找到)以及自己学到的知识编写,可以简单学习链表和图形工具的运用,根据自己的喜好加以修改,仅供学习参考,不足之处还望指出,大家一起学习进步。

资源:链接:https://pan.baidu.com/s/1sLC0f1D77iQ-EUQrTbnu-Q 
提取码:0lp8

用C语言写一个类似天天酷跑游戏(图形库用easyx)相关推荐

  1. 【C语言】实现天天酷跑游戏

    天天酷跑游戏开发日志及源码 ** 纯c语言开发的游戏项目,与天天酷跑玩法与贴图类似,日志中有着详细的开发过程,从零开始手把手带你,解决游戏开发的问题:体验开发的乐趣!!! ps:源码在文章最下面,有详 ...

  2. 不敢相信,居然用Java写了个“天天酷跑”!

    作者 | MyHuey 来源 | https://blog.csdn.net/qq_45909299 首先,写一个需求文档: 一.项目名称:<天天酷跑>(RunDay) 二.功能介绍: 闯 ...

  3. 天天酷跑java_利用Java怎么实现一个天天酷跑游戏

    利用Java怎么实现一个天天酷跑游戏 发布时间:2020-12-15 17:25:03 来源:亿速云 阅读:102 作者:Leah 利用Java怎么实现一个天天酷跑游戏?很多新手对此不是很清楚,为了帮 ...

  4. java酷跑_不敢相信,居然用Java写了个“天天酷跑”!

    首先,写一个需求文档: 一.项目名称:<天天酷跑>(RunDay) 二.功能介绍: 闯关类游戏,玩家登录后,选择进入游戏,通过键盘控制玩家的上下左右移动,来躲避 障碍物和吃金币,玩家躲避的 ...

  5. 【Python游戏】基于Python的pygame模块实现的天天酷跑游戏 | 附带源码

    前言 我相信很多小伙伴都玩过的第一个腾讯游戏,那就是天天酷跑,还记得之前为了凑齐钻石买小单车.人物.坐骑,小编可是花费了老长时间去弄这个的!!不过现在的天天酷跑随便冲个钱都能上大几百万分,没有了以前的 ...

  6. c语言写一个格子涂色的游戏,不一样的涂色游戏小程序,这个魔力贴贴涂色游戏有点意思...

    原标题:不一样的涂色游戏小程序,这个魔力贴贴涂色游戏有点意思 30000+游戏爱好者已加入我们! 沐沐带你发现好游戏! <魔力贴贴>游戏小程序好玩吗? <魔力贴贴>小游戏怎么玩 ...

  7. 用C语言写一个简单的贪吃蛇游戏(用到easyx图形库)

    学习内容:1.游戏的存储与读写 2.制作游戏菜单 3.制作定时器 目录 一.需要用到的头文件.全局变量和一些函数 二.定时器 三.数据的初始化和绘制 四.蛇的运行和吃食物 五.游戏菜单界面 六.游戏存 ...

  8. 模拟天天酷跑游戏java_cocos2d 简单高仿天天酷跑游戏

    1.先直接上视频来看下这个游戏的样子(GIF已经不能满足这个游戏的展示了) 跑酷游戏最纠结的是地图,碰撞倒是简单,可以自己写或者使用box2d等物理引擎.跑酷游戏地图的特点就是随机性.但是随机中又有策 ...

  9. cocos2d 简单高仿天天酷跑游戏

    1.先直接上视频来看下这个游戏的样子(GIF已经不能满足这个游戏的展示了) 跑酷游戏最纠结的是地图,碰撞倒是简单,可以自己写或者使用box2d等物理引擎.跑酷游戏地图的特点就是随机性.但是随机中又有策 ...

最新文章

  1. 信噪比与错误指数matlab,关于信噪比不符合理论值的问题
  2. 架构无小事:QQ碰微信 贴吧遇微博
  3. 程序员避免颈椎病攻略
  4. 高性能异步批量ping的golang实现
  5. 安卓手机主题软件_手机看书神器!Amazon Kindleios、安卓软件
  6. 马云:首批助力欧洲防疫的物资今天到达比利时
  7. python+opencv打开摄像头、拍摄指定次数的照片_python+openCV调用摄像头拍摄和处理图片的实现...
  8. 远离你的电脑,代码写得更好!
  9. 使用redis作为缓存,数据还需要存入数据库中吗?
  10. android 字符串 转json,从字符串到json对象的转换android
  11. g729源码分析-9-g729-解码
  12. 机器学习系列(13)_PCA对图像数据集的降维_02
  13. ROS:TF,机器人坐标管理神器
  14. 计算机无法连接移动硬盘,移动硬盘无法访问解决大全
  15. 关闭windows默认共享
  16. 《英语(二)》作文案例
  17. 如何在R中画出高效美观的相关性分析图
  18. 红烧茄条————————炒茄子不费油却很好吃的办法
  19. java中正则表达式以及Pattern和Matcher
  20. Cesium(六)淹没分析(polygon版本)

热门文章

  1. ruoyi框架中使用swagger调用不需要认证接口需要认证401 认证失败,无法访问系统资源问题
  2. 使用Scrapy框架编写 东方财富网eastmoney的爬虫
  3. Python3入门机器学习经典算法与应用——手写knn模块
  4. 办公室服务器安装系统,教你如何架设办公室FTP服务器以Serv-U为例
  5. 不同电脑的办公便签软件如何同步 办公室和家里电脑同步的便签
  6. 抖音实战~我关注的博主列表、关注、取关
  7. typescript真的有学习的必要吗?
  8. MobDataQ3手机报告:隐形贫困人口解密 苹果用户无房无车比例比较多
  9. Giga-pixel照相机诞生了
  10. 猫眼字体解决,自动匹配