在上一篇中,我們把這個項目的各個文件都創立了下,而且還在snake.h文件中把我們要用到的函數都列了出來,接下來我們來逐步完善各個函數。
gotoxy函數
爲啥子不按照順序先從initMap開始講嘞?因爲initMap這個函數需要定點輸出,而且我之前說了,在這個項目中我不會使用“\n”這種來輸出界面,所以我們採用定點輸出的方式,爲了方便它的使用,當然是把它打包成一個函數啦。
這個函數沒啥子講的,只是死套模板罷了,只不過我們把x和y作爲函數的輸入就可以了:
void gotoxy(int x, int y)
{
HANDLE hout; //Defining handle objects
COORD cor; //Defining coordinate objects
hout = GetStdHandle(STD_OUTPUT_HANDLE); //Get the handle of the output screen buffer
cor.X = y;
cor.Y = x;
SetConsoleCursorPosition(hout, cor); //Move Cursor
}
這樣,我們在主函數中導入snake.h頭文件後就可以直接調用這個函數了,而且在snake.c文件中也是。
menu函數
如果你大概玩了下這個小遊戲你就會知道,我們在剛打開這個遊戲的時候,會有個問你玩遊戲還是退出的界面,這個函數就是用來顯示這個界面的。
不知大家還記不記得我們在snake.h裏面定義的一個ret變量,它就是在這裏用來當這個函數的返回值的。
int menu()
{
gotoxy(12, 42);//移動到12,42的位置
printf("歡迎來到貪喫蛇小遊戲....");
gotoxy(14, 45);//移動到14,45的位置
printf("開始遊戲請按(1)");
gotoxy(16, 42);//移動到16,42的位置
printf("按其他任意鍵退出遊戲QAQ");
gotoxy(18,25);//移動到18,25的位置
printf("反正閒着也是閒着,不如坐下來來一把緊張又刺激的貪喫蛇如何?┐(‘~`;)┌");
int ch = getch();//使用ch接收鍵盤輸入的值,getch()作用參考第一章
while (TRUE)
{
if (ch == 49) //因爲它的 ASCII 值是1,因爲我們的ch是int型
{
ret = 1;//則把ret標記爲1,意爲用戶同意玩
break;
}
else
{
break;
}
}
system("cls");//把屏幕清空下,方便接下來的顯示界面
return ret;//把ret的值返回
}
initMap函數
這個函數是用來顯示地圖界面的,它用來初始化蛇的各種信息,果子的座標,和遊戲邊框等地方,是非常重要的函數。我的註釋會打的非常詳細,幫助大家理解
void initMap(void)
{
ch = UP;//默認的ch爲向前
Direction = UP;//默認方向爲向前
//初始化食物
srand(time(NULL)); //使用當前時間進行隨機數發生器的初始化
food.x = rand() % (FRAME_HEIGHT - 2) + 1;//rand( )隨機函數, 食物的x座標爲1到界面最右邊少一個位置中的任意一個值。FRAME_HEIGHT 和FRAME_WIDTH都是我們之前已經宏定義後的值。
food.y = rand() % (FRAME_WIDTH - 2) + 1;
gotoxy(food.x, food.y);//定位到我們隨機出的座標
printf("!");//使用!代表食物
//初始化蛇
snake.x[0] = FRAME_HEIGHT / 2;//用地圖的長和寬都除2,從而把蛇頭定位到地圖中央
snake.y[0] = FRAME_WIDTH / 2;
gotoxy(snake.x[0], snake.y[0]);//到地圖中央的地方
printf("@");//用@表示蛇身
snake.len = 3;//初始蛇的長度是3個
snake.speed = 200;//默認蛇的速度是200
for (k = 1; k<snake.len; k++)//從正中央的地點開始後3個把蛇的身子部分都顯示出來
{
snake.x[k] = snake.x[k - 1] + 1;
snake.y[k] = snake.y[k - 1];
gotoxy(snake.x[k], snake.y[k]);
printf("@");
}
//初始化地圖
for (j = 0; j<FRAME_WIDTH; j++)//初始化寬
{
gotoxy(0, j);
printf("#");//是用#表示邊界
gotoxy(FRAME_HEIGHT - 1, j);
printf("#");
}
for (i = 1; i<FRAME_HEIGHT - 1; i++)//初始化長
{
gotoxy(i, 0);
printf("#");
gotoxy(i, FRAME_WIDTH - 1);
printf("#");
}
}
printFont函數
這個函數主要是顯示一些遊戲信息啊神馬的東西與遊戲內容無關,主要是加強遊戲體驗的東西。爲了方便,這個函數的入口參數就弄了倆,其他輸出地點的座標直接計算出來,emm至於計算公式,,不用太深究,,慢慢調出來的,主要是爲了美觀。
void printFont(int x, int y, int speed)
{
int i = 1;//定義一個變量,後面計算用
gotoxy(x, y);
printf("反正閒着也是閒着,不如坐下來來一把緊張又刺激的貪喫蛇如何?");
gotoxy(x + ADD, y);//ADD也是我們在snake.h裏面定義的一個常量,現在用作計算座標用,大家隨意處理即可
if (speed == 200)//根據速度顯示數度級數
{
printf("現在的速度是:%d級", i);
}
else if (speed == 175)
{
printf("現在的速度等級是:%d級", i + 1);
}
else if (speed == 150)
{
printf("現在的速度等級是:%d級", i + 2);
}
else if (speed == 100)
{
printf("現在的速度等級是:%d級", i + 3);
}
else
{
printf("恭喜你,召喚師,現在是最高級");
}
gotoxy(x + 2 * ADD, y);
printf("上下左右操作鍵分別是:w,s,a,d");
gotoxy(x + 3 * ADD, y);
printf("當喫到自己身體或者撞牆時遊戲結束");
gotoxy(x + 4 * ADD, y);
printf("按空格鍵暫停,在按空格鍵繼續");
}
updataFood函數
這個函數主要是用來更新了食物的,它用來判斷食物是否被喫,如果被喫掉了就再隨機出一個新的食物。。
至於怎麼判斷食物是否被喫掉了,很簡單,直接判斷蛇頭的座標是否和食物的座標一樣就可與了,,emm,,但是後來我玩這個遊戲的時候,發現這個bug,因爲食物是全圖生成的,如果生成的食物在蛇的身上,它會隨着蛇的移動,輸出的食物圖標“!”被覆蓋,隨後消失。而且不會生成新的食物。。。說白了,按照上面的邏輯,這個bug就是食物沒了,而且不再生成。
所以我把它的判斷邏輯小改了下——當食物的座標在蛇的身體中時,它才判定食物被喫掉了。
void updataFood()
{
int iseat=0;//用作標記食物是否被喫,默認爲沒有被喫
for(int i=0;i<snake.len;i++){//循環判斷,食物的座標是否以在蛇的身體中
if(snake.x[i]==food.x&&snake.y[i]==food.y){
iseat=1;//如果時,則記錄食物被吃了
break;
}
}
if (iseat)//當食物被吃了後,再次隨機新的食物
{
srand(time(NULL));//不明白的參考第一章
food.x = rand() % (FRAME_HEIGHT - 2) + 1;//使用取餘的方式,把隨機的結果固定在地圖範圍中
food.y = rand() % (FRAME_WIDTH - 2) + 1;
gotoxy(food.x, food.y);
printf("!");
snake.len++;//由於食物被吃了,蛇的長度加一
grow = 1;//是否增長標記爲是,這個變量也是snake.h宏定義過的
}
}
好了,今天就先講解這麼多,剩下的明天再講吧,,,畢竟打字打的手有點疼