利用C/C++實(shí)現(xiàn)貪吃蛇游戲
利用C/C++實(shí)現(xiàn)貪吃蛇
(注意:本文章僅供參考,第一次寫博客還請(qǐng)多多指教。理解本文章需要easyx和c++等基礎(chǔ)知識(shí),并且需要了解貪吃蛇游戲機(jī)制)
貪吃蛇機(jī)制介紹
相信絕大多數(shù)人都曾玩過或者了解過貪吃蛇這款經(jīng)典的游戲。貪吃蛇顧名思義,就是讓蛇盡可能的吃食物。玩家可通過方向鍵或自定義鍵來控制蛇頭的方向,使它吃到地圖出現(xiàn)的隨機(jī)食物。蛇每吃到一個(gè)食物,自身便會(huì)增長(zhǎng)。當(dāng)蛇碰到地圖的邊界或是蛇碰到自身,蛇便會(huì)死亡,游戲便結(jié)束。
機(jī)制大概了解過后,我們將考慮如何實(shí)現(xiàn)這類游戲。
設(shè)計(jì)與分析
首先,我們分析游戲整體結(jié)構(gòu)大概由四個(gè)部分構(gòu)成——界面、地圖、蛇、食物。
1、界面:界面能夠方便玩家的使用,可讓玩家自行選擇游戲的開始或結(jié)束;通過界面,我們可以設(shè)定一些有趣的東西來增加玩家的游戲體驗(yàn),例如:讓玩家選擇蛇的速度,以靈活調(diào)節(jié)游戲難度。
2、地圖:地圖能為蛇提供活動(dòng)空間,同時(shí)也是蛇位置的坐標(biāo)軸,方便定位。
3、蛇:蛇是游戲的靈魂。蛇可以定義如下屬性:坐標(biāo)、方向、速度、長(zhǎng)度。蛇。蛇的行為有:移動(dòng)、吃食物、死亡。
4、食物:食物在地圖中隨機(jī)分布,具有坐標(biāo)(可以嘗試去增加顏色屬性、大小屬性,本文章由于篇幅有限,暫不提供)。
思維導(dǎo)圖如下
首先設(shè)計(jì)用戶界面
//部分函數(shù)可以暫時(shí)不用考慮 void menu() { initgraph(640, 480); int flag = 1; while (flag) { cleardevice(); outtextxy(280, 180, "貪吃蛇游戲"); outtextxy(280, 200, "按1開始游戲"); outtextxy(280, 220, "按2結(jié)束游戲"); //接受輸入指令0、1 char ch = _getch(); switch (ch) { //開始 case '1': { food F; Initfood(F);//食物初始化 Snake S; hatch(S);//蛇初始化 control_speed(S.speed);//蛇速度控制函數(shù) drawsnake(S, F);//開始繪制游戲面板 break; } //結(jié)束 case '2': flag = 0; break; default : break; } } closegraph(); }
接下來可以通過結(jié)構(gòu)體來定義蛇和食物
typedef struct Snake { int speed = 0;//速度 pair<int, int> coor[MAXSIZE]={};//坐標(biāo)(x, y) int dir;//方向 int length;//長(zhǎng)度 }; typedef struct food { pair<int, int> place[MAXSIZE] = {};//坐標(biāo) int score;//分?jǐn)?shù) };
接下來將食物和蛇進(jìn)行初始化
void Initfood(food& F) { F.score = 0; srand(time(NULL)); //將食物坐標(biāo)隨機(jī)設(shè)置 for (int i = 0; i < 100; i++) { F.place[i].first = rand() % (640 - R) + R; F.place[i].second = rand() % (480 - R) + R; } } void hatch(Snake &S) { S.length = 3; S.dir = 2; S.speed = 0; //先給出3節(jié)身體 for (int i = 0; i < 3; i++) { S.coor[i].first = 40 - i * 10; S.coor[i].second = 30; } }
再接著設(shè)計(jì)蛇速度控制函數(shù)
void control_speed(int &speed) { cleardevice(); outtextxy(280, 180, "請(qǐng)選擇蛇的速度1-5"); char ch = _getch(); speed = ch - '0'; }
最關(guān)鍵的蛇運(yùn)動(dòng)機(jī)制設(shè)計(jì)來了,我將分段講解
1、繪制蛇(蛇將有一系列正方體塊組成)
for (int i = 0; i < S.length; i++) { int x = S.coor[i].first; int y = S.coor[i].second; //蛇頭設(shè)為綠色,方便區(qū)分 if (i == 0) { setfillcolor(GREEN); solidrectangle(x - R, y - R, x + R, y + R); } else { setcolor(WHITE); rectangle(x - R, y - R, x + R, y + R); }
2、繪制食物(食物由單個(gè)正方體組成)
int m = F.place[F.score].first; int n = F.place[F.score].second; setfillcolor(WHITE); solidrectangle(m-R, n-R, m+R, n+R);
3、蛇的運(yùn)動(dòng)
像人的運(yùn)動(dòng)是通過腳向前邁步來制動(dòng)整個(gè)軀干一樣,蛇頭同樣驅(qū)動(dòng)整個(gè)身體。也就是說我們只要控制蛇頭的運(yùn)動(dòng)方向及前進(jìn),軀干便會(huì)跟著蛇頭一起移動(dòng)。蛇軀干的每個(gè)節(jié)點(diǎn)只需要繼承上一個(gè)節(jié)點(diǎn)的位置即可。
void movesnake(Snake& S) { //繼承坐標(biāo) for (int i = S.length - 1; i > 0; i--) { S.coor[i].first = S.coor[i - 1].first; S.coor[i].second = S.coor[i - 1].second; } switch (S.dir) { case 1: S.coor[0].second-= 10; break; case 2: S.coor[0].first+=10; break; case 3: S.coor[0].second+=10; break; case 4: S.coor[0].first-=10; break; default: break; } }
4、蛇運(yùn)動(dòng)控制
使用方向鍵改變蛇頭的運(yùn)動(dòng)方向即可
void control_dir(int& DIR) { char ch = _getch(); switch (ch) { case 72: case 'W': case 'w': //這里用if主要是因?yàn)樯哌\(yùn)動(dòng)的機(jī)制:當(dāng)蛇在一某方向運(yùn)動(dòng)的途中,不能直接往反方向運(yùn)動(dòng)(這樣會(huì)導(dǎo)致蛇身體重疊),只能通過以當(dāng)前運(yùn)動(dòng)方向?yàn)檎较?,進(jìn)行左右移動(dòng)來改變方向。 if (DIR != 3) DIR = 1; break; case 77: case 'D': case 'd': if (DIR != 4) DIR = 2; break; case 80: case 'S': case 's': if (DIR != 1) DIR = 3; break; case 75: case 'A': case 'a': if (DIR != 2) DIR = 4; break; default: break; } }
4、吃食物
吃完食物的結(jié)果:出現(xiàn)下一個(gè)食物、蛇變長(zhǎng)
void Eating(Snake& S, food& F) { if (S.coor[0].first >= F.place[F.score].first - R&& S.coor[0].first <= F.place[F.score].first + R && S.coor[0].second >= F.place[F.score].second -R&& S.coor[0].second <= F.place[F.score].second+R) { F.score++; S.length++; } }
5、判斷是否死亡
死亡判斷有兩種結(jié)果:1、碰壁。2、自身形成回路(自己咬自己)
int isdead(Snake S) { if (S.coor[0].first > 640-R || S.coor[0].first < R || S.coor[0].second>480-R || S.coor[0].second<=R) return 1; else { for (int i = 4; i < S.length; i++) { if (S.coor[0].first >= S.coor[i].first-R&& S.coor[0].first <= S.coor[i].first + R && S.coor[0].second >= S.coor[i].second-R&& S.coor[0].second <= S.coor[i].second+R) return 1; } return 0; } }
蛇的運(yùn)動(dòng)機(jī)制設(shè)計(jì)基本大功告成,可以自行在地圖上進(jìn)行修飾,像加入分?jǐn)?shù)欄
void control_dir(int& DIR) { char ch = _getch(); switch (ch) { case 72: case 'W': case 'w': if (DIR != 3) DIR = 1; break; case 77: case 'D': case 'd': if (DIR != 4) DIR = 2; break; case 80: case 'S': case 's': if (DIR != 1) DIR = 3; break; case 75: case 'A': case 'a': if (DIR != 2) DIR = 4; break; default: break; } } void movesnake(Snake& S) { for (int i = S.length - 1; i > 0; i--) { S.coor[i].first = S.coor[i - 1].first; S.coor[i].second = S.coor[i - 1].second; } switch (S.dir) { case 1: S.coor[0].second-= 10; break; case 2: S.coor[0].first+=10; break; case 3: S.coor[0].second+=10; break; case 4: S.coor[0].first-=10; break; default: break; } } int isdead(Snake S) { if (S.coor[0].first > 640-R || S.coor[0].first < R || S.coor[0].second>480-R || S.coor[0].second<=R) return 1; else { for (int i = 4; i < S.length; i++) { if (S.coor[0].first >= S.coor[i].first-R&& S.coor[0].first <= S.coor[i].first + R && S.coor[0].second >= S.coor[i].second-R&& S.coor[0].second <= S.coor[i].second+R) return 1; } return 0; } } void Eating(Snake& S, food& F) { if (S.coor[0].first >= F.place[F.score].first - R&& S.coor[0].first <= F.place[F.score].first + R && S.coor[0].second >= F.place[F.score].second -R&& S.coor[0].second <= F.place[F.score].second+R) { F.score++; S.length++; } } void drawsnake(Snake& S, food F) { char out[3] = {}; BeginBatchDraw(); while (1) { cleardevice(); for (int i = 0; i < S.length; i++) { int x = S.coor[i].first; int y = S.coor[i].second; if (i == 0) { setfillcolor(GREEN); solidrectangle(x - R, y - R, x + R, y + R); } else { setcolor(WHITE); rectangle(x - R, y - R, x + R, y + R); } } int m = F.place[F.score].first; int n = F.place[F.score].second; setfillcolor(WHITE); solidrectangle(m-R, n-R, m+R, n+R); sprintf_s(out, "%d", F.score * S.speed); setbkmode(0); outtextxy(570, 20, "得分"); outtextxy(620, 20, out); FlushBatchDraw(); Sleep(200-S.speed*30); while(_kbhit()) { control_dir(S.dir); } movesnake(S); Eating(S, F); if (isdead(S)) break; } cleardevice(); sprintf_s(out, "%d", F.score * S.speed); outtextxy(280, 180, "得分"); outtextxy(320, 180, out); outtextxy(280, 200, "按Enter鍵繼續(xù)"); FlushBatchDraw(); getchar(); EndBatchDraw(); }
完整代碼如下
#include <iostream> #include <graphics.h> #include <conio.h> #include <time.h> using namespace std; #define MAXSIZE 100 #define R 5 typedef struct Snake { int speed = 0;//速度 pair<int, int> coor[MAXSIZE]={}; int dir = 2; int length = 3; }; typedef struct food { pair<int, int> place[MAXSIZE] = {}; int score; }; void Initfood(food& F) { F.score = 0; srand(time(NULL)); for (int i = 0; i < 100; i++) { F.place[i].first = rand() % (640 - R) + R; F.place[i].second = rand() % (480 - R) + R; } } void hatch(Snake &S) { S.length = 3; S.dir = 2; S.speed = 0; for (int i = 0; i < 3; i++) { S.coor[i].first = 40 - i * 10; S.coor[i].second = 30; } } void control_speed(int &speed) { cleardevice(); outtextxy(280, 180, "請(qǐng)選擇蛇的速度1-5"); char ch = _getch(); speed = ch - '0'; } void control_dir(int& DIR) { char ch = _getch(); switch (ch) { case 72: case 'W': case 'w': if (DIR != 3) DIR = 1; break; case 77: case 'D': case 'd': if (DIR != 4) DIR = 2; break; case 80: case 'S': case 's': if (DIR != 1) DIR = 3; break; case 75: case 'A': case 'a': if (DIR != 2) DIR = 4; break; default: break; } } void movesnake(Snake& S) { for (int i = S.length - 1; i > 0; i--) { S.coor[i].first = S.coor[i - 1].first; S.coor[i].second = S.coor[i - 1].second; } switch (S.dir) { case 1: S.coor[0].second-= 10; break; case 2: S.coor[0].first+=10; break; case 3: S.coor[0].second+=10; break; case 4: S.coor[0].first-=10; break; default: break; } } int isdead(Snake S) { if (S.coor[0].first > 640-R || S.coor[0].first < R || S.coor[0].second>480-R || S.coor[0].second<=R) return 1; else { for (int i = 4; i < S.length; i++) { if (S.coor[0].first >= S.coor[i].first-R&& S.coor[0].first <= S.coor[i].first + R && S.coor[0].second >= S.coor[i].second-R&& S.coor[0].second <= S.coor[i].second+R) return 1; } return 0; } } void Eating(Snake& S, food& F) { if (S.coor[0].first >= F.place[F.score].first - R&& S.coor[0].first <= F.place[F.score].first + R && S.coor[0].second >= F.place[F.score].second -R&& S.coor[0].second <= F.place[F.score].second+R) { F.score++; S.length++; } } void drawsnake(Snake& S, food F) { char out[3] = {}; BeginBatchDraw(); while (1) { cleardevice(); for (int i = 0; i < S.length; i++) { int x = S.coor[i].first; int y = S.coor[i].second; if (i == 0) { setfillcolor(GREEN); solidrectangle(x - R, y - R, x + R, y + R); } else { setcolor(WHITE); rectangle(x - R, y - R, x + R, y + R); } } int m = F.place[F.score].first; int n = F.place[F.score].second; setfillcolor(WHITE); solidrectangle(m-R, n-R, m+R, n+R); sprintf_s(out, "%d", F.score * S.speed); setbkmode(0); outtextxy(570, 20, "得分"); outtextxy(620, 20, out); FlushBatchDraw(); Sleep(200-S.speed*30); while(_kbhit()) { control_dir(S.dir); } movesnake(S); Eating(S, F); if (isdead(S)) break; } cleardevice(); sprintf_s(out, "%d", F.score * S.speed); outtextxy(280, 180, "得分"); outtextxy(320, 180, out); outtextxy(280, 200, "按Enter鍵繼續(xù)"); FlushBatchDraw(); getchar(); EndBatchDraw(); } void menu() { initgraph(640, 480); int flag = 1; while (flag) { cleardevice(); outtextxy(280, 180, "貪吃蛇游戲"); outtextxy(280, 200, "按1開始游戲"); outtextxy(280, 220, "按2結(jié)束游戲"); char ch = _getch(); switch (ch) { case '1': { food F; Initfood(F); Snake S; hatch(S); control_speed(S.speed); drawsnake(S, F); break; } case '2': flag = 0; break; default : break; } } closegraph(); } int main(void) { menu(); return 0; }
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- C++ 情懷游戲貪吃蛇的實(shí)現(xiàn)流程詳解
- C++入門指南之貪吃蛇游戲的實(shí)現(xiàn)
- C++實(shí)現(xiàn)簡(jiǎn)易貪吃蛇游戲
- C++實(shí)現(xiàn)簡(jiǎn)單貪吃蛇小游戲
- C++實(shí)現(xiàn)貪吃蛇游戲
- C++代碼實(shí)現(xiàn)貪吃蛇小游戲
- 基于easyx的C++實(shí)現(xiàn)貪吃蛇
- C++控制臺(tái)循環(huán)鏈表實(shí)現(xiàn)貪吃蛇
- C++控制臺(tái)實(shí)現(xiàn)貪吃蛇游戲
- C++通過類實(shí)現(xiàn)控制臺(tái)貪吃蛇
- C++結(jié)構(gòu)體數(shù)組實(shí)現(xiàn)貪吃蛇
- c++實(shí)現(xiàn)超簡(jiǎn)單的貪吃蛇游戲?qū)嵗榻B
相關(guān)文章
C++實(shí)現(xiàn)LeetCode(241.添加括號(hào)的不同方式)
這篇文章主要介紹了C++實(shí)現(xiàn)LeetCode(241.添加括號(hào)的不同方式),本篇文章通過簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-07-07C語言基礎(chǔ)知識(shí)變量的作用域和存儲(chǔ)方式詳細(xì)介紹
這篇文章主要介紹了C語言基礎(chǔ)知識(shí)變量的作用域和存儲(chǔ)方式詳細(xì)介紹的相關(guān)資料,需要的朋友可以參考下2017-01-01visual?studio?2022?編譯出來的文件被刪除并監(jiān)視目錄中的文件變更(示例詳解)
這篇文章主要介紹了visual?studio?2022?編譯出來的文件被刪除?并監(jiān)視目錄中的文件變更,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-08-08C語言實(shí)現(xiàn)文本文件/二進(jìn)制文件格式互換
這篇文章主要為大家詳細(xì)介紹了C語言實(shí)現(xiàn)文本文件和二進(jìn)制文件格式互換,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-03-03