首先我們需要下載EasyX(具體的方法在EasyX專(zhuān)欄中有提到)
easyX下載和繪制簡(jiǎn)單基本圖形_小梁今天敲代碼了嗎的博客-CSDN博客
貪吃蛇這個(gè)游戲我們一定都玩過(guò),玩家使用方向鍵操控一條“蛇”,蛇會(huì)朝著一個(gè)方向不斷移動(dòng),玩家可以通過(guò)上下左右鍵改變其運(yùn)動(dòng)方向。同時(shí)屏幕上隨機(jī)會(huì)出現(xiàn)各種“食物”,玩家要控制蛇去吃掉這些食物,每吃掉一個(gè),蛇的身體就會(huì)增長(zhǎng)一節(jié)。
想要實(shí)現(xiàn)這個(gè)游戲,我們主要得考慮蛇和食物
蛇:
蛇的移動(dòng)方向如何實(shí)現(xiàn)
蛇的身體長(zhǎng)度如何實(shí)現(xiàn)增長(zhǎng)
食物:
食物如何隨機(jī)生成
下面我將代碼部分拆解做一個(gè)簡(jiǎn)單的說(shuō)明,后附源碼
首先是播放背景音樂(lè):
將音樂(lè)的mp3格式與代碼放在一個(gè)文件夾中,用以下函數(shù)調(diào)用:
#include<mmsystem.h>//頭文件
#pragma comment(lib,"winmm.lib")//庫(kù)文件
//播放音樂(lè) mci media control interface(多媒體設(shè)備接口)
//Send 發(fā)送 String字符串
//音樂(lè)需要放在程序同一文件目錄中
mciSendString("open 音樂(lè).mp3",0,0,0);
mciSendString("play 音樂(lè).mp3", 0, 0, 0);
?創(chuàng)建“精靈類(lèi)”,它是“蛇類(lèi)”和“食物類(lèi)”的父類(lèi)
這里難理解的地方是:碰撞檢測(cè)(我們?nèi)绾稳ヅ卸ㄉ吣艹缘绞澄铮窟@里采用的方法是當(dāng)蛇頭的左上方x,y坐標(biāo)完全與食物的左上方x,y坐標(biāo)相等時(shí),我們認(rèn)為蛇吃到了食物)
這個(gè)函數(shù)用于設(shè)置當(dāng)前設(shè)備填充顏色。
void setfillcolor(COLORREF color);
?
這個(gè)函數(shù)用于畫(huà)有邊框的填充矩形。
void fillrectangle(
int left,
int top,
int right,
int bottom
);
?
//精靈類(lèi)
class Sprite
{
public:
Sprite():Sprite(0,0) {};
Sprite(int x, int y) :m_x(x), m_y(y),m_color(RED) {};
//繪制精靈
virtual void draw()
{
//設(shè)置填充顏色
setfillcolor(m_color);
//繪制矩形
fillrectangle(m_x, m_y, m_x + 10, m_y + 10);
}
//移動(dòng)
void moveBy(int dx, int dy)
{
m_x += dx;
m_y += dy;
}
//碰撞檢測(cè)
bool collision(const Sprite& other)
{
return m_x == other.m_x && m_y == other.m_y;
}
protected:
int m_x;
int m_y;
COLORREF m_color;//顏色
};
蛇類(lèi)這里移動(dòng)時(shí),將上一個(gè)格子坐標(biāo)賦值給下一個(gè)格子,實(shí)現(xiàn)移動(dòng)
push_back()函數(shù)的用法
函數(shù)將一個(gè)新的元素加到vector的最后面,位置為當(dāng)前最后一個(gè)元素的下一個(gè)元素
//蛇類(lèi)
class Snake : public Sprite
{
public:
Snake():Snake(0,0) {}
Snake(int x,int y):Sprite(x,y),dir(VK_RIGHT)
{
//初始化三節(jié)蛇
nodes.push_back(Sprite(20, 0));
nodes.push_back(Sprite(10, 0));
nodes.push_back(Sprite(0, 0));
}
void draw() override
{
for (int i = 0; i < nodes.size(); i++)
{
nodes[i].draw();
}
}
//蛇的身體移動(dòng)
void bodyMove()
{
//身體跟著蛇頭移動(dòng)
for (size_t i = nodes.size()-1; i >0; i--)
{
nodes[i] = nodes[i - 1];
}
//移動(dòng)蛇頭
switch (dir)
{
case VK_UP:
nodes[0].moveBy(0,-10);
break;
case VK_DOWN:
nodes[0].moveBy(0,10);
break;
case VK_LEFT:
nodes[0].moveBy(-10, 0);
break;
case VK_RIGHT:
nodes[0].moveBy(10, 0);
break;
}
}
bool collision(const Sprite& other)
{
return nodes[0].collision(other);
}
//蛇增加一節(jié)
void incrment()
{
nodes.push_back(Sprite());
}
private:
//蛇只有一節(jié)嗎?
std::vector<Sprite> nodes;//蛇的所有節(jié)點(diǎn)
public:
int dir;//蛇的方向
};
?食物:
為了使程序在每次執(zhí)行時(shí)都能生成一個(gè)新序列的隨機(jī)值,我們通常通過(guò)為隨機(jī)數(shù)生成器提供一粒新的隨機(jī)種子。函數(shù)srand()可以為隨機(jī)數(shù)生成器播散種子。隨機(jī)生成食物時(shí),我們需要它的坐標(biāo)為10的整數(shù)倍,因?yàn)樯叩纳眢w我們?cè)O(shè)定的占10個(gè)像素,所以只能吃到坐標(biāo)為10的整數(shù)倍的食物
//食物
class Food :public Sprite
{
public:
Food() :Sprite(0, 0)
{
changePos();
}
void draw()override
{
setfillcolor(m_color)
;
solidellipse(m_x, m_y, m_x + 10, m_y + 10);
}
//改變食物的坐標(biāo)
void changePos()
{
//隨機(jī)生成坐標(biāo)
m_x = rand() % 64 * 10;
m_y = rand() % 48 * 10;
}
};
?游戲場(chǎng)景:
這里引用的函數(shù)是什么意思基本已經(jīng)在代碼中進(jìn)行了標(biāo)注
這里的switch代碼是在蛇的移動(dòng)過(guò)程中,讓它不能掉頭
switch (msg.vkcode)
{
case VK_UP:
if (snake.dir != VK_DOWN)
snake.dir = msg.vkcode;
break;
case VK_DOWN:
if (snake.dir != VK_UP)
snake.dir = msg.vkcode;
break;
case VK_LEFT:
if (snake.dir != VK_RIGHT)
snake.dir = msg.vkcode;
break;
case VK_RIGHT:
if (snake.dir != VK_LEFT)
snake.dir = msg.vkcode;
break;
}
?ExMessage這個(gè)結(jié)構(gòu)體用于保存鼠標(biāo)消息
WM_KEYDOWN | EX_KEY | 按鍵按下消息 |
BeginBatchDraw()這個(gè)函數(shù)用于開(kāi)始批量繪圖。執(zhí)行后,任何繪圖操作都將暫時(shí)不輸出到繪圖窗口上,直到執(zhí)行 FlushBatchDraw 或 EndBatchDraw 才將之前的繪圖輸出。
void BeginBatchDraw();
?
cleardevice()這個(gè)函數(shù)使用當(dāng)前背景色清空繪圖設(shè)備。
void cleardevice();
/*游戲場(chǎng)景*/
class GameScene
{
public:
GameScene()
{
};
void run()
{
BeginBatchDraw();//雙緩沖繪圖 防止屏幕閃爍
cleardevice();//清屏
snake.draw();
food.draw();
EndBatchDraw();
//移動(dòng)蛇,改變蛇的坐標(biāo)
snake.bodyMove();
snakeEatFood();
//獲取消息
ExMessage msg = { 0 };
while (peekmessage(&msg, EX_KEY))
{
onMsg(msg);
}
}
//改變蛇的移動(dòng)方向 獲取鍵盤(pán)按鍵 _getch()
//響應(yīng)消息:鼠標(biāo)消息 鍵盤(pán)消息
void onMsg(const ExMessage& msg)
{
//如果有鍵盤(pán)消息(有沒(méi)有按鍵按下)
if (msg.message == WM_KEYDOWN)
{
//判斷具體的是哪個(gè)按鍵按下 virtual key code 虛擬鍵碼
switch (msg.vkcode)
{
case VK_UP:
if (snake.dir != VK_DOWN)
snake.dir = msg.vkcode;
break;
case VK_DOWN:
if (snake.dir != VK_UP)
snake.dir = msg.vkcode;
break;
case VK_LEFT:
if (snake.dir != VK_RIGHT)
snake.dir = msg.vkcode;
break;
case VK_RIGHT:
if (snake.dir != VK_LEFT)
snake.dir = msg.vkcode;
break;
}
//std::cout << msg.vkcode << std::endl;
}
}
//判斷蛇能否吃到食物
void snakeEatFood()
{
if (snake.collision(food))//如果蛇和食物產(chǎn)生了碰撞
{
//蛇的節(jié)數(shù)增加
snake.incrment();
//食物重新產(chǎn)生在別的地方
food.changePos();
}
}
private:
Snake snake;
Food food;
};
?最后源碼如下:
#include<iostream>//標(biāo)準(zhǔn)輸入輸出頭文件
#include<graphics.h>
#include<mmsystem.h>
#pragma comment(lib,"winmm.lib")
#include<easyx.h>
#include<vector> //順序表
#include<ctime>
//精靈類(lèi)
class Sprite
{
public:
Sprite():Sprite(0,0) {};
Sprite(int x, int y) :m_x(x), m_y(y),m_color(RED) {};
//繪制精靈
virtual void draw()
{
//設(shè)置填充顏色
setfillcolor(m_color);
//繪制矩形
fillrectangle(m_x, m_y, m_x + 10, m_y + 10);
}
//移動(dòng)
void moveBy(int dx, int dy)
{
m_x += dx;
m_y += dy;
}
//碰撞檢測(cè)
bool collision(const Sprite& other)
{
return m_x == other.m_x && m_y == other.m_y;
}
protected:
int m_x;
int m_y;
COLORREF m_color;//顏色
};
//蛇類(lèi)
class Snake : public Sprite
{
public:
Snake():Snake(0,0) {}
Snake(int x,int y):Sprite(x,y),dir(VK_RIGHT)
{
//初始化三節(jié)蛇
nodes.push_back(Sprite(20, 0));
nodes.push_back(Sprite(10, 0));
nodes.push_back(Sprite(0, 0));
}
void draw() override
{
for (int i = 0; i < nodes.size(); i++)
{
nodes[i].draw();
}
}
//蛇的身體移動(dòng)
void bodyMove()
{
//身體跟著蛇頭移動(dòng)
for (size_t i = nodes.size()-1; i >0; i--)
{
nodes[i] = nodes[i - 1];
}
//移動(dòng)蛇頭
switch (dir)
{
case VK_UP:
nodes[0].moveBy(0,-10);
break;
case VK_DOWN:
nodes[0].moveBy(0,10);
break;
case VK_LEFT:
nodes[0].moveBy(-10, 0);
break;
case VK_RIGHT:
nodes[0].moveBy(10, 0);
break;
}
}
bool collision(const Sprite& other)
{
return nodes[0].collision(other);
}
//蛇增加一節(jié)
void incrment()
{
nodes.push_back(Sprite());
}
private:
//蛇只有一節(jié)嗎?
std::vector<Sprite> nodes;//蛇的所有節(jié)點(diǎn)
public:
int dir;//蛇的方向
};
//食物
class Food :public Sprite
{
public:
Food() :Sprite(0, 0)
{
changePos();
}
void draw()override
{
setfillcolor(m_color)
;
solidellipse(m_x, m_y, m_x + 10, m_y + 10);
}
//改變食物的坐標(biāo)
void changePos()
{
//隨機(jī)生成坐標(biāo)
m_x = rand() % 64 * 10;
m_y = rand() % 48 * 10;
}
};
/*游戲場(chǎng)景*/
class GameScene
{
public:
GameScene()
{
};
void run()
{
BeginBatchDraw();//雙緩沖繪圖 防止屏幕閃爍
cleardevice();//清屏
snake.draw();
food.draw();
EndBatchDraw();
//移動(dòng)蛇,改變蛇的坐標(biāo)
snake.bodyMove();
snakeEatFood();
//獲取消息
ExMessage msg = { 0 };
while (peekmessage(&msg, EX_KEY))
{
onMsg(msg);
}
}
//改變蛇的移動(dòng)方向 獲取鍵盤(pán)按鍵 _getch()
//響應(yīng)消息:鼠標(biāo)消息 鍵盤(pán)消息
void onMsg(const ExMessage& msg)
{
//如果有鍵盤(pán)消息(有沒(méi)有按鍵按下)
if (msg.message == WM_KEYDOWN)
{
//判斷具體的是哪個(gè)按鍵按下 virtual key code 虛擬鍵碼
switch (msg.vkcode)
{
case VK_UP:
if (snake.dir != VK_DOWN)
snake.dir = msg.vkcode;
break;
case VK_DOWN:
if (snake.dir != VK_UP)
snake.dir = msg.vkcode;
break;
case VK_LEFT:
if (snake.dir != VK_RIGHT)
snake.dir = msg.vkcode;
break;
case VK_RIGHT:
if (snake.dir != VK_LEFT)
snake.dir = msg.vkcode;
break;
}
//std::cout << msg.vkcode << std::endl;
}
}
//判斷蛇能否吃到食物
void snakeEatFood()
{
if (snake.collision(food))//如果蛇和食物產(chǎn)生了碰撞
{
//蛇的節(jié)數(shù)增加
snake.incrment();
//食物重新產(chǎn)生在別的地方
food.changePos();
}
}
private:
Snake snake;
Food food;
};
int main()
{
//初始化窗口界面
initgraph(640,480,EW_SHOWCONSOLE);
GameScene scene;
scene.run();
//設(shè)置隨機(jī)數(shù)種子
srand(time(nullptr));
//播放音樂(lè) mci media control interface(多媒體設(shè)備接口)
//Send 發(fā)送 String字符串
mciSendString("open 音樂(lè).mp3",0,0,0);
mciSendString("play 音樂(lè).mp3", 0, 0, 0);
Snake snake;
snake.draw();
while (true)
{
scene.run();
Sleep(100);
}
getchar();//防止程序閃退
return 0;
}
文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-426909.html
至此我們就實(shí)現(xiàn)了簡(jiǎn)單的貪吃蛇游戲,它可以上下左右移動(dòng),并在吃到食物后增長(zhǎng)一格身體文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-426909.html
到了這里,關(guān)于貪吃蛇小游戲(C++)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!