零基礎教做貪喫蛇——(4)剩餘函數講解

emmm,昨天沒有更新,,這個嘛。還是因爲STM32的原因,,,昨天弄它的串口通信弄了一下午加半個晚上,,再加上降溫了。。手冷,,昨天就沒寫。。今天因爲妹妹開網課了,,我又給她把家裏以前的臺式拼起來,,所以耽誤的不少時間。。在這裏插入圖片描述
好了,話不多說,我們來開始今天的主題,這是最後一章了,我會把剩餘的函數都講了它。大家看完後可以自己嘗試着也寫一個,或者找啥子像素鳥啊,五子棋啊啥子試試,原理都是通的。這些項目除了可以激發興趣外,還可以加深你對c語言的理解。

moveSnake函數

這個函數可以說是整個遊戲的核心函數了,我們一定要弄明白蛇在整個遊戲中的移動的邏輯。
首先,蛇在地圖初始化的時候已經被我們打印出來了,但是在遊戲中,即使我們不操作,蛇也是會自動移動的,這個移動的方向初始化時是向上,其他時候就是我們上次操作時的方向。
怎麼樣顯示蛇“移動”的這個效果嘞?嘿嘿,通過座標運算,把蛇的身子的其他值往前一個移動就可以了。

	for (k = snake.len - 1; k>0; k--)//蛇的身子一格一格的移動
	{
		snake.x[k] = snake.x[k - 1];
		snake.y[k] = snake.y[k - 1];
	}

並且蛇在移動時,如果沒有喫到過果子,是沒有長大的。所以我們渲染蛇向前移動時,最後一格的蛇尾“#”也要變成“ ”
同時,使用鍵盤控制蛇的移動時,如果蛇是向上走的,則你輸入“S”向下是無效的。即需要考慮操作的合理性。
這個函數的完整代碼:

void moveSnake()
{

	if (!grow)//如果沒有長大,則上次的最後一個點,即尾巴,的地方顯示空.這裏的grow是在更新食物時我們標記的
	{
		gotoxy(snake.x[snake.len - 1], snake.y[snake.len - 1]);
		printf(" ");//用空格覆蓋之前的蛇尾巴
	}
	for (k = snake.len - 1; k>0; k--)//蛇的身子一格一格的移動
	{
		snake.x[k] = snake.x[k - 1];
		snake.y[k] = snake.y[k - 1];
	}
	if (kbhit())//檢查當前是否有鍵盤輸入
	{
		ch = getch();
		if (ch == ' ')												//如果輸入空格表示暫停,使用while函數一直卡着。
		while (getch() != ' '){};
		if (ch != UP && ch != DOWN && ch != LEFT && ch != RIGHT)	//如果輸入的時其他的鍵,則使用默認方向。這裏的UP啊啥的都是之前定義好的
		{
			ch = Direction;
			goto sport;//無條件跳轉
		}

		if (Direction != ch)//如果輸入的不默認方向
		{
			if ((Direction == UP &&ch != DOWN) || (Direction == DOWN &&ch != UP) || (Direction == LEFT && ch != RIGHT) || (Direction == RIGHT && ch != LEFT)) //Prevent reverse movement
			{//確保輸入的方向與當前方向邏輯上不違背,即確保蛇不能倒退
				Direction = ch;
				goto sport;
			}
			else
			{//如果違背了。則保持當前
				ch = Direction;
				goto sport;
			}

		}
		else
		{
			goto sport;
		}
	}
	else
	{
	sport:
		switch (ch)							//移動蛇的頭部
		{
		case UP: snake.x[0]--; break;//注意,在窗口中,座標與我們常用的座標是倒過來的
		case DOWN:  snake.x[0]++; break;
		case LEFT: snake.y[0]--; break;
		case RIGHT: snake.y[0]++; break;
		default: break;

		}
	}

	gotoxy(snake.x[0], snake.y[0]);
	printf("@");							//輸出蛇的頭
	grow = 0;//把grow標記回0
	gotoxy(FRAME_HEIGHT, 0);//把光標始終弄在結尾處
}

emm,爲了方便大家理解,我在它原本的基礎上加了不少註釋,方便大家理解。

isAlive函數

這個函數時用來判斷蛇是否存活。主要的邏輯是判斷蛇是否撞到邊界和撞到自己。
這個函數很簡單,就是一個判斷函數

int isAlive(void)
{//判斷蛇是否還活着,即判斷蛇有沒有撞上自己的身體,有沒有碰到邊界
	if (snake.x[0] == 0 || snake.x[0] == FRAME_HEIGHT - 1 || snake.y[0] == FRAME_WIDTH - 1 || snake.y[0] == 0)   //When you touch a wall or eat your own body, you die
		return 0;
	for (k = 1; k<snake.len; k++)
	if (snake.x[k] == snake.x[0] && snake.y[k] == snake.y[0])
		return 0;
	return 1;
}

getSpeed函數

這個函數是用來根據蛇的長度判斷蛇的速度的。但是我們主要的速度邏輯並不是在這裏實現的,所以這個函數並不複雜。

void getSpeed(void)//根據長度修改速度
{
	if (snake.len <= 6)
		snake.speed = 200;
	else if (snake.len <= 10)
		snake.speed = 175;
	else if (snake.len <= 20)
		snake.speed = 150;
	else if (snake.len <= 30)
		snake.speed = 100;
	else snake.speed = 50;
	if (snake.len == 40)
		finish = 0;//長度40爲通關
}

main主函數

嘿嘿,關於snake.h和它的函數終於寫完了。接下來我們就可以來完成最後一步了。之前說了,我們只要在開頭把snake.h的頭文件包含進來,就可以直接用了。具體邏輯我就不詳細講解了,但是註釋我還是給大家打的挺詳細的。在這裏插入圖片描述

#include "snake.h"
#include <windows.h>
#include <math.h>
//Transposed structure object
extern  struct Food food;//全局變量申明
extern  struct Snake snake;

//main function
int main()
{
	ret = menu();//顯示初始化菜單,並且判斷用戶是否想玩遊戲
	if (ret == 1)//輸入1,表示是
	{
		while (finish)
		{
			initMap();																	//初始化地圖
			while (TRUE)
			{
				updataFood();														//updata food
				getSpeed();															//speed
				moveSnake();														//move snake
				Sleep(snake.speed);	//是計算機處理的程序的函數。。功能是暫停,單位是毫秒,它就是用來控制蛇的快慢的,嘿嘿。其實就是通過這個函數讓系統進程變慢,從而控制蛇的快慢
				printFont(FONT_WINDOW_STARTX, FONT_WINDOW_STARTY, snake.speed);		//顯示遊戲信息
				if (!(isAlive()))//如果沒有存活,則結束
					break;
			}
			if (finish)//如果沒有標記通關,則顯示你這次的長度														//Death or customs clearance
			{
				system("cls");//清屏函數
				gotoxy(22, 5);
				printf("您的遊戲結束,您操作的貪喫蛇長度爲%d,請再接再厲",snake.len);
				gotoxy(24, 5);
				printf("按(1)鍵退出遊戲,按(2)鍵重玩");
                char ch;
                while((ch=getch(),ch)!= 50)
                {
                    if(ch==49) return 0;
                    if(ch==50) break;
                }
				system("cls");
			}
			else//如果通關了
			{
				system("cls");
				gotoxy(22, 5);
				printf("恭喜你通關了");
				gotoxy(24, 5);
				printf("按(1)鍵退出遊戲,按(2)鍵重玩");
                char ch;
                while((ch=getch(),ch)!= 50)
                {
                    if(ch==49) return 0;//注意這裏的49沒有引號,是數字,因爲“1”的ASIIC碼值就是49,所以可以這樣判斷
                    if(ch==50) break;
                }
				system("cls");
			}

		}

	}
}

關於貪喫蛇這個小項目的講解就到這裏了,大家可以自己去嘗試下,完善下。其實在實際的寫課設的過程中,寫的順序並不是我這個講解的順序,我只是爲了方便大家理解。寫過課設的童鞋都知道,大多都是自己先定一個大概的框架,然後再逐步完善的而不是像這個一樣一口氣寫出來。
最後,大家如果有不明白的地方也歡迎在評論區問我。也可以來技術菌團的qq羣一起討論

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章