【C语言】练手游戏项目:天天酷跑1.0代码详解,包括源码,素材,第三方文件。

项目总览:

1.开发语言:C语言加上一点点C++的函数
2.IDE:VS2022(点击跳转到配置环境教程)
3.开发用时:3天左右
4.代码所需要使用的第三方函数与所有图形素材及本项目源码文件均已经上传到我的GitHub,链接:https://github.com/2394799692/Cool-running-every-day1.0 或点此跳转


以下是本篇文章正文内容,欢迎朋友们进行指正,一起探讨,共同进步。——来自考研路上的lwj。QQ:2394799692

一、项目开发日志

/*
* 天天酷跑开发日志
* 1.创建项目
* 2.导入素材
* 3.实际的开发流程:从用户界面入手
* 1)创建游戏窗口
* 2)实现游戏背景(基于“easyx”图形库)
* a:三重背景不同的速度
* b:循环滚动背景的实现
* 3)实现游戏背景
* a.加载背景资源
* b,渲染(坐标)
* 遇到问题:背景图片的png格式图片出现黑色
* 解决办法:百度引入第三方头文件中的putimagePNG2函数解决
* 4.实现玩家的奔跑
* 5.实现玩家的跳跃(空格)
* 6.实现随机小乌龟
* 7.创建障碍物结构体数据类型
* 8.使用障碍物结构体后重新初始化
* 9.封装后多个障碍物的显示
* 10.实现玩家下蹲技能
* 11.实现“柱子”障碍物
* 12.实现血条与计分
* 13.判断游戏胜利
*/

二、引入库与宏编译

#define _CRT_SECURE_NO_WARNINGS//使用scanf函数防止报错
#define WIN_SCORE 20//用于定义游戏获胜的分数条件
#define WIDTH 1012//游戏背景的宽度
#define HEIGHT 396//高度
#define OBSTACLE_COUNT 10//障碍物数量
#include<stdio.h>//标准输入输出库函数
#include<graphics.h>//引入图形库
#include<conio.h>//按键输入库
#include"tools.h"//添加本地头文件
#include<vector>//引入c++库用于使用容器变长数组

三、全局变量与结构体的定义

using namespace std;//声明命名空间
//游戏初始化
IMAGE imgBgs[3];//全局变量,存放三重背景
int bgX[3];//背景图片的x坐标
int bgSpeed[3] = { 1,2,4 };//背景移动的速度
IMAGE imgHeros[12];//奔跑
int heroX;//玩家的x坐标
int heroY;
int heroIndex;//玩家奔跑的图片帧序号
bool heroJump;//玩家跳跃状态
int jumpHeightMax;//设置跳跃最大高度
int heroJumoOff;//设置偏移量
int update;//表示是否需要马上刷新
//IMAGE imgTortoise;//小乌龟
//int torToiseX;//小乌龟的水平坐标
//int torToiseY;
//bool torToiseXExist;//当前窗口是否有小乌龟
int heroBlood;//玩家血量
int score;//分数
typedef enum {//定义障碍物类型结构体
	TORTOISE,
	LION,
	HOOK1,
	HOOK2,
	HOOK3,
	HOOK4,
	OBSTACLE_TYPE_COUNT
}obstacle_type;
vector<vector<IMAGE>>obstacleImgs;//相当于IMAGE obstacleImgs[][]
typedef struct obstacle {//定义障碍物结构体
	int type;//障碍物的类型
	int imgIndex;//当前显示的图片的序号
	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];
bool heroDown;//表示玩家是否处于下蹲状态
IMAGE imgSZ[10];

四、主函数中的内容

int main(void) { 
	init();//初始化函数
	loadimage(0, "res/over.png");//初始画面
	system("pause");//调用DOS系统的暂停命令 pause 来暂停程序执行,按任意一个键后将继续执行。
	int timer = 0;
	while (1) {
		keyEvent();//用于接收空格和tab键来去执行对应的跳跃/下蹲函数
		timer+=getDelay();//第三方封装函数用于返回距离上次间隔调用的时间
		if (timer > 30) {//间隔30帧刷新一次页面
			timer = 0;
			update = true;
		}
		if (update) {//刷新页面
			update = false;
			BeginBatchDraw();//去除闪烁
			updateBg();//渲染游戏背景
			//putimagePNG2(heroX, heroY, &imgHeros[heroIndex]);
			updateHero();//渲染下蹲图片
			updateEnemy();//渲染障碍物
			updateBloodBar();//调用第三方接口渲染血条
			updateScore();//渲染分数图片输出
			checkWin();//检查游戏是否胜利
			EndBatchDraw();//去除闪烁
			checkOver();//检查游戏是否结束
			checkScore();//计算得分
			fly();//实现跳跃,下蹲,障碍物的移动等动态效果
		}
	}
	system("pause");//调用DOS系统的暂停命令 pause 来暂停程序执行,按任意一个键后将继续执行。
	return 0;
}

五、逐个自定义函数拆解分析

1.初始化init()函数

void init() {
	//创建游戏窗口
	initgraph(WIDTH, HEIGHT,EW_SHOWCONSOLE);//调用“easyx”图形库中的函数实现页面大小
	char name[64];
	//加载游戏背景资源
	for (int i = 0; i < 3; i++) {
		sprintf(name, "res/bg%03d.png", i + 1);//宽3位不够前面补充0
		loadimage(&imgBgs[i], name);//载入游戏背景
		bgX[i] = 0;//背景图片的x坐标设为0
		heroJump = false;//跳跃状态初始化为否
	}
	//加载玩家Hero奔跑的图片帧素材
	for (int i = 0; i < 12; i++) {
		sprintf(name, "res/hero%d.png", i + 1);
		loadimage(&imgHeros[i], name);
	}
	//设置玩家的初始位置
	heroX = WIDTH * 0.5 - imgHeros[0].getwidth() * 0.5;
	heroY = 345 - imgHeros[0].getheight();
	heroIndex = 0;
	heroJump = false;
	jumpHeightMax = 345 - imgHeros[0].getheight() - 120;
	heroJumoOff = -4;
	update = true;
	//加载小乌龟
	/*loadimage(&imgTortoise, "res/t1.png");
	torToiseXExist = false;//小乌龟初始化
	torToiseY = 345 - imgTortoise.getheight()+5;*/
	//用结构体加载小乌龟
	IMAGE imgTort;
	loadimage(&imgTort, "res/t1.png");
	vector<IMAGE>imgTortArray;
	imgTortArray.push_back(imgTort);
	obstacleImgs.push_back(imgTortArray);
	//加载狮子
	IMAGE imgLion;
	vector<IMAGE> imgLionArray;
	for (int i = 0; i < 6; i++) {
		sprintf(name, "res/p%d.png", i + 1);
		loadimage(&imgLion, name);
		imgLionArray.push_back(imgLion);
	}
	obstacleImgs.push_back(imgLionArray);
	//初始化障碍物池
	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/h%d.png", i + 1);
		loadimage(&imgH, name,60,260,true);
		imgHookArray.push_back(imgH);
		obstacleImgs.push_back(imgHookArray);
	}
	heroBlood = 100;//初始化血量为满血
	//预加载音效
	preLoadSound("res/hit.mp3");
	mciSendString("play res/bg.mp3 repeat", 0, 0, 0);//重复播放
	lastObsIndex = -1;
	score = 0;//起始分数为0
	//加载数字得分图片
	for (int i = 0; i < 10; i++) {
		sprintf(name, "res/sz/%d.png", i);
		loadimage(&imgSZ[i], name);
	}
}

2.处理用户按键输入keyEvent() 函数

//处理用户按键输入
void jump() {
	heroJump = true;
	update = true;
}
void down() {
	update = true;
	heroDown = true;
	heroIndex = 0;
}
void keyEvent() {
	char ch;
	if (_kbhit()) {//如果有按键按下,返回true
		ch = getch();//不需要按回车即可读取
		if (ch == ' ') {//如果按下空格执行跳跃函数
			jump();
		}
		else if (ch == '	') {//如果按下tab键执行下蹲函数
			down();
		}
	}
}

3.渲染游戏背景 updateBg()函数

void updateBg() {
	putimagePNG2(bgX[0],0,&imgBgs[0]);
	putimagePNG2(bgX[1], 119, &imgBgs[1]);
	putimagePNG2(bgX[2], 330, &imgBgs[2]);
}

4.渲染下蹲图片 updateHero()函数

void updateHero() {
	if (!heroDown) {//下蹲图片渲染
		putimagePNG2(heroX, heroY, &imgHeros[heroIndex]);
	}
	else {
		int y = 345 - imgHeroDown[heroIndex].getheight();
		putimagePNG2(heroX, y, &imgHeroDown[heroIndex]);
	}
}

5.渲染障碍物图片 updateEnemy()函数

void updateEnemy() {
	//渲染小乌龟
	/*if (torToiseXExist) {
		putimagePNG2(torToiseX, torToiseY,WIDTH,&imgTortoise);
	}*/
	for (int i = 0; i < OBSTACLE_COUNT; i++) {
		if (obstacles[i].exist) {
			putimagePNG2(obstacles[i].x, obstacles[i].y, WIDTH, &obstacleImgs[obstacles[i].type][obstacles[i].imgIndex]);
		}
	}
}

6.渲染血条 updateBloodBar()函数

void updateBloodBar() {//调用第三方接口
	drawBloodBar(10, 10, 200, 10, 2, BLUE, DARKGRAY, RED, heroBlood / 100.0);
}

7.渲染分数图片显示 updateScore()函数

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;
	}
}

8.检查游戏是否胜利 checkWin()函数

void checkWin() {
	if (score >= WIN_SCORE) {
		FlushBatchDraw();
		mciSendString("play res/win.mp3", 0, 0, 0);
		Sleep(2000);
		loadimage(0, "res/win.png");
		FlushBatchDraw();
		mciSendString("stop res/bg.mp3", 0, 0, 0);
		system("pause");
		heroBlood = 100;
		score = 0;
		mciSendString("play res/bg.mp3 repeat", 0, 0, 0);
	}
}

9.检查游戏是否结束(死亡) checkOver()函数

void checkOver() {
	if (heroBlood <= 0) {
		loadimage(0, "res/over.png");
		FlushBatchDraw();//刷新缓存
		mciSendString("stop res/bg.mp3", 0, 0, 0);
		system("pause");
		//暂停之后,复活或者开始下一局
		heroBlood = 100;
		score = 0;
		mciSendString("play res/bg.mp3 repeat", 0, 0, 0);
	}
}

10.计算得分 checkScore()函数

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 + obstacleImgs[obstacles[i].type][0].getwidth() < heroX) {
			score++;
			obstacles[i].passed = true;
			printf("score:%d\n", score);
		}
	}
}

11.实现跳跃,下蹲,障碍物的移动等动态效果fly() 函数

void fly() {
	for (int i = 0; i < 3; i++) {
		bgX[i] -=bgSpeed[i];
		if (bgX[i] < -WIDTH) {
			bgX[i] = 0;
		}
	}
	//实现跳跃
	if (heroJump) {
		if (heroY < jumpHeightMax) {//防止飞天
			heroJumoOff = 4;
		}
		heroY += heroJumoOff;//上升
		if (heroY > 345 - imgHeros[0].getheight()) {//防止遁地
			heroJump = false;
			heroJumoOff = -4;
		}
	}
	else if (heroDown) {
		static int count = 0;
		int delays[2] = { 8,30 };
		count++;
		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 enemyFre = 50;
	frameCount++;
	if (frameCount > enemyFre) {
		frameCount = 0;
		enemyFre =50 + rand() % 50;//50-99随机数
		createObstacle();
	}
	//if (torToiseXExist) {
	//	//设置小乌龟的移动
	//	torToiseX -= bgSpeed[2];
	//	if (torToiseX < -imgTortoise.getwidth()) {
	//		torToiseXExist = false;
	//	}
	//}
	//更新所有障碍物的坐标
	for (int i = 0; i < OBSTACLE_COUNT; i++) {
		if (obstacles[i].exist) {
			obstacles[i].x -= obstacles[i].speed + bgSpeed[2];
			if (obstacles[i].x < -obstacleImgs[obstacles[i].type][0].getwidth()*2) {//obstacleImgs[obstacles[i].type][0].getwidth() * 2
				obstacles[i].exist = false;
			}
			int len = obstacleImgs[obstacles[i].type].size();
			obstacles[i].imgIndex = (obstacles[i].imgIndex + 1) % len;
		}
	}
	//玩家和障碍物的碰撞检测
	checkHit();
	
}

六、效果展示:

1.视频效果:点击链接直达

2.图片效果:

1)开始页面:
在这里插入图片描述
2)进入游戏页面:
在这里插入图片描述
3)跳跃页面:
在这里插入图片描述
4)下蹲页面:
在这里插入图片描述
5)游戏结束页面:
在这里插入图片描述

  • 23
    点赞
  • 141
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 20
    评论
c语言天天酷跑是一个小游戏,其中包含了一些编程和开发环境的要求。首先,在游戏代码中,需要打开属性界面,并进行一些配置。具体操作是右键单击游戏代码中的“天天酷跑”,选择属性,然后在属性界面中打开“高级”,找到“字符集”,选择“使用多字节字符集”。接下来,在属性界面中打开“c/c++”,进入“常规”选项,选择“SDL检查”,将该选项设置为“否”。通过这些配置,就可以运行游戏了。 此外,在编写游戏代码中,需要包含一个名为tools.h的头文件,这是游戏程序员自己编写的一个头文件,其中包含了一些详细内容。建议使用VS进行编写,在项目中直接添加该头文件即可。 c语言天天酷跑游戏开发环境可以是VC2010-VS2022,并且需要掌握C语言和一些C的函数。整个开发过程大约需要7小时。如果需要获取游戏素材源码以及第三方库等资源,可以加入学习群817459939获取。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [C语言仿天天酷跑游戏](https://blog.csdn.net/m0_73554747/article/details/128516368)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *3* [【C语言游戏开发天天酷跑丨完美练手项目 [附源码]](https://blog.csdn.net/xiangxin1030/article/details/124174971)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 20
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

立志冲海大

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值