C语言项目——天天酷跑

文章目录

    • C语言项目——天天酷跑
  • 前言
  • 注意事项
  • 源代码分享
  • 效果展示
  • 总结

前言

自学编程最有效的就是通过一些自己感兴趣的项目去学习,如果只是纯粹的听取知识点很难坚持,在项目中看到不懂的再去查询相关知识点,印象会更加深刻!
今天我开始了第一个项目——天天酷跑小游戏!

注意事项

注意下载easyx包哦!
相关png,mp3文件素材或tools文件工具包,可以自己百度寻找也可以在三连后评论区告诉我!推荐使用自己找的素材可以变得更加有趣!

源代码分享

#define _CRT_SECURE_NO_WARNINGS 1
/*
* 基于easyx图形库
* 背景三重移动速度不同
*/
#include <stdio.h>
#include <graphics.h>
#include "tools.h"//消除png背景透明,其他功能函数
#include <conio.h>
#include <vector>//暂时借用C++里的可变数组头文件using namespace std;//声明命名空间#define WIN_WIDTH 1012
#define WIN_HEIGHT 396
#define OBSTACLE_COUNT 10
#define WIN_SCORE 20IMAGE imgBgs[3];//小游戏,全局变量,类型为图片的数组IMAGE,素材在文件夹res里
int bgX[3];//实际上背景的x坐标为动态变化
int bgSpeed[3] = { 1,2,4 };
IMAGE imgHeros[12];
int heroX;
int heroY;
int heroIndex;//英雄图片帧序号bool heroJump;//true和falseint jumpHeightMax;
int heroJumpOff;//跳跃偏移量
int update;//表示是否需要马上刷新画面//IMAGE imgTortoise;//小乌龟随机出现
//int tortoiseX;
//int tortoiseY;
//bool tortoiseExist;//当前窗口是否有小乌龟int heroBlood;
int score;//enum用于定义枚举变量,typedef和obstacle_type配合产生一种新的类型
typedef enum {//枚举类型TORTOISE,//乌龟 0LION,//狮子 1HOOK1,HOOK2,HOOK3,HOOK4,OBSTACLE_TYPE_COUNT //6,表示类型个数
}obstacle_type;
obstacle_type type1;//obstacle_type为一种新定义的类型vector<vector<IMAGE>> obstacleImgs;
//C++特殊二维数组:存放三种障碍物各自图片;C语言IMAGE obstacleImags[3][12]但不可变
//vector<int> data;//特殊一维数组:可变数组,类型为int
//IMAGE obstacleImgs[3][12];typedef struct obstacle {obstacle_type 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];//游戏初始化
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);//用于生成文件名,%03d三位整数,不够三位补零loadimage(&imgBgs[i],name);//在面板中加载图片bgX[i] = 0;}for (int i = 0; i < 12; i++){//加载Hero奔跑的图片帧素材sprintf(name, "res/hero%d.png", i + 1);loadimage(&imgHeros[i], name);}//设置hero初始位置heroX = WIN_WIDTH * 0.5 - imgHeros[0].getwidth() * 0.5;heroY = 345 - imgHeros[0].getheight() ;heroIndex = 0;heroJump = false;jumpHeightMax = 345 - imgHeros[0].getheight() - 120;//限制跳的高度heroJumpOff = -4;update = true;//加载小乌龟//loadimage(&imgTortoise, "res/t1.png");//tortoiseExist = false;//tortoiseY = 345 - imgTortoise.getheight()+4;IMAGE imgTort;loadimage(&imgTort, "res/t1.png");//加载乌龟图片,这里只用了一张vector<IMAGE>imgTortArray;//定义乌龟障碍图片空数组imgTortArray.push_back(imgTort);//将imgTort添加到空数组,若多个图片可利用循环添加见LIONobstacleImgs.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/d2.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, 63, 260, true);imgHookArray.push_back(imgH);obstacleImgs.push_back(imgHookArray);}heroBlood = 100;//预加载音效,防止hit音效延迟preLoadSound("res/hit.mp3");mciSendString("play res/bg.mp3 repeat", 0, 0, 0);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].imgIndex = 0;//obstacles[i].type = (obstacle_type)(rand ()% OBSTACLE_TYPE_COUNT);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 = 345 + 5 - obstacleImgs[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 = 10;}else if (obstacles[i].type >= HOOK1&& obstacles[i].type <= HOOK4) {obstacles[i].speed = 0;obstacles[i].power = 10;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;//hero图片斜对角两点坐标int off = 30;//偏移量,不那么严格if (!heroDown) {//非下蹲a1x = heroX + off;a1y = heroY + off;a2x = heroX + imgHeros[heroIndex].getwidth() - off;a2y = heroY + imgHeros[heroIndex].getheight();}else {//下蹲时a1x = heroX + off;a1y = 345-imgHeroDown[heroIndex].getheight();a2x = heroX + imgHeroDown[heroIndex].getwidth() - off;a2y = 345;}int b1x = obstacles[i].x + off;//障碍物对角坐标int b1y = obstacles[i].y + off;int b2x = obstacles[i].x + obstacleImgs[obstacles[i].type][obstacles[i].imgIndex].getwidth() - off;int b2y = obstacles[i].y+obstacleImgs[obstacles[i].type][obstacles[i].imgIndex].getheight()- 10;if (rectIntersect(a1x, a1y, a2x, a2y, b1x, b1y, b2x, b2y)) {//tools里的矩形碰撞检测函数heroBlood -= obstacles[i].power;printf("血量剩余:%d\n", heroBlood);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;}}//heroIndex = (heroIndex + 1) % 12;//数组序号不想要1-12;而要0-11//实现跳跃if (heroJump) { //按下空格后,跳跃启动函数jump()为trueif (heroY < jumpHeightMax) {//超过高度上限;注:Y坐标正方向朝下;X朝右heroJumpOff = 4;}heroY += heroJumpOff;//上升或下落if (heroY > 345 - imgHeros[0].getheight()) {//地面坐标heroJump = false;heroJumpOff = -4;}}else if (heroDown) {static int count = 0;int delays[2] = { 4,12 };//前一帧时间短点,后一帧下蹲时间长点儿 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 = 60;frameCount++;if (frameCount > enemyFre) {//帧数计够数,该产生乌龟了;计数是随机的frameCount = 0;//if (!tortoiseExist)//如果不存在//{// tortoiseExist = true;//使存在//   tortoiseX = WIN_WIDTH;//enemyFre = 200 + rand() % 300;//计数随机//}enemyFre = 50 + rand() % 50;//50+0~49即50-99creatObstacle();}//if (tortoiseExist) {//更新小乌龟位置如果存在//  tortoiseX -= bgSpeed[2];// if (tortoiseX < -imgTortoise.getwidth()) {//     tortoiseExist = 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()) {obstacles[i].exist = false;}int len = obstacleImgs[obstacles[i].type].size();obstacles[i].imgIndex = (obstacles[i].imgIndex + 1) % len;}}//"碰撞检测“checkHit();
}void updateBg()//渲染游戏背景,背景是移动的{putimagePNG2(bgX[0], 0, &imgBgs[0]);//指定图片加载位置,左上角坐标,x不固定变量putimagePNG2(bgX[1], 119, &imgBgs[1]);putimagePNG2(bgX[2], 330, &imgBgs[2]);}void jump() {//启动跳跃开关,真正实现此功能在fly()函数heroJump = true;update = true;//如果没计时到30ms按下按键可能跳走停止画面刷新,这里强制使其继续刷新}void down() {heroDown = true;update = true;heroIndex = 0;}void keyEvent()//用户按键输入,跳跃蹲下等{char ch;//scanf函数需要回车键会卡住程序,不用if (_kbhit())//有按键按下,kbhit()返回 true{ch=_getch();//不需要回车直接读取if (ch == 'w') {jump();}else if (ch == 's') {down();}}}void updateEnemy() {//if (tortoiseExist) {//初始值为false//  putimagePNG2(tortoiseX, tortoiseY, WIN_WIDTH, &imgTortoise);//}for (int i = 0; i < OBSTACLE_COUNT; i++) {if (obstacles[i].exist) {putimagePNG2(obstacles[i].x, obstacles[i].y, WIN_WIDTH, &obstacleImgs[obstacles[i].type][obstacles[i].imgIndex]);}}}void updateHero() {if (!heroDown) {putimagePNG2(heroX, heroY, &imgHeros[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);//tools工具}void checkOver() {if (heroBlood <= 0) {loadimage(0, "res/over.png");FlushBatchDraw();//显示缓存mciSendString("stop res/bg.mp3 repeat", 0, 0, 0);//关闭背景音乐system("pause");//暂停之后,充币复活,或者开始下一局heroBlood = 100;mciSendString("play res/bg.mp3", 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 + obstacleImgs[obstacles[i].type][0].getwidth() < heroX) {score++;obstacles[i].passed = true;printf("分数:%d\n", score);}}}void updateScore() {//50=>"50"  '5'  '5'-'0'==5char 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/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);}}int main(void){init();//显示初始界面loadimage(0, "res/over.png");system("pause");int timer = 0;while (1){keyEvent();timer += getDelay();//tools工具,帧休眠,代替sleep提高实时性if (timer > 30){timer = 0;update = true;//Sleep(30);//帧休眠,不然速度太快}if (update){update = false;BeginBatchDraw();//tools工具,为了改善闪烁updateBg();//putimagePNG2(heroX, heroY, &imgHeros[heroIndex]);//确定英雄位置,利用图片帧实现奔跑updateHero();updateEnemy();updateBloodBar();updateScore();checkWin();EndBatchDraw();checkOver();//游戏是否结束checkScore();fly();}}return 0;
}

效果展示


总结

遇到挫折,要有勇往直前的信念,马上行动,坚持到底,决不放弃,成功者决不放弃,放弃者绝不会成功。成功的道路上,肯定会有失败;对于失败,我们要正确地看待和对待,不怕失败者,则必成功;怕失败者,则一无是处,会更失败。
本次项目练习学习亲测有效可以运行,参考了互联网上诸多材料,仅供互相交流学习使用!
欢迎自学的小伙伴们发言指正!

【C语言项目】——天天酷跑相关推荐

  1. C语言仿天天酷跑小游戏

    前言:全文代码是模仿程序员rock开发的游戏代码思路,如果大家想根据视频一步步进行制作可以直接去b站进行搜索.全文代码主要分为两个部分,一个是完整版的开发代码(博主根据视频进行一步一步制作而成,素材也 ...

  2. C语言开发 天天酷跑 用到的 graphics.h

    我是C开发的小白,才开始学.这些库需要单独引入,自己操作了一遍,可以实现引入了.就写个博客,记录一下. 下载easyx 下载完安装,如下图: 软件会自动检测你当前的VS版本,点击安装,会弹出提示安装成 ...

  3. 【C语言】游戏开发:天天酷跑丨完美练手项目 [附源码]

    目录 一.项目说明: 二.项目作用 三.项目技术要求 四.库.宏.主函数说明 五.项目实现 5.1游戏背景的实现 5.2实现Hero奔跑 5.3 实现Hero跳跃 5.4 优化帧等待 5.6使用结构体 ...

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

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

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

    C语言手写天天酷跑代码详解 项目总览: 一.项目开发日志 二.引入库与宏编译 三.全局变量与结构体的定义 四.主函数中的内容 五.逐个自定义函数拆解分析 1.初始化init()函数 2.处理用户按键输 ...

  6. java窗体添加背景图片_Java项目实战之实战之天天酷跑(四):游戏主界面

    接上文,本文将实现游戏主界面,功能如下: 移动的背景图片.动态的玩家.玩家的移动功能.五种障碍物持续出现.玩家和障碍物的碰撞.暂停.继续功能. 首先,看一下整体效果: 动图实在太大,几秒钟的 Gif ...

  7. awt jtable 多线程加载图片_Java项目实战之天天酷跑(三):缓冲加载游戏界面

    前文,我们完成了开始游戏界面的搭建.本文将实现缓冲加载界面的搭建.并搭建与前面俩界面间的桥梁.实现输入正确用户名密码后,进入开始游戏界面,点击开始游戏按钮后,进入缓冲加载界面的功能. 界面示意图: 具 ...

  8. 【Java练手项目七】Java项目实战之天天酷跑

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

  9. Java项目实战之天天酷跑

    来源:blog.csdn.net/qq_45909299 首先,写一个需求文档: 一.项目名称:<天天酷跑>(RunDay) 二.功能介绍: 闯关类游戏,玩家登录后,选择进入游戏,通过键盘 ...

最新文章

  1. 【重磅】马斯克遇终极麻烦:被起诉欺诈罪 或丢掉CEO职位 特斯拉暴跌约13%
  2. 利用存储过程来实现分页性能比较
  3. php查询当前session,php查看当前Session的ID方法
  4. AS升级编译报错:The SourceSet 'instrumentTest' is not recognized by the Android Gradle Plugin....
  5. python语言有什么用-为什么现在很多人都使用Python语言有什么优势
  6. 比特币钱包(2) BIP32 HD钱包之生成子密钥
  7. MIDDLEWARE 在传输大量数据时,经常会发生堵塞,如果有一条错误的数据整个队列将无法处理
  8. 旋转轨迹_谁是最可怕的压轴题?——直线运动轨迹
  9. 【硬核课】最新《图卷积神经网络GCN》2020概述,76页ppt,NTU-Xavier Bresson,纽约大学深度学习课程...
  10. 测试电动车速度的软件,应用测试:最高速度达11MB/S
  11. 图像各向异性平滑滤波
  12. 百度在首页输出console发布招聘信息
  13. 【Asan】新鲜货:使用ASan检测内存越界问题
  14. 数据科学 | 如何解释线性回归的R方
  15. Numpy的tile函数
  16. 测试人员,如何对直播类产品的直播质量进行测试呢?
  17. AAAI 2020 提前看 | 三篇论文解读问答系统最新研究进展
  18. # Ubuntu执行sudo apt-get update提示:E: 仓库 “https://mirrors.ustc.edu.cn/ubuntu focal Release” 没有 Release
  19. 网传外企巨头Oracle北京裁员900多人,良心赔偿N+6
  20. Git安装教程(超详细教程)

热门文章

  1. 软件设计师教程中常用公式汇总
  2. 计算机启动时滴滴两声,请问电脑开机时嘀嘀两声是什么故障啊?
  3. HBase+Solr 的 二级索引 实时查询
  4. IdentityServer4实战:Token 中返回用户属性
  5. 交互设计的那些事(下)
  6. 《敢达SEED 宿命 CE世纪》5结局一览
  7. 【vue3 computed 的讲解 案例使用 v3.2+新特性】
  8. 【​观察】解读浪潮云遇上“云上云” 技术赋能驱动数字经济落地
  9. MySql对于时间段交集的处理和通用实现方式(MyBatis-Plus)
  10. 学计算机需要右脑还是左脑,心理学:你第一眼看到的是什么?看出你左脑发达还是右脑发达!...