貪吃蛇—C語言控制臺簡單實作
- 模塊拆分
- 蛇身及蛇身列印
- 蛇身的移動(重點)
- 判定死亡
- 生成目標
- 吃到目標后加長
- 模塊整合
- 完整代碼
模塊拆分
蛇身及蛇身列印
這里我采用的是結構體陣列來儲存蛇身資訊,包含x,y坐標,當然也可以用其他的儲存方式,比如二維陣列、鏈表等,“場地”的大小是24x24,用字符*來表示蛇身,
struct snake {
int x, y;
};//蛇身資訊
struct snake body[600];//結構體陣串列示蛇身
body[0].x = 2; body[0].y = 0;
body[1].x = 1; body[1].y = 0;
body[2].x = 0; body[2].y = 0; //初始化,初始長度為3
//此處注意蛇頭的資訊一定要存在body[0]
void show()
{
int is_body=0; //判斷是否是是否是蛇身
system("cls"); //清屏函式,在windows.h里
for (i = 0; i < 24; i++)
{
for (j = 0; j < 24; j++)
{
for(k=0;k<lenth;k++) //遍歷目前蛇身長度
if (i == body[k].y && j == body[k].x||i== target _y&&j== target_x)
is_body = 1;//判斷是否是蛇身或目標(后面隨機生成)
//注意這里i是行號代表y,j是列號代表x
if(is_body ==1) printf("*");
else printf(" ");
is_body = 0;
}
printf("|\n");//每行的末尾列印邊界
}
for (i = 0; i < 24; i++)
printf("-"); //最后一行列印邊界
}
運行效果

因為字符是長方形的,最后列印出來也是長方形的,原理就是一行行列印,在遇到對應蛇身的x,y坐標的時候就列印星號,注意清屏函式的使用,
蛇身的移動(重點)
當我們移動蛇身時,我們只需要改變蛇身的x,y坐標,因為蛇是連續的,我們可以這樣理解,當我們移動的時候,每一步我們改變的只有頭和尾,我們將除了頭以外的身體部分,覆寫之前除了尾的身體部分,這樣得到的就是連續變化的了,再改變頭的坐標,往要移動的方向前進一格,這一部分理解了,貪吃蛇就完成了一大半,
那么我們怎么從鍵盤獲得輸入,從而改變方向呢,這里需要用到 _kbhit() 函式(在<conio.h>下),檢查當前是否有鍵盤輸入,若有則回傳一個非0值,否則回傳0,再用_getch()函式得到用戶鍵入的字符,若沒有輸入,既保持這個方向移動不變,
還要用到延時函式Sleep(微秒數)(在<windows.h>里),來減慢移動速度,
void move()
{
if (a == 'w') {
for (i = lenth - 1; i > 0; i--)
body[i] = body[i - 1]; //移動除蛇頭部分
body[0].y -= 1; //將蛇頭向上移動一格
}
if (a == 's') {
for (i = lenth - 1; i > 0; i--)
body[i] = body[i - 1];
body[0].y += 1; //向下運動
}
if (a == 'a') {
for (i = lenth - 1; i > 0; i--)
body[i] = body[i - 1];
body[0].x -= 1;//向左運動
}
if (a == 'd') {
for (i = lenth - 1; i > 0; i--)
body[i] = body[i - 1];
body[0].x += 1;//向右運動
}
show();
}
//main函式中的內容,die_flag,用來判斷是否死亡
while (die_flag)
{
if (_kbhit())
{
a = _getch(); move(); Sleep(speed); //有鍵入時將字符賦給a
}
else {
move(); Sleep(speed);//沒有鍵入,a不變繼續此方向移動
}
判定死亡
游戲結束有兩種情況,一種是碰到邊界了,另一種是碰到自身了,判定的方法都是將蛇頭的x,y坐標和邊界和自身其他x,y相比較,
void die()
{
for (i = 1; i < lenth; i++)
if (body[i].x == body[0].x && body[i].y == body[0].y || body[0].x > 23 || body[0].x < 0 || body[0].y >23|| body[0].y < 0)die_flag = 0;
//遍歷蛇身,看蛇頭是否有重合,及是否超出邊界
if (die_flag == 0) {
system("cls");
printf("GAME OVER!");
}
}
while (die_flag)
{
if (_kbhit())
{
a = _getch(); move();die(); Sleep(speed);
}
else {
move(); die(); Sleep(speed); //每次移動后都判定是否死亡
}
}
生成目標
生成目標我們只需要生成兩個小于24的亂數,作為目標的橫縱坐標,srand函式在stdlib.h頭檔案中,srand函式生成的是偽亂數,所以還需要播種,我們將時間轉換成數字,這樣就能保證每一次的種子不同,
另外,我們生成的目標還不能與蛇身重合,否則玩家會找不到目標,
void target()
{
is_on_body = 1; //判斷目標是否生成在蛇身上
srand((unsigned)time(NULL));
target_x = (rand() % 24) ;
target_y = (rand() % 24) ; //生成亂數
for (i = 0; i < lenth; i++)
if (body[i].x == target_x && body[i].y == target_y) is_on_body = 0;//判斷是否和蛇身重合
}
}
//生成目標的時候用do while,首先執行一次,如果重合就繼續執行
do
target(); while (is_on_body == 0);
吃到目標后加長
加長無非是在蛇尾后加一個,但是這一塊怎么保證和蛇身方向相同呢,其實不難,我們能夠輕易得知,倒數第二塊和倒數第一塊總是在一個方向上,那么我新加上的這一塊和倒數第一塊的相對位置也是如此,
void add()
{
if (body[0].x == target_x && body[0].y == target_y)
{
lenth++;//蛇身長度加一
body[lenth - 1].x = 2 * body[lenth - 2].x - body[lenth - 3].x;
body[lenth - 1].y = 2 * body[lenth - 2].y - body[lenth - 3].y;
//計算添加的蛇尾的位置
show();
if (lenth % 5 == 0 && speed != 100)speed -= 50;//增加游戲難度,每吃到五個目標速度加快50ms
do
target(); while (is_on_body == 0);//吃到目標后重新生成目標
}
}
模塊整合
最后將幾個函式有序地放在一起,就完成了整個貪吃蛇,
while (die_flag)
{
if (_kbhit())
{
a = _getch(); move(); add(); die(); Sleep(speed);
}
else {
move(); add(); die(); Sleep(speed);
}
不過控制臺玩起來十分不流暢,主要是重繪率的問題,還有游標,其實也有辦法解決,控制臺輸出的時候,游標不一定要順序移動,我們可以用SetConsoleCursorPosition()函式直接將游標移動到相應位置,還可以用HideCursor()來隱藏游標,
這里我們就不做過多的講解了,后面我們用easyx可以做出更流暢,用戶體驗更好的版本,
完整代碼
#include<stdio.h>
#include<stdlib.h>
#include <windows.h>
#include<conio.h>
#include <time.h>
void move();
void add();
void die();
void target();
void show();
int i, j,k, target_x, target_y, speed, lenth, die_flag, is_on_body;
char a;
struct snake {
int x, y;
};//蛇身資訊
struct snake body[600];//結構體陣串列示蛇身
int main()
{
int c = 1;
speed = 300;
lenth = 3; die_flag = 1;
body[0].x = 2; body[0].y = 0;
body[1].x = 1; body[1].y = 0;
body[2].x = 0; body[2].y = 0; //初始化,初始長度為3
//此處注意蛇頭的資訊一定要存在body[0]
show();
do
target(); while (is_on_body == 0);
while (die_flag)
{
if (_kbhit())
{
a = _getch(); move(); add(); die(); Sleep(speed);
}
else {
move(); add(); die(); Sleep(speed);
}
}
return 0;
}
void move()
{
if (a == 'w') {
for (i = lenth - 1; i > 0; i--)
body[i] = body[i - 1]; body[0].y -= 1; //向上運動
}
if (a == 's') {
for (i = lenth - 1; i > 0; i--)
body[i] = body[i - 1]; body[0].y += 1; //向下運動
}
if (a == 'a') {
for (i = lenth - 1; i > 0; i--)
body[i] = body[i - 1]; body[0].x -= 1;//向左運動
}
if (a == 'd') {
for (i = lenth - 1; i > 0; i--)
body[i] = body[i - 1]; body[0].x += 1;//向右運動
}
show();
}
void show()
{
int is_body=0;
system("cls"); //清屏函式,在windows.h里
for (i = 0; i < 24; i++)
{
for (j = 0; j < 24; j++)
{
for(k=0;k<lenth;k++) //遍歷目前蛇身長度
if (i == body[k].y && j == body[k].x||i== target_y&&j== target_x)
is_body = 1;//判斷是否是蛇身或目標(后面隨機生成)
//注意這里i是行號代表y,j是列號代表
if(is_body ==1) printf("*");
else printf(" ");
is_body = 0;
}
printf("|\n");//每行的末尾列印邊界
}
for (i = 0; i < 24; i++)
printf("-");//最后一行列印邊界
}
void add()
{
if (body[0].x == target_x && body[0].y == target_y)
{
lenth++;
body[lenth - 1].x = 2 * body[lenth - 2].x - body[lenth - 3].x;
body[lenth - 1].y = 2 * body[lenth - 2].y - body[lenth - 3].y;
show();
if (lenth % 5 == 0 && speed != 100)speed -= 50;
do
target(); while (is_on_body == 0);
}
}
void die()
{
for (i = 1; i < lenth; i++)
if (body[i].x == body[0].x && body[i].y == body[0].y || body[0].x > 23 || body[0].x < 0 || body[0].y >23|| body[0].y < 0)die_flag = 0;
//遍歷蛇身,看蛇頭是否有重合,及是否超出邊界
if (die_flag == 0) {
system("cls");
printf("GAME OVER!");
}
}
void target()
{
is_on_body = 1;
srand((unsigned)time(NULL));
target_x = (rand() % 24) ;
target_y = (rand() % 24) ;//生成亂數
for (i = 0; i < lenth; i++)
if (body[i].x == target_x && body[i].y == target_y) is_on_body = 0; //判斷是否和蛇身重合
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/248989.html
標籤:其他
上一篇:如何制作2048小游戲(超詳細)
