c語言貪吃蛇詳解4.食物的投放與蛇的變長
前幾天的實驗室教育訓練課後作業我布置了貪吃蛇,今天有時間就來寫一下題解。我将分幾步來教大家寫一個貪吃蛇小遊戲。由于大家c語言未學完,這個教程隻涉及數組和函數等知識點。
通過前幾次的教程,我們已經做出來了能上下左右跑的小蛇了。現在我們就先來做下食物投放吧。
食物投放的基本思想是在地圖上随機找一個沒有蛇身也沒有障礙物的地方,然後把這個地方的地圖數組值标記為-1(前面我們讓空地為0,障礙物為1)。
我們先來寫一個函數來判斷一個點是不是符合上面的條件。
int check(int ii,int jj) //判斷這個點能不能放食物,可以放傳回1,不能放傳回0
{
if(a[ii][jj]==1) //如果有障礙物,傳回0
return 0;
int i;
for(i=0; i<sLength; i++)
{
if(ii==s[i]0&&jj==s[i][1]) //如果和其中一個蛇身重合,就傳回0
return 0;
}
if(ii==0||ii==H-1||jj==0||jj==W-1) //如果在邊界上面,傳回0
return 0;
return 1; //最後篩選 過後的是符合條件的點
}
要使用随機數,先
#include <stdlib.h>
然後由于要根據時間設定随機數種子,是以要
#include<time.h>
在init函數裡面寫這句代碼
srand((unsigned)time(NULL)); //設定随機數種子為現在的時間
然後寫一個food函數,實作投放一個食物
void food()
{
int i,j;
do
{
i=rand()%H; //生成0~H-1之間的一個數
j=rand()%W;
}while(check(i,j)==0); //生成點直到滿足條件
a[i][j]=-1; //标記為食物
gotoxy(i,j);
printf("$"); //畫出食物
}
然後在main裡面的循環前面調用一次food,實作開始遊戲時有一個食物。然後檢查蛇頭與食物是否重合,如果重合,就調用一次food,投放一個食物。
int main()
{
init(); //程式開始時的初始化操作
drawMap(); //畫地圖
food();
while(1)
{
drawSnake(); //畫蛇
Sleep(WAIT_TIME); //等待一段時間
key();
move(); //移動蛇(主要是修改蛇身數組的資料)
if(a[s[0][0]][s[0][1]]==-1) //如果蛇頭碰到食物,就重新投放食物,并且把食物點重置為0
{
food();
a[s[0][0]][s[0][1]]=0;
}
}
getchar();
return 0;
}
讓我們來看看效果

到現在為止的代碼:
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include<time.h>
#include<windows.h>
#define H 23
#define W 75
#define WAIT_TIME 500
//定義direction的每個值代表的方向
#define UP 0
#define DOWN 1
#define LEFT 2
#define RIGHT 3
int a[H][W]; //地圖數組
int s[H*W][2]; //蛇身坐标數組
int sLength; //蛇的長度
int direction; //蛇的方向
void init() //程式開始時的初始化操作
{
srand((unsigned)time(NULL)); //設定随機數種子為現在的時間
CONSOLE_CURSOR_INFO cursor_info = {1, 0};
SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &cursor_info); //隐藏關标
int i,j;
for(i=0; i<H; i++)
{
a[i][0]=1; //讓第一列為1
a[i][W-1]=1; //讓最後一列為1
}
for(j=0; j<W; j++)
{
a[0][j]=1; //讓第一行為1
a[H-1][j]=1; //讓最後一行為1
}
sLength=4; //讓蛇的最初長度為4
s[0][0]=H/2;
s[0][1]=W/2; //給蛇頭坐标指派
for(i=1; i<4; i++)
{
s[i][0]=s[0][0]+i;
s[i][1]=s[0][1]; //給剛開始的蛇身幾個初始坐标
}
direction=UP;
}
void gotoxy(int i,int j) //移動光标
{
COORD position= {j,i};
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),position);
}
int check(int ii,int jj) //判斷這個點能不能放食物,可以放傳回1,不能放傳回0
{
if(a[ii][jj]==1) //如果有障礙物,傳回0
return 0;
int i;
for(i=0; i<sLength; i++)
{
if(ii==s[i][0]&&jj==s[i][1]) //如果和其中一個蛇身重合,就傳回0
return 0;
}
if(ii==0||ii==H-1||jj==0||jj==W-1) //如果在邊界上面,傳回0
return 0;
return 1; //最後篩選 過後的是符合條件的點
}
void food()
{
int i,j;
do
{
i=rand()%H; //生成0~H-1之間的一個數
j=rand()%W;
}
while(check(i,j)==0); //生成點直到滿足條件
a[i][j]=-1; //标記為食物
gotoxy(i,j);
printf("$"); //畫出食物
}
void drawMap() //畫地圖
{
gotoxy(0,0);
int i,j;
for(i=0; i<H; i++)
{
for(j=0; j<W; j++) //兩重for循環周遊數組
{
if(a[i][j]==0) //為0輸出空格
printf(" ");
else //為1輸出#
printf("#");
}
printf("\n"); //别忘了換行
}
}
void move()
{
int i;
gotoxy(s[sLength-1][0],s[sLength-1][1]);
printf(" "); //在尾巴上面畫空格以擦除尾巴
for(i=sLength-1; i>0; i--) //從尾巴開始,每一個點的位置等于它前面一個點的位置
{
s[i][0]=s[i-1][0];
s[i][1]=s[i-1][1];
}
switch(direction)
{
case UP:
s[0][0]--;
break;
case DOWN:
s[0][0]++;
break;
case LEFT:
s[0][1]--;
break;
case RIGHT:
s[0][1]++;
break;
}
}
void drawSnake() //畫蛇
{
int i;
for(i=0; i<sLength; i++)
{
gotoxy(s[i][0],s[i][1]); //移動關标到蛇的坐标
printf("@"); //在這個位置畫蛇
}
}
void key()
{
if(kbhit()!=0) //如果有鍵盤輸入
{
char in;
while(!kbhit()==0) //如果玩家輸入了多個按鍵,以最後一個按鍵為準
in=getch();
switch(in)
{
case 'w':
case 'W':
if(direction!=DOWN) //不能縮頭吧。。。。
direction=UP;
break;
case 's':
case 'S':
if(direction!=UP)
direction=DOWN;
break;
case 'a':
case 'A':
if(direction!=RIGHT)
direction=LEFT;
break;
case 'd':
case 'D':
if(direction!=LEFT)
direction=RIGHT;
break;
}
}
}
int main()
{
init(); //程式開始時的初始化操作
drawMap(); //畫地圖
food();
while(1)
{
drawSnake(); //畫蛇
Sleep(WAIT_TIME); //等待一段時間
key();
move(); //移動蛇(主要是修改蛇身數組的資料)
if(a[s[0][0]][s[0][1]]==-1) //如果蛇頭碰到食物,就重新投放食物,并且把食物點重置為0
{
food();
a[s[0][0]][s[0][1]]=0;
}
}
getchar();
return 0;
}
好了,現在食物能正常投放了
接下來我們就來實作一下蛇吃到食物的變長功能吧。
首先設定一個變量标記蛇是否吃到食物
bool eated=false; //标記是否吃到食物
然後在main裡面的判斷吃到食物時,使eated變為true
if(a[s[0][0]][s[0][1]]==-1) //如果蛇頭碰到食物,就重新投放食物,并且把食物點重置為0
{
eated=true; //标記已經吃到食物
food();
a[s[0][0]][s[0][1]]=0; //去掉食物
}
然後在move函數裡面加下面的代碼
if(eated) //如果吃到了食物
{
sLength++;
eated=false; //設定為false,不然無限變長
}
這樣在下面的坐标移動環節,就不會舍棄掉上一次的尾巴節點。蛇就變長了。
來看看效果:
蛇可以變長了。不過有時候玩着玩着有事,又舍不得玩了這麼長的蛇,要是有個暫停功能就好了。接下來我們就來順便實作下。
在key函數裡面的switch裡面加一個case
case 'p':
case 'P':
gotoxy(H,0); //将光标移動到下面
system("pause");
gotoxy(H,0);
printf(" "); //消去下面的按任意鍵繼續
break;
這樣就可以實作按p鍵暫停了。(記得玩的時候切換為英文輸入法呀)
來看看到現在為止的代碼:
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include<time.h>
#include<windows.h>
#define H 23
#define W 75
#define WAIT_TIME 500
//定義direction的每個值代表的方向
#define UP 0
#define DOWN 1
#define LEFT 2
#define RIGHT 3
int a[H][W]; //地圖數組
int s[H*W][2]; //蛇身坐标數組
int sLength; //蛇的長度
int direction; //蛇的方向
bool eated=false; //标記是否吃到食物
void init() //程式開始時的初始化操作
{
srand((unsigned)time(NULL)); //設定随機數種子為現在的時間
CONSOLE_CURSOR_INFO cursor_info = {1, 0};
SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &cursor_info); //隐藏關标
int i,j;
for(i=0; i<H; i++)
{
a[i][0]=1; //讓第一列為1
a[i][W-1]=1; //讓最後一列為1
}
for(j=0; j<W; j++)
{
a[0][j]=1; //讓第一行為1
a[H-1][j]=1; //讓最後一行為1
}
sLength=4; //讓蛇的最初長度為4
s[0][0]=H/2;
s[0][1]=W/2; //給蛇頭坐标指派
for(i=1; i<4; i++)
{
s[i][0]=s[0][0]+i;
s[i][1]=s[0][1]; //給剛開始的蛇身幾個初始坐标
}
direction=UP;
}
void gotoxy(int i,int j) //移動光标
{
COORD position= {j,i};
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),position);
}
int check(int ii,int jj) //判斷這個點能不能放食物,可以放傳回1,不能放傳回0
{
if(a[ii][jj]==1) //如果有障礙物,傳回0
return 0;
int i;
for(i=0; i<sLength; i++)
{
if(ii==s[i][0]&&jj==s[i][1]) //如果和其中一個蛇身重合,就傳回0
return 0;
}
if(ii==0||ii==H-1||jj==0||jj==W-1) //如果在邊界上面,傳回0
return 0;
return 1; //最後篩選 過後的是符合條件的點
}
void food()
{
int i,j;
do
{
i=rand()%H; //生成0~H-1之間的一個數
j=rand()%W;
}
while(check(i,j)==0); //生成點直到滿足條件
a[i][j]=-1; //标記為食物
gotoxy(i,j);
printf("$"); //畫出食物
}
void drawMap() //畫地圖
{
gotoxy(0,0);
int i,j;
for(i=0; i<H; i++)
{
for(j=0; j<W; j++) //兩重for循環周遊數組
{
if(a[i][j]==0) //為0輸出空格
printf(" ");
else //為1輸出#
printf("#");
}
printf("\n"); //别忘了換行
}
}
void move()
{
int i;
gotoxy(s[sLength-1][0],s[sLength-1][1]);
printf(" "); //在尾巴上面畫空格以擦除尾巴
if(eated) //如果吃到了食物
{
sLength++;
eated=false; //設定為false,不然無限變長
}
for(i=sLength-1; i>0; i--) //從尾巴開始,每一個點的位置等于它前面一個點的位置
{
s[i][0]=s[i-1][0];
s[i][1]=s[i-1][1];
}
switch(direction)
{
case UP:
s[0][0]--;
break;
case DOWN:
s[0][0]++;
break;
case LEFT:
s[0][1]--;
break;
case RIGHT:
s[0][1]++;
break;
}
}
void drawSnake() //畫蛇
{
int i;
for(i=0; i<sLength; i++)
{
gotoxy(s[i][0],s[i][1]); //移動關标到蛇的坐标
printf("@"); //在這個位置畫蛇
}
}
void key()
{
if(kbhit()!=0) //如果有鍵盤輸入
{
char in;
while(!kbhit()==0) //如果玩家輸入了多個按鍵,以最後一個按鍵為準
in=getch();
switch(in)
{
case 'w':
case 'W':
if(direction!=DOWN) //不能縮頭吧。。。。
direction=UP;
break;
case 's':
case 'S':
if(direction!=UP)
direction=DOWN;
break;
case 'a':
case 'A':
if(direction!=RIGHT)
direction=LEFT;
break;
case 'd':
case 'D':
if(direction!=LEFT)
direction=RIGHT;
break;
case 'p':
case 'P':
gotoxy(H,0); //将光标移動到下面
system("pause");
gotoxy(H,0);
printf(" "); //消去下面的按任意鍵繼續
break;
}
}
}
int main()
{
init(); //程式開始時的初始化操作
drawMap(); //畫地圖
food();
while(1)
{
drawSnake(); //畫蛇
Sleep(WAIT_TIME); //等待一段時間
key();
move(); //移動蛇(主要是修改蛇身數組的資料)
if(a[s[0][0]][s[0][1]]==-1) //如果蛇頭碰到食物,就重新投放食物,并且把食物點重置為0
{
eated=true; //标記已經吃到食物
food();
a[s[0][0]][s[0][1]]=0; //去掉食物
}
}
getchar();
return 0;
}
轉載于:https://www.cnblogs.com/hjw1/p/7987877.html