C語言實(shí)現(xiàn)2D賽車游戲的示例代碼
一、簡(jiǎn)介
此游戲是《2D 賽車》的”魔改版“——2.5D 雙人賽車!
原作實(shí)現(xiàn)了 2D 視角的賽車游戲,但是我覺得不夠真實(shí)、操縱感不強(qiáng),故擠出數(shù)個(gè)周末完成了這個(gè)”魔改版“,實(shí)現(xiàn)了第一人稱的視角。
二、如何建立一個(gè)地圖包
1. 選擇賽車,音樂,地圖的素材
2. 在程序的 map 文件夾下建立一個(gè)文件夾將這些素材放入
3. 建立 set.ini 文件
三、關(guān)于碰撞圖的繪制
碰撞圖色彩格式:
- 黑色(0xFFFFFF)為賽道,減速較小
- 黃色(0xFFFF00)為沙地,會(huì)減速
- 藍(lán)色(0x0000FF)為冰面,會(huì)滑動(dòng)
- 紅色(0xFF0000)為圍欄,無法通過
- 綠色(0xFFFFFF)為終點(diǎn)線
- 灰色(0xAAAAAA)為終點(diǎn)線的兩端,用于判定方向(對(duì)應(yīng)色值 RGB(170,170,170))
- 紫色(0xFF00FF)為玩家 2 起點(diǎn)
- 白色(0x000000)為玩家 1 起點(diǎn)
注意事項(xiàng):
終點(diǎn)線最好為寬度為一的直線!
灰色只有兩個(gè)像素點(diǎn),分布在終點(diǎn)線的兩端點(diǎn)
畫碰撞圖寧可把道路畫粗一點(diǎn),因?yàn)閷?shí)際游戲中可能會(huì)因?yàn)榕鲎矆D畫的太窄,導(dǎo)致玩家好像在路上但是被卡住了
此外,設(shè)置玩家起始位置也要考慮玩家車輛的長(zhǎng)度,如果玩家的起始位置離終點(diǎn)線太近,以至于玩家的車尾超過了終點(diǎn)線的話,那么開動(dòng)車子的時(shí)候就會(huì)觸發(fā)一次車子越過終點(diǎn)的判定。
四、游戲時(shí)的說明
- 上/W 向前開
- 下/S 倒車
- 左/A 左轉(zhuǎn)
- 右/D 右轉(zhuǎn)
如果卡在墻里就按住一個(gè)方向鍵加向前直到出去
五、如何更好地繪制賽場(chǎng)圖與碰撞圖
利用 PS 的自由路徑和描邊,一定要用鉛筆。
游戲截圖
六、實(shí)現(xiàn)代碼
#include <graphics.h> // 引用圖形庫(kù)頭文件 #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; // 轉(zhuǎn)動(dòng)速度的 -1 次方 int NeedR = 5; // 目標(biāo)圈數(shù) int WIDE = 1280; int HEIGHT = 960; double EndLineForward = 0; // 終點(diǎn)角度 bool inIce; bool inRoad; bool inSand; bool inWall; bool inEndline; IMAGE Racing; // 賽場(chǎng)地圖 IMAGE Toucher; // 碰撞圖 IMAGE car1; IMAGE car2; IMAGE Player1; int Px = 150; int Py = 150; double PForward = 0; // 方向 int Pspeed = 0; // 速度 int Ppass = 0; // 通過幾次終點(diǎn) bool Pwrong = false; // 是否逆行 bool PHadPass = false; // 是否通過終點(diǎn) bool PWaitOut = false; // 是否等待通過終點(diǎn) bool Pover = false; // 是否結(jié)束 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 // 簡(jiǎn)易的按鈕實(shí)現(xiàn) { 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) // 鼠標(biāo)區(qū)域判定 { 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() // 顯示并等待按鍵被響應(yīng),返回相應(yīng)的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 // 計(jì)時(shí)器 { 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); // 坐標(biāo)與數(shù)值的轉(zhuǎn)換 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(); // 清空緩沖區(qū) void restart(); // 用于重新開始游戲 bool CanRota (bool player);//是否可以旋轉(zhuǎn)
到此這篇關(guān)于C語言實(shí)現(xiàn)2D賽車游戲的示例代碼的文章就介紹到這了,更多相關(guān)C語言賽車游戲內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C++中為何推薦要把基類析構(gòu)函數(shù)設(shè)置成虛函數(shù)
這篇文章主要介紹了C++中為何推薦要把基類析構(gòu)函數(shù)設(shè)置成虛函數(shù)問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-12-12C語言報(bào)錯(cuò):Format String Vulnerability的多種解決方案
Format String Vulnerability(格式化字符串漏洞)是C語言中常見且嚴(yán)重的安全漏洞之一,它通常在程序使用不受信任的輸入作為格式化字符串時(shí)發(fā)生,本文將詳細(xì)介紹Format String Vulnerability的產(chǎn)生原因,提供多種解決方案,需要的朋友可以參考下2024-06-06C++ 實(shí)現(xiàn)優(yōu)先隊(duì)列的簡(jiǎn)單實(shí)例
這篇文章主要介紹了C++ 實(shí)現(xiàn)優(yōu)先隊(duì)列的簡(jiǎn)單實(shí)例的相關(guān)資料,希望通過本文能幫助大家實(shí)現(xiàn)優(yōu)先隊(duì)列,需要的朋友可以參考下2017-08-08C++如何計(jì)算結(jié)構(gòu)體與對(duì)象的大小
這篇文章主要給大家介紹了關(guān)于C++如何計(jì)算結(jié)構(gòu)體與對(duì)象大小的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-05-05詳解C++ 動(dòng)態(tài)庫(kù)導(dǎo)出函數(shù)名亂碼及解決
這篇文章主要介紹了C++ 動(dòng)態(tài)庫(kù)導(dǎo)出函數(shù)名亂碼及解決,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-03-03一文詳解C++關(guān)鍵字nullptr及與NULL的區(qū)別
這篇文章主要給大家詳細(xì)介紹了C++關(guān)鍵字nullptr,及?NULL與nullptr的區(qū)別,文中通過代碼示例介紹的非常詳細(xì),需要的朋友可以參考下2023-06-06