利用C/C++實現(xiàn)貪吃蛇游戲
利用C/C++實現(xiàn)貪吃蛇
(注意:本文章僅供參考,第一次寫博客還請多多指教。理解本文章需要easyx和c++等基礎知識,并且需要了解貪吃蛇游戲機制)
貪吃蛇機制介紹
相信絕大多數(shù)人都曾玩過或者了解過貪吃蛇這款經典的游戲。貪吃蛇顧名思義,就是讓蛇盡可能的吃食物。玩家可通過方向鍵或自定義鍵來控制蛇頭的方向,使它吃到地圖出現(xiàn)的隨機食物。蛇每吃到一個食物,自身便會增長。當蛇碰到地圖的邊界或是蛇碰到自身,蛇便會死亡,游戲便結束。
機制大概了解過后,我們將考慮如何實現(xiàn)這類游戲。
設計與分析
首先,我們分析游戲整體結構大概由四個部分構成——界面、地圖、蛇、食物。
1、界面:界面能夠方便玩家的使用,可讓玩家自行選擇游戲的開始或結束;通過界面,我們可以設定一些有趣的東西來增加玩家的游戲體驗,例如:讓玩家選擇蛇的速度,以靈活調節(jié)游戲難度。
2、地圖:地圖能為蛇提供活動空間,同時也是蛇位置的坐標軸,方便定位。
3、蛇:蛇是游戲的靈魂。蛇可以定義如下屬性:坐標、方向、速度、長度。蛇。蛇的行為有:移動、吃食物、死亡。
4、食物:食物在地圖中隨機分布,具有坐標(可以嘗試去增加顏色屬性、大小屬性,本文章由于篇幅有限,暫不提供)。
思維導圖如下

首先設計用戶界面
//部分函數(shù)可以暫時不用考慮
void menu()
{
initgraph(640, 480);
int flag = 1;
while (flag)
{
cleardevice();
outtextxy(280, 180, "貪吃蛇游戲");
outtextxy(280, 200, "按1開始游戲");
outtextxy(280, 220, "按2結束游戲");
//接受輸入指令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;
}
//結束
case '2':
flag = 0;
break;
default :
break;
}
}
closegraph();
}
接下來可以通過結構體來定義蛇和食物
typedef struct Snake {
int speed = 0;//速度
pair<int, int> coor[MAXSIZE]={};//坐標(x, y)
int dir;//方向
int length;//長度
};
typedef struct food {
pair<int, int> place[MAXSIZE] = {};//坐標
int score;//分數(shù)
};
接下來將食物和蛇進行初始化
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;
//先給出3節(jié)身體
for (int i = 0; i < 3; i++)
{
S.coor[i].first = 40 - i * 10;
S.coor[i].second = 30;
}
}
再接著設計蛇速度控制函數(shù)
void control_speed(int &speed)
{
cleardevice();
outtextxy(280, 180, "請選擇蛇的速度1-5");
char ch = _getch();
speed = ch - '0';
}
最關鍵的蛇運動機制設計來了,我將分段講解
1、繪制蛇(蛇將有一系列正方體塊組成)
for (int i = 0; i < S.length; i++)
{
int x = S.coor[i].first;
int y = S.coor[i].second;
//蛇頭設為綠色,方便區(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、繪制食物(食物由單個正方體組成)
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、蛇的運動
像人的運動是通過腳向前邁步來制動整個軀干一樣,蛇頭同樣驅動整個身體。也就是說我們只要控制蛇頭的運動方向及前進,軀干便會跟著蛇頭一起移動。蛇軀干的每個節(jié)點只需要繼承上一個節(jié)點的位置即可。
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;
}
}
4、蛇運動控制
使用方向鍵改變蛇頭的運動方向即可
void control_dir(int& DIR)
{
char ch = _getch();
switch (ch)
{
case 72:
case 'W':
case 'w':
//這里用if主要是因為蛇運動的機制:當蛇在一某方向運動的途中,不能直接往反方向運動(這樣會導致蛇身體重疊),只能通過以當前運動方向為正方向,進行左右移動來改變方向。
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、吃食物
吃完食物的結果:出現(xiàn)下一個食物、蛇變長
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、判斷是否死亡
死亡判斷有兩種結果: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;
}
}
蛇的運動機制設計基本大功告成,可以自行在地圖上進行修飾,像加入分數(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, "請選擇蛇的速度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結束游戲");
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;
}

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。
相關文章
C++實現(xiàn)LeetCode(241.添加括號的不同方式)
這篇文章主要介紹了C++實現(xiàn)LeetCode(241.添加括號的不同方式),本篇文章通過簡要的案例,講解了該項技術的了解與使用,以下就是詳細內容,需要的朋友可以參考下2021-07-07
visual?studio?2022?編譯出來的文件被刪除并監(jiān)視目錄中的文件變更(示例詳解)
這篇文章主要介紹了visual?studio?2022?編譯出來的文件被刪除?并監(jiān)視目錄中的文件變更,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2022-08-08

