当前位置:网站首页>C實現貪吃蛇小遊戲
C實現貪吃蛇小遊戲
2022-07-04 06:03:00 【浪雨123】
貪吃蛇小遊戲可以說是很多小夥伴的遊戲啟蒙之物,今天我們一起來用C語言複刻童年經典遊戲貪吃蛇,在編寫這個遊戲之前,需要了解一些easyx圖形庫的知識,因為遊戲的窗口就是靠此來提供。
這篇文章主要介紹編寫這個遊戲要實現的功能,另外我會再寫一篇關於這個遊戲常見的一些BUG及其解决辦法,如果已經能完成部分的編寫,而困於某些BUG的夥伴可以移步另一篇文章,可能會有你遇到的一些BUG。
實現貪吃蛇遊戲,首先我們需要設置一個遊戲窗口,利用easyx圖形庫,設置一個經典的640*480大小的窗口。窗口設定好了,接下來就可以定義蛇了,我們用結構體來定義蛇的類型,分析一下蛇需要用到那些數據,我們首先需要知道這個蛇有多長,便於遊戲開始時蛇的長度設定,及遊戲結束後蛇長的統計,那我們就用 int n 來錶示蛇的長度。蛇在移動過程中是要有一個移動方向的,因此我們也需要設置一個int direction 來錶示蛇移動的方向,因為方向就四個,我們幹脆就把四個方向枚舉出來,然後蛇的移動方向就用枚舉變量來錶示
//枚舉方向
enum direction
{
up = 72,
down = 80,
left = 75,
right = 77
};
其次我們需要知道蛇的每一節身體的坐標,這樣我們通過坐標來讓蛇移動,以及把蛇繪制到窗口上,因為蛇的身體有很多節,坐標又有x , y兩個值。我們就把坐標單獨定義為結構體,然後身體的每一節都對應著一個坐標,我們用數組來錶示身體
//定義蛇的坐標
struct coor
{
int x;
int y;
}coor;
最終蛇的定義如下
//定義蛇的數據類型
struct snake
{
int n = 3;
direction site;
coor szb[NUM];
}snake;
//其中NUM是該數組的最大值即蛇的身體最長長度,自行定義
定義完蛇的類型,接下來我們就把蛇初始化以下,寫一個初始化函數, initsnake() 假設蛇剛開始長度為3, 方向向左, 坐標依次為
snake.n = 3;
snake.site = left;
snake.szb[0].x = 320;
snake.szb[0].y = 240;
snake.szb[1].x = 310;
snake.szb[1].y = 240;
snake.szb[2].x = 300;
snake.szb[2].y = 240;
初始化完成後,我們就把蛇繪制到窗口上,寫一個 Drawsnake() 函數,其實就是一個循環,以蛇的長度為判定條件,從蛇頭的坐標開始依次繪制,畫矩形或者圓都可,這裏我用的是矩形
void Drawsnake()
{
for (int i = 0; i < snake.n; i++)
{
rectangle(snake.szb[i].x, snake.szb[i].y, snake.szb[i].x+10, snake.szb[i].y+10);
}
}
繪制完成之後,接下來就要讓蛇動起來了,這點很關鍵,如何實現讓蛇動起來,分析可知,蛇移動的原理是讓蛇頭的坐標朝向某個方向不斷的改變,身體再跟著蛇頭一起改變,坐標每變換一次就重新繪制蛇的身體,因為這個過程足够快,我們將其處理的速度用Sleep()再延緩一點,就能形成我們眼睛所能識別的幀率,從而看著蛇是連續移動的。既然要不斷的變換蛇頭的坐標,並且重新繪制蛇的身體,那就要將這兩個函數放到循環裏面,蛇的移動我們編寫一個Movesnake()。
int main()
{
initgraph(640, 480);
initgame();
while (ture)
{
cleardevice();
Movesnake();
Drawsnake();
Sleep(100);
}
}
那麼如何讓蛇的坐標不斷朝著某個方向改變呢?接下來我們就仔細解决Movesnake(),首先我們要判斷具體往哪個方向移動,還記得在定義蛇的時候,設置了一個方向變量site嘛,現在它派上用場了。我們在初始化的時候,將這個變量初始化向左移動,然後程序將蛇頭坐標的x减少10,即向左改變了10個像素點,因為在循環裏,只要site的值不變,蛇頭就一直向左移動,第二節身體的坐標移動到原先蛇頭的比特置,其他節身體的坐標依次移動到它上一節身體的坐標處,這樣就實現了蛇的移動,別忘了加上一個cleardevice()函數,清除上一次繪制的圖形。
switch (snake.site)
{
case up:
snake.szb[0].y-=10;
break;
case down:
snake.szb[0].y+=10;
break;
case left:
snake.szb[0].x-=10;
break;
case right:
snake.szb[0].x+=10;
break;
}
for (int i = snake.n - 1; i > 0; i--) //將蛇的每一節身體的坐標替換成上一節身體的坐標
{
snake.szb[i].x = snake.szb[i - 1].x;
snake.szb[i].y = snake.szb[i - 1].y;
}
蛇的移動完成之後,接下來就是蛇在移動的時候,方向的改變,如果不讓蛇的方向改變,那也沒法玩呢,首先我們只有在按下方向鍵的時候蛇頭的方向才會改變,那就先設置一個變量用來接收我們按下的方向鍵,然後再把這個方向鍵賦值給蛇頭的方向變量,我們就編寫一個Chdirection()函數來實現
void Chdirection()
{
char key;
key = _getch();
switch(key)
{
case up:
if (snake.site != down)
{
snake.site = up;
}
break;
case down:
if (snake.site != up)
{
snake.site = down;
}
break;
case left:
if (snake.site != right)
{
snake.site = left;
}
break;
case right:
if (snake.site != left)
{
snake.site = right;
}
break;
}
}
這裏為什麼要在每一個分支後面加上 if 判斷語句呢,其實就是為了防止蛇直接就調頭了,這和現實是不符的,顯示中的掉頭要繞圈子的。
其實,直接掉頭也是可以的,還蠻有意思的,像火車一樣兩頭開,哈哈,感興趣可以試試。
轉向的問題搞定了,但是程序怎麼知道什麼時候轉向呢?因為這個程序是放在循環裏的,我們不妨加一個判斷語句,用kbhit()函數來檢測玩家是否按下了按鍵,如果按下了就返回真值,進入轉向函數,並在其內部判斷該轉向哪裏,沒有按下就為假,不進入轉向函數。
int main()
{
initgraph(640, 480);
initgame();
while (ture)
{
cleardevice();
Movesnake();
Drawsnake();
Sleep(100);
if ( kbhit() )
{
Chdirection();
}
}
}
小蛇能跑起來了,接下就是吃食物了,那吃食物的效果又該如何實現呢?同樣,我們要給食物定義一個數據類型,首先就是食物的坐標,其次是食物此刻的狀態,是被吃了還是沒被吃,狀態我們就用bool變量
//定義食物的數據類型
struct food
{
int x;
int y;
bool state;
}food;
接著我們回到初始化函數處,給第一個食物的狀態設定一下,定義為true,錶示被吃了,為何設定為被吃了,等會解釋,我們接著編寫Createfood(),用來創造食物,就是給食物的坐標附上隨機值,隨機值就用隨機值生成種子,一旦我們創建一個食物,那創建的瞬間,需要將食物的狀態改成false,錶示未被吃。
void Creatfood()
{
while (1)
{
food.x = rand() % 62 * 10;
food.y = rand() % 46 * 10;
if (food.x >= 20 && food.y >= 20)
{
food.state = false;
break;
}
}
}
//這裏我加循環是不想讓食物生成到邊界點
那麼什麼時候生成食物呢,那當然是食物的狀態為true錶示被吃了的時候,這也是為什麼我們要在開頭處將食物的狀態設置為true,就是為了開局就生成一個食物。同樣要用到一個判斷語句
int main()
{
initgraph(LENGTH, WIDTH);
initgame();
while (1)
{
if (food.state)
{
Creatfood();
}
cleardevice();
Movesnake();
Drawsnake();
Drawfood();
Sleep(100);
EndBatchDraw();
if (_kbhit())
{
Chdirection();
}
}
食物創建好了,現在就剩下最後一步了,那就是實現吃的過程,就編寫個Eatfood(),當蛇頭的坐標與食物的坐標重合時就可以吃了,然後食物的狀態改為true,蛇的身長加1.
void Eatfood()
{
if (snake.szb[0].x == food.x && snake.szb[0].y == food.y)
{
snake.n++;
food.state = true;
}
}
就這樣,簡易的貪吃蛇就完成了,還有一個繪制食物,這個蠻簡單的,各比特夥伴自己實現吧。
int main()
{
initgraph(LENGTH, WIDTH);
initgame();
while (1)
{
if (food.state)
{
Creatfood();
}
cleardevice();
Movesnake();
Drawsnake();
Drawfood();
Eatfood();
Sleep(100);
if (_kbhit())
{
Chdirection();
}
}
getchar();
}
边栏推荐
- BeanFactoryPostProcessor 与 BeanPostProcessor 相关子类概述
- win10清除快速访问-不留下痕迹
- HMS v1.0 appointment. PHP editid parameter SQL injection vulnerability (cve-2022-25491)
- Detectron: train your own data set -- convert your own data format to coco format
- 746. Climb stairs with minimum cost
- 【无标题】
- (4) Canal multi instance use
- 每周小结(*63):关于正能量
- left_and_right_net正常版本
- 2022.7.3-----leetcode. five hundred and fifty-six
猜你喜欢
Notes and notes
BeanFactoryPostProcessor 与 BeanPostProcessor 相关子类概述
Actual cases and optimization solutions of cloud native architecture
【无标题】
buuctf-pwn write-ups (8)
C language exercises (recursion)
JS flattened array of number shape structure
Detailed explanation of common APIs for component and container containers: frame, panel, scrollpane
[untitled]
JS how to convert seconds into hours, minutes and seconds display
随机推荐
Install pytoch geometric
Steady! Huawei micro certification Huawei cloud computing service practice is stable!
Error CVC complex type 2.4. a: Invalid content beginning with element 'base extension' was found. Should start with one of '{layoutlib}'.
Wechat applet +php realizes authorized login
报错cvc-complex-type.2.4.a: 发现了以元素 ‘base-extension‘ 开头的无效内容。应以 ‘{layoutlib}‘ 之一开头。
AWT介绍
2022.7.2-----leetcode. eight hundred and seventy-one
BeanFactoryPostProcessor 与 BeanPostProcessor 相关子类概述
Detectron: train your own data set -- convert your own data format to coco format
input显示当前选择的图片
分布式CAP理论
JSON Web Token----JWT和传统session登录认证对比
Invalid revision: 3.18.1-g262b901-dirty
MySQL information_ Schema database
tutle时钟改进版
一键过滤选择百度网盘文件
安装 Pytorch geometric
Google Chrome browser will support the function of selecting text translation
How does apscheduler set tasks not to be concurrent (that is, execute the next task after the first one)?
剑指 Offer II 038. 每日温度