C语言零基础项目:2D 赛车游戏,详细思路+源码分享

news2025/3/1 13:42:20

目录

一、简介

二、如何建立一个地图包

三、关于碰撞图的绘制

四、游戏时的说明

五、如何更好地绘制赛场图与碰撞图?

游戏截图

源码下载


一、简介

此游戏是《2D 赛车》的”魔改版“——2.5D 双人赛车!

原作实现了 2D 视角的赛车游戏,但是我觉得不够真实、操纵感不强,故挤出数个周末完成了这个”魔改版“,实现了第一人称的视角。

二、如何建立一个地图包


1. 选择赛车,音乐,地图的素材
2. 在程序的 map 文件夹下建立一个文件夹将这些素材放入
3. 建立 set.ini 文件
详情参考工程下的文件夹 a 和 b

三、关于碰撞图的绘制

碰撞图色彩格式:

黑色(0xFFFFFF)为赛道,减速较小
黄色(0xFFFF00)为沙地,会减速
蓝色(0x0000FF)为冰面,会滑动
红色(0xFF0000)为围栏,无法通过
绿色(0xFFFFFF)为终点线
灰色(0xAAAAAA)为终点线的两端,用于判定方向(对应色值 RGB(170,170,170))
紫色(0xFF00FF)为玩家 2 起点
白色(0x000000)为玩家 1 起点

注意事项:

终点线最好为宽度为一的直线!
灰色只有两个像素点,分布在终点线的两端点
画碰撞图宁可把道路画粗一点,因为实际游戏中可能会因为碰撞图画的太窄,导致玩家好像在路上但是被卡住了
此外,设置玩家起始位置也要考虑玩家车辆的长度,如果玩家的起始位置离终点线太近,以至于玩家的车尾超过了终点线的话,那么开动车子的时候就会触发一次车子越过终点的判定。

四、游戏时的说明


上/W 向前开
下/S 倒车
左/A 左转
右/D 右转
如果卡在墙里就按住一个方向键加向前直到出去
预设的地图包为 a、b,在工程文件夹下

五、如何更好地绘制赛场图与碰撞图?


利用 PS 的自由路径和描边,一定要用铅笔。

游戏截图

#include <graphics.h>      // 引用图形库头文件
#include <ctime>
#include <sstream>
#include <fstream>
#include <vector>
#include <conio.h>
// 播放 MP3 所需
#include <mmsystem.h>
#pragma comment(lib,"Winmm.lib")

using namespace std;

#define	CMD_UP			1
#define	CMD_DOWN		2
#define	CMD_LEFT		4
#define	CMD_RIGHT		8
#define	sCMD_UP			16
#define	sCMD_DOWN		32
#define	sCMD_LEFT		64
#define	sCMD_RIGHT		128
#define	CMD_QUIT		256
#define PI				3.1415926

int MaxSpeed = 8;			// 最大速度
int FinSand = 5;			// 在沙上的摩擦力
int FinRoad = 1;			// 在路上的摩擦力
int FinIce = -2;			// 在冰上的摩擦力
int SpeedAdd = 2;			// 加速度
int Rota = 64;				// 转动速度的 -1 次方
int NeedR = 5;				// 目标圈数

int WIDE = 1280;
int HEIGHT = 960;
double EndLineForward = 0;	// 终点角度

bool inIce;
bool inRoad;
bool inSand;
bool inWall;
bool inEndline;

IMAGE Racing;				// 赛场地图
IMAGE Toucher;				// 碰撞图
IMAGE car1;
IMAGE car2;

IMAGE Player1;
int Px = 150;
int Py = 150;
double PForward = 0;		// 方向
int Pspeed = 0;				// 速度
int Ppass = 0;				// 通过几次终点
bool Pwrong = false;		// 是否逆行
bool PHadPass = false;		// 是否通过终点
bool PWaitOut = false;		// 是否等待通过终点
bool Pover = false;			// 是否结束
clock_t Ptime = 0;
clock_t Ptime2 = 0;

IMAGE Player2;
int Cx = 170;
int Cy = 170;
double CForward = 0;
int Cspeed = 0;
int Cpass = 0;
bool Cwrong = false;
bool CHadPass = false;
bool CWaitOut = false;
bool Cover = false;
clock_t Ctime = 0;
clock_t Ctime2 = 0;

bool TwoPlayer = true;

bool isres = true;
bool chexit = false;

bool MeumMod = false;

clock_t Start = 0;
clock_t Now = 0;
clock_t MeumUsed = 0;

struct bottom				// 简易的按钮实现
{
	int ID;

	int x;
	int y;
	int wide;
	int heigh;
	RECT a;
	wstring str;

	COLORREF fillcolor;
	COLORREF linecolor;
	COLORREF textcolor;
	LOGFONT textstyle;
	UINT uFormat;

	bottom(int gID, int gx, int gy, int gw, int gh, wstring gs)
	{
		fillcolor = getfillcolor();
		linecolor = getlinecolor();
		textcolor = gettextcolor();
		gettextstyle(&textstyle);
		uFormat = DT_CENTER | DT_VCENTER | DT_SINGLELINE;
		ID = gID;
		x = gx;
		y = gy;
		wide = gw;
		heigh = gh;
		str = gs;
		a = { x, y, x + wide, y + heigh };
	}
};

struct page
{
	vector<bottom> botlist;

	bool MouseTouch(int left, int top, int right, int bottom, MOUSEMSG m)	// 鼠标区域判定
	{
		for (int i1 = left; i1 < right; i1++)
		{
			for (int i2 = top; i2 < bottom; i2++)
			{
				if (m.x == i1 && m.y == i2)
				{
					return true;
				}
			}
		}
		return false;
	}

	int ShownPage()														// 显示并等待按键被响应,返回相应的ID值
	{
		COLORREF fillcolor = getfillcolor();
		COLORREF linecolor = getlinecolor();
		COLORREF textcolor = gettextcolor();
		LOGFONT textstyle;
		gettextstyle(&textstyle);

		MOUSEMSG m;
		setbkmode(TRANSPARENT);

		for (unsigned int i = 0; i < botlist.size(); i++)
		{
			setfillcolor(botlist[i].fillcolor);
			setlinecolor(botlist[i].linecolor);
			settextcolor(botlist[i].textcolor);
			settextstyle(&botlist[i].textstyle);

			fillrectangle(botlist[i].x, botlist[i].y, botlist[i].x + botlist[i].wide, botlist[i].y + botlist[i].heigh);

			drawtext(botlist[i].str.c_str(), &botlist[i].a, botlist[i].uFormat);
		}
		FlushBatchDraw();

		while (true)
		{
			FlushMouseMsgBuffer();
			m = GetMouseMsg();
			if (m.mkLButton)
			{
				for (unsigned int i = 0; i < botlist.size(); i++)
				{
					if (MouseTouch(botlist[i].x, botlist[i].y, botlist[i].x + botlist[i].wide, botlist[i].y + botlist[i].heigh, m))
					{
						return botlist[i].ID;
					}
				}
			}
		}

		setfillcolor(fillcolor);
		setlinecolor(linecolor);
		settextcolor(textcolor);
		settextstyle(&textstyle);
	}
};

struct intro	// 地图的介绍信息
{
	wstring filename;
	wstring title;
	wstring intr;
	wstring inipath;
};
vector<intro> IntroList;

class timer		// 计时器
{
private:
	bool is_start = false;
	clock_t start;
public:
	bool WaitFor(clock_t s)
	{
		if (is_start)
		{
			if ((start + s) <= clock())
			{
				is_start = false;
				return true;
			}
			else
			{
				return false;
			}
		}
		else
		{
			start = clock();
			is_start = true;
			return false;
		}
	}
};

void init();
void gaming();
int GetCommand();
void DispatchCommand(int _cmd);
void OnLeft(bool player);		// false 玩家 1,true 玩家 2
void OnRight(bool player);
void OnUp(bool player);
void OnDown(bool player);
void MoveCheck(bool player);	// 碰撞判定
int PointTsm(int x, int y, int wide, int high);	// 坐标与数值的转换
void Draw();
void End();
void PutImgWithout(IMAGE &obj, int px, int py, COLORREF withouter, DWORD* pbWnd, int wX, int wY, DWORD bitsub);	// 放置图片,除了
void SetBirth();	// 第一次读取
void StartWord();
void Loading();		// 加载地图
int ChooseMap();	// 选择地图
void LoadIntro(string File);
BOOL SearchFilesByWildcard(string wildcardPath);	// 搜索文件,参考自https://blog.csdn.net/faithzzf/article/details/54290084
IMAGE zoomImage(IMAGE* pImg, int newWidth, int newHeight);	// 图片缩放
void showhelp();	// 显示帮助文件
void clean();		// 清空缓冲区
void restart();		// 用于重新开始游戏
bool CanRota (bool player);//是否可以旋转

源码下载

群文件自行下载

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

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

相关文章

关于 国产麒麟系统赋值给双精度double时乘以1.0f编译器优化 的解决方法

若该文为原创文章&#xff0c;转载请注明原文出处 本文章博客地址&#xff1a;https://hpzwl.blog.csdn.net/article/details/128459376 红胖子(红模仿)的博文大全&#xff1a;开发技术集合&#xff08;包含Qt实用技术、树莓派、三维、OpenCV、OpenGL、ffmpeg、OSG、单片机、软…

【 uniapp - 黑马优购 | 首页】小程序首页全局配置(home、网络请求、轮播图、分类...)

个人名片&#xff1a; &#x1f43c;作者简介&#xff1a;一名大二在校生&#xff0c;讨厌编程&#x1f38b; &#x1f43b;‍❄️个人主页&#x1f947;&#xff1a;小新爱学习. &#x1f43c;个人WeChat&#xff1a;hmmwx53 &#x1f54a;️系列专栏&#xff1a;&#x1f5bc…

csdn里的KaTex 公式语法

KaTex 语法 Accents 字母各种上下标 波浪&#xff0c;箭头&#xff0c;声调等 Delimiters 分隔符 大括号&#xff0c;小括号&#xff0c;方括号 Environments 行列式里多行多列数字表达式包含 HTML Letters and Unicode 字符和 Unicode Layout 布局 Spacing 空格 Logic and Se…

Centos系统,防火墙没开,docker部署的rabbitmq不能外网访问监听端口,但别的端口都能正常访问???

真是一个神奇的问题&#xff0c;防火墙firewalld ,iptables都没开。 之前访问都正常&#xff0c;最近可能是服务器被动了。rabbitmq的相关监听接口&#xff0c;只能本机服务器连接了&#xff0c;导致设备连接不了rabbitmq组件了。 排查问题记录 1.防火墙是否开启。发现是关闭…

web仿真或实际内存分析应用及自动化方案

js 自带 GC&#xff08;垃圾回收&#xff09;机制&#xff0c;因此绝大多数 web 开发人员不会在日常开发中考虑内存情况&#xff08;包括本人&#xff09;&#xff0c;在多数业务场景中&#xff0c;这可能没有问题&#xff0c;但在一些核心web应用场景下&#xff08;比如某个页…

【Spring(一)】初识Spring(史上最详细的Spring介绍!)

文章目录前言1.初识Spring2.Spring Framework系统架构3.核心概念前言 在学习 Spring 之前&#xff0c;我们需要先知道为什么要学习它?    IT业的任何一门技术,它只有抢占了很强的市场占有率&#xff0c;才会有更多的人使用和学习它&#xff0c;Spring技术在我们Java开发界拥…

APP怎么免费接入MobPush

1、获取AppKey 申请Appkey的流程&#xff0c;请点击 http://bbs.mob.com/thread-8212-1-1.html?fromuid70819 2、下载SDK 下载解压后&#xff0c;如下图&#xff1a; 目录结构 &#xff08;1&#xff09;Sample&#xff1a;演示Demo。&#xff08;2&#xff09;SDK&#…

【C操作符】详解操作符

操作符前言一、操作符分类二、算数操作符三、移位操作符&#xff08;一&#xff09;原码、补码、反码&#xff08;二&#xff09;操作符应用1.左移操作符&#xff08;1&#xff09;正数&#xff08;2&#xff09;负数&#xff08;3&#xff09;总结2.右移操作符&#xff08;1&a…

《码出高效:java开发手册》六-数据结构与集合(二)

前言 接上篇&#xff0c;第六章第二部分&#xff0c;上篇讲到了红黑树的FixAfterInsertion方法&#xff0c;这个方法原理与fixAfterDelete类似&#xff0c;只讲这个添加时的调整方法 代码可以看到&#xff0c;调整后的根节点一定是黑色的&#xff0c;叶子节点可红可黑&#x…

Spring 之 @Import 注解使用与源码浅析

1、Import 的作用&#xff1f; 再说 Import 之前先回忆下 Component 的作用&#xff0c;在类上标注该注解&#xff0c;该类就能够被 Spring 扫描封装成 BeanDefinition 并注册到容器中。但现在需要将第三方 jar 包、或者其他路径下面的包中的类也要被扫描注册呢&#xff1f;使…

Unity 制作一个简单的星系

使用素材&#xff1a; 1.Planets with Space Background in Flat Style 2.Planet Icons 创建场景 编写脚本 using System.Collections; using System.Collections.Generic; using UnityEngine;public class Cytaster : MonoBehaviour {[SerializeField]private float rotate_s…

【LeetCode】矩阵置零 [M](矩阵)

73. 矩阵置零 - 力扣&#xff08;LeetCode&#xff09; 一、题目 给定一个 m x n 的矩阵&#xff0c;如果一个元素为 0 &#xff0c;则将其所在行和列的所有元素都设为 0 。请使用 原地 算法。 示例 1&#xff1a; 输入&#xff1a;matrix [[1,1,1],[1,0,1],[1,1,1]] 输出&a…

uni-app - 封装全局 API 调用弹框组件

uni-app - 在纯 JS 文件中调用自定义弹框组件 / 封装全局 API 调用弹框组件&#xff08;解决小程序、APP 无法使用 document.body.appendChild 插入组件节点&#xff09;适配全端 uni-app中实现一个全局弹层组件 引用超级全局组件方案 一、安装 npm install vue-inset-loade…

零入门容器云网络-9:命令行式操作tun设备介绍

已发表的技术专栏&#xff08;订阅即可观看所有专栏&#xff09; 0  grpc-go、protobuf、multus-cni 技术专栏 总入口 1  grpc-go 源码剖析与实战  文章目录 2  Protobuf介绍与实战 图文专栏  文章目录 3  multus-cni   文章目录(k8s多网络实现方案) 4  gr…

测开工具:spring boot 实现同步数据库表结构

源码&#xff1a; GitHub - 18713341733/mysqlsync 一、使用场景 一个项目&#xff0c;有多套开发环境。有一套标准的数据库&#xff0c;不同的开发环境&#xff0c;有各自的一套数据库。 标准数据库的表结构经常发生变化&#xff0c;不同的开发环境中的数据库&#xff0c;…

C#,图像二值化(04)——全局阈值 Kittler 算法及其源程序

1、Kittler算法&#xff08;最小误差法&#xff09;概述 最小误差法是 J. Kittler & J. Illingworth 1986年在《MINIMUM ERROR THRESHOLDING》文章中提出的一种基于直方图的阈值分割方法,简称 Kittler 算法。其思想:假设灰度图像由目标和背景组成,且目标和背景满足一混合高…

11个技巧让你成为更好的 Typescript 程序员

学习 Typescript 通常是一次重新发现之旅。您的最初印象可能非常具有欺骗性&#xff1a;这不就是一种注释 Javascript 的方式&#xff0c;所以编译器可以帮助我找到潜在的错误吗&#xff1f; 通过 r/mevlixreddit 虽然这句话通常是正确的&#xff0c;但随着您继续前进&#xff…

【聆思CSK6 视觉AI开发套件试用】AI识别试用以及闭坑方案

本篇文章来自极术社区与聆思科技组织的CSK6 视觉AI开发套件活动&#xff0c;更多开发板试用活动请关注极术社区网站。作者&#xff1a;X Y Z 非常感谢能有这次机会体验聆思CSK6 视觉AI开发套件。上班的一大早收到了快递&#xff0c;迫不及待的打开快递。必须先来个图&#xff0…

4个技巧,节约网络工程师一半的时间

01 批量ping网段 对于一个网段ip地址众多&#xff0c;如果单个检测实在麻烦&#xff0c;那么你就可以直接批量ping网段检测&#xff0c;那个ip地址出了问题&#xff0c;一目了然。 先看代码&#xff0c;直接在命令行窗口输入&#xff1a; for /L %D in (1,1,255) do ping 10…

渗透测试神器--Burp Suite

一、介绍 Burp Suite 是用于攻击web 应用程序的集成平台。Burp Suite是一款信息安全从业人员必备的集成型的渗透测试工具&#xff0c;它采用自动测试和半自动测试的方式&#xff0c;包含了Proxy、Spider、Scanner、Intruder、Repeater、Sequencer、Decoder、Comparer等工具模块…