国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

小游戲貪吃蛇的實現(xiàn)之C語言版

這篇具有很好參考價值的文章主要介紹了小游戲貪吃蛇的實現(xiàn)之C語言版。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

找往期文章包括但不限于本期文章中不懂的知識點:

個人主頁:我要學(xué)編程(?_?)-CSDN博客

所屬專欄:C語言

目錄

游戲前期準(zhǔn)備:

設(shè)置控制臺相關(guān)的信息?

GetStdHandle

GetConsoleCursorInfo?

SetConsoleCursorInfo

SetConsoleCursorPosition

GetAsyncKeyState

貪吃蛇游戲設(shè)計與分析?

本地化

地圖,食物和蛇身的設(shè)計?

GameStart()—— 游戲的初始化

打印歡迎界面?

繪制貪吃蛇地圖?

初始化貪吃蛇

初始化食物

GameRun()——游戲的運(yùn)行

打印右側(cè)的幫助信息

貪吃蛇的相關(guān)運(yùn)行信息?

GameOver()——游戲的結(jié)束(善后工作)?

貪吃蛇源碼?


使用C語言在Windows環(huán)境的控制臺中模擬實現(xiàn)經(jīng)典小游戲貪吃蛇。

游戲前期準(zhǔn)備:

?本次實現(xiàn)貪吃蛇會使用到的一些Win32 API知識,接下來我們就學(xué)習(xí)一下。

背景介紹

Windows 這個多作業(yè)系統(tǒng)除了協(xié)調(diào)應(yīng)用程序的執(zhí)行、分配內(nèi)存、管理資源之外, 它同時也是一個很大的服務(wù)中心,調(diào)用這個服務(wù)中心的各種服務(wù)(每一種服務(wù)就是一個函數(shù)),可以幫應(yīng)用程序達(dá)到開啟視窗、描繪圖形、使用周邊設(shè)備等目的,由于這些函數(shù)服務(wù)的對象是應(yīng)用程序(Application), 所以便稱之為 Application Programming Interface,簡稱 API 函數(shù)。WIN32 API也就是Microsoft Windows 32位平臺的應(yīng)用程序編程接口。

設(shè)置控制臺相關(guān)的信息?

平常我們運(yùn)行起來的黑框程序其實就是控制臺程序(如下圖所示)。

小游戲貪吃蛇的實現(xiàn)之C語言版,C語言,數(shù)據(jù)結(jié)構(gòu)(C語言版),c語言,開發(fā)語言,貪吃蛇游戲

我們可以使用cmd命令來設(shè)置控制臺窗口的長寬。例如:設(shè)置控制臺窗口的大小,30行,100列。?

//格式:  列        行
mode con cols=100 lines=30

注意:

1. 列和行在賦值時,不能帶有空格。例如:cols = 100,這就是不行的,沒有影響到控制臺的大小。

2. 使用這個命令之前,需要把這個控制臺改為讓W(xué)indows決定或者Windows 控制臺主機(jī)

演示:

改變VS編譯器的控制臺

3. 使用system函數(shù)所需要包含的頭文件既可以是stdlib.h,也可以是Windows.h(不分大小寫的,因此可以使用"windows.h"、"WINDOWS.H"或者"Windows.h"等形式來引用該頭文件。不過,一般約定使用"Windows.h"的形式來引用該頭文件,以保持代碼的一致性和可讀性。)?

下面就來使用這個來改變控制臺的大小。

小游戲貪吃蛇的實現(xiàn)之C語言版,C語言,數(shù)據(jù)結(jié)構(gòu)(C語言版),c語言,開發(fā)語言,貪吃蛇游戲

從上面的結(jié)果來看:行列對應(yīng)不一致。沒錯,一行的寬度是一列的寬度的二倍。

也可以通過命令設(shè)置控制臺窗口的名字:?

//格式:
title 要修改的名字

注意:在更改之后要觀察到的話,就不能讓程序運(yùn)行結(jié)束,也就是說只能在程序運(yùn)行期間才能夠觀察的到。小游戲貪吃蛇的實現(xiàn)之C語言版,C語言,數(shù)據(jù)結(jié)構(gòu)(C語言版),c語言,開發(fā)語言,貪吃蛇游戲

?控制臺屏幕上的坐標(biāo)COORD

COORD 是Windows API中定義的一個結(jié)構(gòu)體,表示一個字符在控制臺屏幕緩沖區(qū)上的坐標(biāo),坐標(biāo)系 (0,0) 的原點位于緩沖區(qū)的頂部左側(cè)單元格。?

小游戲貪吃蛇的實現(xiàn)之C語言版,C語言,數(shù)據(jù)結(jié)構(gòu)(C語言版),c語言,開發(fā)語言,貪吃蛇游戲

COORD類型的聲明:

typedef struct _COORD {
    SHORT X;//短整型
    SHORT Y;
} COORD, *PCOORD;

給坐標(biāo)賦值:

COORD pos = { 10, 15 };

GetStdHandle

GetStdHandle是一個Windows API函數(shù)。它用于從一個特定的標(biāo)準(zhǔn)設(shè)備(標(biāo)準(zhǔn)輸入、標(biāo)準(zhǔn)輸出或標(biāo)準(zhǔn)錯誤)中取得一個句柄(用來標(biāo)識不同設(shè)備的數(shù)值),使用這個句柄可以操作設(shè)備。

標(biāo)準(zhǔn)輸入是指鍵盤,標(biāo)準(zhǔn)輸出和標(biāo)準(zhǔn)錯誤是指屏幕。

這個句柄就類似一個遙控器,可以通過句柄來操作標(biāo)準(zhǔn)設(shè)備。而我們想要操作標(biāo)準(zhǔn)設(shè)備也得通過GetStdHandle這個函數(shù)來獲得句柄。再通過句柄來操作。

HANDLE GetStdHandle(DWORD nStdHandle);

小游戲貪吃蛇的實現(xiàn)之C語言版,C語言,數(shù)據(jù)結(jié)構(gòu)(C語言版),c語言,開發(fā)語言,貪吃蛇游戲

例如:

HANDLE hOutput = NULL;
//獲取標(biāo)準(zhǔn)輸出的句柄(?來標(biāo)識不同設(shè)備的數(shù)值)
hOutput = GetStdHandle(STD_OUTPUT_HANDLE);

GetConsoleCursorInfo?

小游戲貪吃蛇的實現(xiàn)之C語言版,C語言,數(shù)據(jù)結(jié)構(gòu)(C語言版),c語言,開發(fā)語言,貪吃蛇游戲

檢索有關(guān)指定控制臺屏幕緩沖區(qū)的光標(biāo)大小和可見性的信息。?

BOOL WINAPI GetConsoleCursorInfo(
 HANDLE hConsoleOutput,
 PCONSOLE_CURSOR_INFO lpConsoleCursorInfo
);
PCONSOLE_CURSOR_INFO 是指向 CONSOLE_CURSOR_INFO 結(jié)構(gòu)的指針,該結(jié)構(gòu)接收有關(guān)主機(jī)游標(biāo)

CONSOLE_CURSOR_INFO 這個結(jié)構(gòu)體,包含有關(guān)控制臺光標(biāo)的信息。

小游戲貪吃蛇的實現(xiàn)之C語言版,C語言,數(shù)據(jù)結(jié)構(gòu)(C語言版),c語言,開發(fā)語言,貪吃蛇游戲

typedef struct _CONSOLE_CURSOR_INFO {
    DWORD dwSize;//光標(biāo)的寬度占比
    BOOL bVisible;//光標(biāo)的可見性
} CONSOLE_CURSOR_INFO, *PCONSOLE_CURSOR_INFO;

舉例:

HANDLE hOutput = NULL;
//獲取標(biāo)準(zhǔn)輸出的句柄(用來標(biāo)識不同設(shè)備的數(shù)值)
hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_CURSOR_INFO CursorInfo = {0};
//獲取控制臺光標(biāo)信息
GetConsoleCursorInfo(hOutput, &CursorInfo);

SetConsoleCursorInfo

設(shè)置指定控制臺屏幕緩沖區(qū)的光標(biāo)的大小和可見性。

BOOL WINAPI SetConsoleCursorInfo(
    HANDLE hConsoleOutput,
    const CONSOLE_CURSOR_INFO *lpConsoleCursorInfo
);

舉例:

//獲取標(biāo)準(zhǔn)輸出的句柄
HANDLE hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
//定義一個存放光標(biāo)信息的結(jié)構(gòu)體
CONSOLE_CURSOR_INFO CursorInfo = {0};
//獲取控制臺光標(biāo)信息存放到這個結(jié)構(gòu)體中
GetConsoleCursorInfo(hOutput, &CursorInfo);
//隱藏控制臺光標(biāo)
CursorInfo.bVisible = false; 
//把控制臺光標(biāo)大小調(diào)到最大
CursorInfo.dwSize = 100;
//設(shè)置控制臺光標(biāo)狀態(tài)(按照上面的設(shè)置調(diào))
SetConsoleCursorInfo(hOutput, &CursorInfo);

SetConsoleCursorPosition

設(shè)置控制臺屏幕緩沖區(qū)中的光標(biāo)位置,我們將想要設(shè)置的坐標(biāo)信息放在COORD類型的變量中,調(diào) 用SetConsoleCursorPosition函數(shù)將光標(biāo)位置設(shè)置到指定的位置。?

小游戲貪吃蛇的實現(xiàn)之C語言版,C語言,數(shù)據(jù)結(jié)構(gòu)(C語言版),c語言,開發(fā)語言,貪吃蛇游戲

BOOL WINAPI SetConsoleCursorPosition(
    HANDLE hConsoleOutput,
    COORD pos
);

舉例:

//改變光標(biāo)的位置
COORD pos = { 10, 5};
HANDLE hOutput = NULL;
//獲取標(biāo)準(zhǔn)輸出的句柄
hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
//設(shè)置標(biāo)準(zhǔn)輸出上光標(biāo)的位置為pos
SetConsoleCursorPosition(hOutput, pos);

注意:這個pos的位置設(shè)置有可能不一定會成功。?

GetAsyncKeyState

獲取按鍵情況,GetAsyncKeyState的函數(shù)原型如下:

SHORT GetAsyncKeyState(int vKey);

小游戲貪吃蛇的實現(xiàn)之C語言版,C語言,數(shù)據(jù)結(jié)構(gòu)(C語言版),c語言,開發(fā)語言,貪吃蛇游戲

將鍵盤上每個鍵的虛擬鍵值傳遞給函數(shù),函數(shù)通過返回值來分辨按鍵的狀態(tài)。GetAsyncKeyState 的返回值是short類型,在上一次調(diào)用?GetAsyncKeyState 函數(shù)后,如果返回的16位的short數(shù)據(jù)中,最高位是1,說明按鍵的狀態(tài)是按下,如果最高是0,說明按鍵的狀態(tài)是抬起;如果最低位被置為1則說明,該按鍵被按過,否則為0。 如果我們要判斷一個鍵是否被按過,可以檢測GetAsyncKeyState返回值的最低位是否為1?。下面是虛擬鍵代碼虛擬鍵碼 (Winuser.h) - Win32 apps | Microsoft Learn虛擬鍵碼

舉例:檢測數(shù)字鍵是否被摁過。(字母鍵上面的數(shù)字鍵)

//判斷一個鍵是否被摁過
//如果被摁過結(jié)果就是1,否則就是0
#define KEY_PRESS(vk) ((GetAsyncKeyState(vk)&0x1)?1:0)
int main()
{
	while (1)
	{
		if (KEY_PRESS(0x30))
		{
			printf("%d\n", 0);
		}
		else if (KEY_PRESS(0x31))
		{
			printf("%d\n", 1);
		}
		else if (KEY_PRESS(0x32))
		{
			printf("%d\n", 2);
		}
		else if (KEY_PRESS(0x33))
		{
			printf("%d\n", 3);
		}
		else if (KEY_PRESS(0x34))
		{
			printf("%d\n", 4);
		}
		else if (KEY_PRESS(0x35))
		{
			printf("%d\n", 5);
		}
		else if (KEY_PRESS(0x36))
		{
			printf("%d\n", 6);
		}
		else if (KEY_PRESS(0x37))
		{
			printf("%d\n", 7);
		}
		else if (KEY_PRESS(0x38))
		{
			printf("%d\n", 8);
		}
		else if (KEY_PRESS(0x39))
		{
			printf("%d\n", 9);
		}
	}
}

貪吃蛇游戲設(shè)計與分析?

實現(xiàn)基本的功能:

? 貪吃蛇地圖繪制

? 蛇吃食物的功能 (上、下、左、右方向鍵控制蛇的動作)

? 蛇撞墻死亡

? 蛇撞自身死亡

? 計算得分

? 蛇身加速、減速

? 暫停游戲

在游戲地圖上,我們打印墻體使用寬字符:□,打印蛇使用寬字符●,打印食物使用寬字符★

普通的字符是占一個字節(jié)的,這類寬字符是占用2個字節(jié)。?

加入了寬字符的類型 wchar_t 和寬字符的輸入和輸出函數(shù),加入了<locale.h>頭文件,其中提供了允許程序員針對特定地區(qū)(通常是國家或者說某種特定語言的地理區(qū)域)調(diào)整程序行為的函數(shù)。

<locale.h>本地化

setlocale函數(shù)原型:

char* setlocale (int category, const char* locale);

類項

通過修改地區(qū),程序可以改變它的行為來適應(yīng)世界的不同區(qū)域。但地區(qū)的改變可能會影響庫的許多部分,其中一部分可能是我們不希望修改的。所以C語言支持針對不同的類項進(jìn)行修改,下面的一個宏, 指定一個類項:

? LC_COLLATE:影響字符串比較函數(shù) strcoll() 和 strxfrm() 。

? LC_CTYPE:影響字符處理函數(shù)的行為。

? LC_MONETARY:影響貨幣格式。

? LC_NUMERIC:影響 printf() 的數(shù)字格式。

? LC_TIME:影響時間格式 strftime() 和 wcsftime() 。

? LC_ALL - 針對所有類項修改,將以上所有類別設(shè)置為給定的語言環(huán)境。?

setlocale 函數(shù)用于修改當(dāng)前地區(qū),可以針對一個類項修改,也可以針對所有類項。?setlocale 的第一個參數(shù)可以是前面說明的類項中的一個,那么每次只會影響一個類項,如果第一個參數(shù)是LC_ALL,就會影響所有的類項。 C標(biāo)準(zhǔn)給第二個參數(shù)僅定義了2種可能取值:"C"(正常模式)和" "(本地模式)。 在任意程序執(zhí)行開始,都會隱藏式執(zhí)行調(diào)用:

setlocale(LC_ALL, "C");

當(dāng)?shù)貐^(qū)設(shè)置為"C"時,庫函數(shù)按正常方式執(zhí)行,小數(shù)點是一個點。 當(dāng)程序運(yùn)行起來后想改變地區(qū),就只能顯示調(diào)用setlocale函數(shù)。用" "作為第2個參數(shù),調(diào)用setlocale 函數(shù)就可以切換到本地模式,這種模式下程序會適應(yīng)本地環(huán)境。比如:切換到我們的本地模式后就支持寬字符(漢字)的輸出等。?

setlocale(LC_ALL, "");//切換到本地環(huán)境(注意這里雙引號里不能有空格)

那如果想在屏幕上打印寬字符,怎么打印呢? 寬字符的字面量必須加上前綴“L”,否則 C 語言會把字面量當(dāng)作窄字符類型處理。前綴“L”在單引號前面,表示寬字符,對應(yīng) wprintf() 的占位符為 %lc ;在雙引號前面,表示寬字符串,對應(yīng) wprintf() 的占位符為 %ls 。

舉例:

#include <stdio.h>
#include <locale.h>
int main()
{
    //切換到本地環(huán)境
    setlocale(LC_ALL, "");
    wprintf(L"%s\n", L"我要學(xué)編程");

    wchar_t wc1 = L'我';
    wchar_t wc2 = L'要';
    wchar_t wc3 = L'學(xué)';
    wchar_t wc4 = L'編';
    wchar_t wc5 = L'程';
    wprintf(L"%lc", wc1);
    wprintf(L"%lc", wc2);
    wprintf(L"%lc", wc3);
    wprintf(L"%lc", wc4);
    wprintf(L"%lc", wc5);
    return 0;
}

地圖,食物和蛇身的設(shè)計?

我們假設(shè)實現(xiàn)一個棋盤27行,58列的棋盤,再圍繞地圖畫出墻。

小游戲貪吃蛇的實現(xiàn)之C語言版,C語言,數(shù)據(jù)結(jié)構(gòu)(C語言版),c語言,開發(fā)語言,貪吃蛇游戲

由于1行的寬度是一列寬度的二倍,就可以按照上面的樣式繪制地圖。這些都用寬字符來打印。

初始化狀態(tài):假設(shè)蛇的長度是5,蛇身的每個節(jié)點是●,在固定的一個坐標(biāo)處,比如(24, 5)處開始出現(xiàn)蛇,連續(xù)5個節(jié)點。 注意:蛇的每個節(jié)點的x坐標(biāo)必須是2個倍數(shù),否則可能會出現(xiàn)蛇的一個節(jié)點有一半出現(xiàn)在墻體中, 另外一半在墻外的現(xiàn)象。 關(guān)于食物,就是在墻體內(nèi)隨機(jī)生成一個坐標(biāo)(x坐標(biāo)必須是2的倍數(shù)),坐標(biāo)不能和蛇的身體重合,然后打印★。食物的x坐標(biāo)也要是2的倍數(shù)。

在游戲運(yùn)行的過程中,蛇每次吃一個食物,蛇的身體就會變長一節(jié),如果我們使用鏈表存儲蛇的信 息,那么蛇的每一節(jié)其實就是鏈表的一個節(jié)點。每個節(jié)點只要記錄好蛇身節(jié)點在地圖上的坐標(biāo)就行, 所以蛇節(jié)點結(jié)構(gòu)如下:?

//蛇身的節(jié)點類型
typedef struct SnakeNode
{
	//坐標(biāo)
	int x;
	int y;
	//指向下一個節(jié)點的指針
	struct SnakeNode* next;
}SnakeNode, * pSnakeNode;

還得創(chuàng)建一些變量:指向蛇頭的指針,初始時蛇的速度,蛇的方向,食物,食物分?jǐn)?shù),總分,貪吃蛇的狀態(tài)。但是這些都比較麻煩,我們就創(chuàng)建一個貪吃蛇的結(jié)構(gòu)體來管理這些變量。

//貪吃蛇
typedef struct Snake
{
	pSnakeNode _pSnake;//指向蛇頭的指針
	pSnakeNode _pFood;//指向食物的指針
	DIRECTION _dir;//蛇的方向
	GAME_STATE _state;//游戲的運(yùn)行狀態(tài)
	int _FoodWeight;//一個食物的分?jǐn)?shù)
	int _score;//總分?jǐn)?shù)
	int _SleepTime;//休眠時間,時間越短,速度越快,時間越長,速度越慢
}Snake, * pSnake;

蛇的方向有四種:上,下,左,右。我們就可以枚舉出來。

//蛇的方向
typedef enum DIRECTION
{
	UP = 1,//上
	DOWN,//下
	LEFT,//左
	RIGHT//右
}DIRECTION;

游戲的運(yùn)行狀態(tài):正常運(yùn)行,正常退出,撞墻死亡,撞到自己死亡。

//游戲的狀態(tài)
typedef enum GAME_STATE
{
	OK,//正常運(yùn)行
	KILL_BY_WALL,//撞墻
	KILL_BY_SELF,//撞到自己
	END_NORMAL//正常退出
}GAME_STATE;

接下來就是正式的游戲設(shè)計。

首先分裝三個大的函數(shù)。

GameStart()—— 游戲的初始化

初始化的內(nèi)容:1,打印歡迎界面? 2,繪制貪吃蛇地圖? 3,初始化貪吃蛇和食物 。

打印歡迎界面?

小游戲貪吃蛇的實現(xiàn)之C語言版,C語言,數(shù)據(jù)結(jié)構(gòu)(C語言版),c語言,開發(fā)語言,貪吃蛇游戲

首先得分裝一個函數(shù)用來定位坐標(biāo)。

//定位光標(biāo)
void SetPos(short x, short y)
{
	HANDLE houtput = GetStdHandle(STD_OUTPUT_HANDLE);//獲取標(biāo)準(zhǔn)輸出的句柄
	COORD pos = { x, y };
	SetConsoleCursorPosition(houtput, pos);//設(shè)置光標(biāo)的位置
}

system("pause")是一個用于暫??刂婆_的函數(shù)。它會在控制臺輸出一個提示信息,等待用戶按下任意鍵后才會繼續(xù)執(zhí)行程序。

system("pause");

小游戲貪吃蛇的實現(xiàn)之C語言版,C語言,數(shù)據(jù)結(jié)構(gòu)(C語言版),c語言,開發(fā)語言,貪吃蛇游戲

由上面的界面切換到下面這個界面,就需要用到一個清理控制臺界面的函數(shù)。?

system("cls");//用于清理當(dāng)前控制臺的界面所有信息

打印歡迎界面:

//打印歡迎界面
void WelcomToGame()
{
	//首先得定位光標(biāo)
	SetPos(39, 10);
	printf("歡迎來到貪吃蛇小游戲\n");
	SetPos(40, 15);
	system("pause");//暫停
	system("cls");//清理屏幕

	SetPos(28, 10);
	printf("用↑.↓.←.→ 來控制蛇的移動!摁F3加速!摁F4減速!\n");
	SetPos(38, 11);
	printf("游戲即將開始,請做好準(zhǔn)備!\n");
	SetPos(40, 15);
	system("pause");
	system("cls");
}

繪制貪吃蛇地圖?

小游戲貪吃蛇的實現(xiàn)之C語言版,C語言,數(shù)據(jù)結(jié)構(gòu)(C語言版),c語言,開發(fā)語言,貪吃蛇游戲

上面這個就是我們要繪制的地圖。值得一提的是:這個方塊是寬字符,而使用wprintf來打印寬字符就得先將C語言環(huán)境轉(zhuǎn)化到本地環(huán)境。至于后面的打印,就是通過定位來循環(huán)打印。

先打印上下兩行,再打印左右兩列。

上一行的坐標(biāo)是(2*i,0),i 的范圍是0~28。? 下一行的坐標(biāo)是(2*i,25),i 的范圍是0~28。?

左一列的坐標(biāo)是(0,i),i 的范圍是1~25。? ? ? 右一列的坐標(biāo)是(56,i),i 的范圍是1~25。

注意:

1. 一行的打印就相當(dāng)于是打印了一列中的一個,因此用總列數(shù)-2就是我們要打印的列坐標(biāo)。

2. 列在打印時,需要先定位好坐標(biāo)。因為打印的順序是默認(rèn)從左到右的;而我們是要實現(xiàn)從上到下的打印。

#define WALL L'□'


//繪制地圖
void CreatMap()
{
	//打印上體墻
	for (int i = 0; i <= 28; i++)
	{
		wprintf(L"%lc", WALL);
	}
	SetPos(0, 26);//定位到下體墻的位置
	//打印下體墻
	for (int i = 0; i <= 28; i++)
	{
		wprintf(L"%lc", WALL);
	}
	//打印左體墻
	for (int i = 1; i <= 25; i++)
	{
		SetPos(0, i);
		wprintf(L"%lc", WALL);//用換行不行,因此加不加換行無所謂
	}
	//打印右體墻
	for (int i = 1; i <= 25; i++)
	{
		SetPos(56, i);
		wprintf(L"%lc", WALL);//用換行不行,因此加不加換行無所謂
	}
}

初始化貪吃蛇

既然要初始化蛇,首先就得有蛇,而蛇是用節(jié)點串起來的。因此我們只要創(chuàng)建5個節(jié)點,并且傳入我們想要的坐標(biāo)(我們想要蛇出現(xiàn)在哪個位置,這個位置最好是固定的,這里也是采用固定的位置。),最后把這些節(jié)點串起來就行了。

//創(chuàng)建一條蛇
pSnakeNode pcur = NULL;
pSnakeNode prev = NULL;
for (int i = 0; i < 5; i++)
{
	pSnakeNode tmp = (pSnakeNode)malloc(sizeof(SnakeNode));
	if (tmp == NULL)
	{
		perror("InitSnake():malloc:");
		return;
	}
	pcur = tmp;
	pcur->x = POS_X + 2 * i;
	pcur->y = POS_Y;
	pcur->next = NULL;
	if (ps->_pSnake == NULL)
	{
		//直接插入即可
		ps->_pSnake = pcur;
	}
	else
	{
		//尾插
		if (prev != NULL)
			prev->next = pcur;
	}
	prev = pcur;
}

打印蛇(打印整個鏈表)

#define BODY L'●'
#define HEAD L'◆'


//開始在控制臺上打印蛇
int count = 0;
while (pcur)
{
	SetPos(pcur->x, pcur->y);//定位
	if (count == 0)
	{
		count++;
		wprintf(L"%lc", HEAD);//打印蛇頭
	}
	else
	{
		wprintf(L"%lc", BODY);//打印蛇身
	}
	pcur = pcur->next;
}

設(shè)置貪吃蛇的屬性。

//設(shè)置貪吃蛇的屬性
ps->_dir = LEFT;//初始時蛇的方向向左
ps->_FoodWeight = 50;//一個食物50分
ps->_score = 0;//總分為0
ps->_SleepTime = 200;//單位是毫秒
ps->_state = OK;//正常運(yùn)行

?因為這里的蛇頭是在最左邊,所以這個蛇的初始方向不能是向右走,除此之外都可以。

初始化食物

初始化食物其實就是創(chuàng)建一個食物并且打印出來。

這個食物為了能夠被蛇給吃掉,x坐標(biāo)也必須是2的倍數(shù),并且這個食物應(yīng)該是要隨機(jī)生成的,還要在這個墻體中。?

	int x = 0;
	int y = 0;
	//隨機(jī)創(chuàng)建食物(食物的x坐標(biāo)必須是2的倍數(shù),因此要判斷)
again:
	do
	{
        //為了食物出現(xiàn)在墻內(nèi)
		x = rand() % 53 + 2;
		y = rand() % 25 + 1;

	} while (x % 2);
	//食物的坐標(biāo)不能和蛇身沖突
	pSnakeNode pcur = ps->_pSnake;
	//開始尋找看看是否與蛇身沖突
	while (pcur)
	{
		if (pcur->x == x && pcur->y == y)
		{
			goto again;//如果沖突了,就要回爐重造
		}
		pcur = pcur->next;
	}
	//開始創(chuàng)建食物的節(jié)點
	pSnakeNode tmp = (pSnakeNode)malloc(sizeof(SnakeNode));
	if (tmp == NULL)
	{
		perror("CreatFood():malloc:");
		return;
	}
	tmp->x = x;
	tmp->y = y;
	tmp->next = NULL;
	ps->_pFood = tmp;

打印食物

//打印食物
SetPos(x, y);
wprintf(L"%lc", FOOD);

GameRun()——游戲的運(yùn)行

1,打印幫助手冊? 2,貪吃蛇的相關(guān)運(yùn)行信息? 3,判斷貪吃蛇是否死亡

小游戲貪吃蛇的實現(xiàn)之C語言版,C語言,數(shù)據(jù)結(jié)構(gòu)(C語言版),c語言,開發(fā)語言,貪吃蛇游戲

上圖就是游戲運(yùn)行時的界面。

打印右側(cè)的幫助信息

//打印幫助信息
void PrintHelpInfo()
{
	SetPos(68, 10);
	printf("小提示:");
	SetPos(68, 13);
	printf("不能穿墻,不能咬到自己!");
	SetPos(68, 14);
	printf("用↑.↓.←.→ 來控制蛇的移動!");
	SetPos(68, 15);
	printf("摁F3加速!摁F4減速!");
	SetPos(68, 16);
	printf("加速將增加單個食物的分?jǐn)?shù)!");
	SetPos(68, 17);
	printf("減速將減少單個食物的分?jǐn)?shù)!");
	SetPos(68, 18);
	printf("摁Esc退出游戲!摁空格暫停游戲!");
}

貪吃蛇的相關(guān)運(yùn)行信息?

貪吃蛇要運(yùn)行起來,就得需要我們摁鍵來實現(xiàn)貪吃蛇的走動。所以接下來就是判斷哪個鍵是否摁過來判斷蛇的走向。而只要是蛇的狀態(tài)不等于OK時,此時就不需要再走了。

#define KEY_PRESS(VK) ((GetAsyncKeyState(VK) & 0x1) ? 1 : 0)


//接下來就是通過按鍵來判斷貪吃蛇的運(yùn)行狀態(tài)
do
{
	//打印分?jǐn)?shù)顯示
	SetPos(68, 7);
	printf("當(dāng)前總分?jǐn)?shù):%08d", ps->_score);
	SetPos(68, 8);
	printf("當(dāng)前食物分?jǐn)?shù):%02d", ps->_FoodWeight);
	//判斷摁了什么鍵,根據(jù)鍵來判斷要執(zhí)行的命令
	if (KEY_PRESS(VK_UP) && ps->_dir != DOWN)
	{
		ps->_dir = UP;//摁了↑,并且蛇不是往下走,就改變方向
	}
	else if (KEY_PRESS(VK_DOWN) && ps->_dir != UP)
	{
		ps->_dir = DOWN;
	}
	else if (KEY_PRESS(VK_LEFT) && ps->_dir != RIGHT)
	{
		ps->_dir = LEFT;
	}
	else if (KEY_PRESS(VK_RIGHT) && ps->_dir != LEFT)
	{
		ps->_dir = RIGHT;
	}
	else if (KEY_PRESS(VK_SPACE))
	{
		Pause();//暫停
	}
	else if (KEY_PRESS(VK_ESCAPE))
	{
		//退出游戲
		ps->_state = END_NORMAL;
	}
	else if (KEY_PRESS(VK_F3))
	{
		//加速(減少休眠時間)
		if (ps->_SleepTime > 80)//設(shè)置為4檔速度
		{
			ps->_SleepTime -= 30;
			ps->_FoodWeight += 10;
		}
	}
	else if (KEY_PRESS(VK_F4))
	{
		//減速
		if (ps->_FoodWeight > 10)//設(shè)置為4檔速度
		{
			ps->_SleepTime += 20;
			ps->_FoodWeight -= 10;
		}
	}
	//蛇開始走
	//走一步,就休息一下
	SnakeMove(ps);//蛇走一步的過程
	Sleep(ps->_SleepTime);
	//檢測是否撞墻
	KillByWall(ps);
	//檢測是否撞到自己
	KillBySelf(ps);
    //通過總分?jǐn)?shù)來判斷游戲是否結(jié)束
    if (ps->_score > 30000)
    {
	    SetPos(20, 13);
	    printf("恭喜你!成功通關(guān)!");
    }
} while (ps->_state == OK);//只有蛇的狀態(tài)正常才走

暫停的實現(xiàn)就只需要系統(tǒng)一直處于休眠狀態(tài)。?

void Pause()
{
	while (1)
	{
		//休眠200毫秒
		Sleep(200);
		//這個只能放到休眠的后面
		if (KEY_PRESS(VK_SPACE))
		{
			break;
		}
	}
}

當(dāng)進(jìn)入這個暫停函數(shù)就需要休眠,即使再次摁了空格鍵,也得先休眠一下。

蛇在走的時候,就是根據(jù)我們摁的鍵位來判斷蛇頭應(yīng)該出現(xiàn)在哪個地方。再通過鏈接蛇頭的下一個位置和蛇身以及釋放蛇身的尾節(jié)點。還有一個小細(xì)節(jié):如果蛇頭下一個位置是食物的話,就要吃掉食物,并且再創(chuàng)建一個食物,而如果不是食物的話,就只需要按照上面的步驟走就行了。因此就得先判斷是否為食物。

//蛇走一步的過程
void SnakeMove(pSnake ps)
{
	//創(chuàng)建一個節(jié)點來存放蛇要走的下一個節(jié)點
	pSnakeNode next = (pSnakeNode)malloc(sizeof(SnakeNode));
	if (next == NULL)
	{
		perror("SnakeMove():malloc:");
		return;
	}
	//根據(jù)方向來判斷蛇是怎么走的
	switch (ps->_dir)
	{
	case UP:
		next->x = ps->_pSnake->x;
		next->y = ps->_pSnake->y - 1;
		break;
	case DOWN:
		next->x = ps->_pSnake->x;
		next->y = ps->_pSnake->y + 1;
		break;
	case LEFT:
		next->x = ps->_pSnake->x - 2;
		next->y = ps->_pSnake->y;
		break;
	case RIGHT:
		next->x = ps->_pSnake->x + 2;
		next->y = ps->_pSnake->y;
		break;
	}
	//判斷蛇走的下一個節(jié)點是不是食物
	if (NextIsFood(next, ps))
	{
        //是食物就吃掉食物
		EatFood(next, ps);
	}
	else
	{
        //不是就不吃
		NoFood(next, ps);
	}
}

下一個位置是食物

//下一個位置是食物,就可以吃掉
void EatFood(pSnakeNode next, pSnake ps)
{
	//把這個節(jié)點(就是食物節(jié)點)頭插到蛇身就行
	ps->_pFood->next = ps->_pSnake;
	ps->_pSnake = ps->_pFood;
	//釋放掉這個節(jié)點(因為創(chuàng)建了兩個節(jié)點:一個食物節(jié)點,一個蛇頭的下一個節(jié)點)
	free(next);
	next = NULL;
	//打印蛇身
	pSnakeNode pcur = ps->_pSnake;
	int count = 0;
	while (pcur)
	{
		SetPos(pcur->x, pcur->y);//定位
		if (count == 0)
		{
			count++;
			wprintf(L"%lc", HEAD);//打印蛇頭
		}
		else
		{
			wprintf(L"%lc", BODY);//打印蛇身
		}
		pcur = pcur->next;
	}
    //分?jǐn)?shù)的增加
	ps->_score += ps->_FoodWeight;
	//重新創(chuàng)建食物
	CreatFood(ps);
}

下一個位置不是食物

//下一個位置不是食物
void NoFood(pSnakeNode next, pSnake ps)
{
	//把下一個位置的節(jié)點頭插到蛇身
	next->next = ps->_pSnake;
	ps->_pSnake = next;
	//把蛇身最后一個節(jié)點的空間釋放掉,順便打印蛇身
	pSnakeNode pcur = ps->_pSnake;
	int count = 0;
	while (pcur->next->next != NULL)
	{
		//遍歷時,可以直接打印
		SetPos(pcur->x, pcur->y);
		if (count == 0)
		{
			count++;
			wprintf(L"%lc", HEAD);
		}
		else
		{
			wprintf(L"%lc", BODY);
		}
		pcur = pcur->next;
	}
	//把最后一個節(jié)點的位置打印成空格
	SetPos(pcur->next->x, pcur->next->y);
	printf("  ");
	free(pcur->next);
	pcur->next = NULL;
}

如果不把蛇身的尾節(jié)點的位置打印成空格,那么上一次的痕跡就不會被消除。?會導(dǎo)致蛇身一直變長。? 走一步,再休息兩百毫秒,可以讓我們有時間來判斷貪吃蛇下一步需怎么走,如果不休息就會直接撞墻。

檢測是否撞墻只需要檢測蛇頭是否撞墻,因為蛇身的每一個節(jié)點是重復(fù)執(zhí)行蛇頭的操作。蛇頭不撞墻那么蛇身就沒有機(jī)會撞墻,如果蛇頭撞墻,那么就說明這個蛇撞墻了。

//檢測是否撞墻
void KillByWall(pSnake ps)
{
	//只要判斷蛇頭是否碰到墻就可以了
	if (ps->_pSnake->x == 0 || ps->_pSnake->x == 56
		|| ps->_pSnake->y == 0 || ps->_pSnake->y == 26)
	{
		ps->_state = KILL_BY_WALL;//改變蛇的狀態(tài)即可 
	}
}

檢測蛇是否撞到自身就只需要檢測蛇頭和蛇身的某一個節(jié)點是否重合就行了。

//檢測是否撞到自己
void KillBySelf(pSnake ps)
{
	//只要判斷蛇頭是否碰到自己的蛇身
	pSnakeNode pcur = ps->_pSnake->next;
	while (pcur)
	{
		if (pcur->x == ps->_pSnake->x && pcur->y == ps->_pSnake->y)
		{
			ps->_state = KILL_BY_SELF;//改變蛇的狀態(tài)即可
			break;
		}
		pcur = pcur->next;
	}
}

GameOver()——游戲的結(jié)束(善后工作)?

善后也就是把蛇身的節(jié)點釋放掉,并告訴玩家游戲結(jié)束的原因。

//結(jié)束游戲(善后工作)
void GameOver(pSnake ps)
{
	SetPos(20, 13);
	switch (ps->_state)
	{
	case KILL_BY_WALL:
		printf("很遺憾!撞墻死亡!");
		break;
	case KILL_BY_SELF:
		printf("很遺憾!撞到自己死亡!");
		break;
	case END_NORMAL:
		printf("玩家主動結(jié)束游戲!");
		break;
	}
	//釋放蛇身鏈表
	pSnakeNode prev = ps->_pSnake;
	pSnakeNode pcur = ps->_pSnake;
	while (pcur)
	{
		prev = pcur->next;
		free(pcur);
		pcur = prev;
	}
}

貪吃蛇源碼?

?Snake.h

#include <stdio.h>
#include <stdlib.h>
#include <Windows.h>
#include <locale.h>
#include <stdbool.h>
#include <time.h>

#define POS_X 24
#define POS_Y 5

#define WALL L'□'
#define BODY L'●'
#define FOOD L'★'
#define HEAD L'◆'

#define KEY_PRESS(VK) ((GetAsyncKeyState(VK) & 0x1) ? 1 : 0)

//游戲的狀態(tài)
typedef enum GAME_STATE
{
	OK,//正常運(yùn)行
	KILL_BY_WALL,//撞墻
	KILL_BY_SELF,//撞到自己
	END_NORMAL//正常退出
}GAME_STATE;

//蛇的方向
typedef enum DIRECTION
{
	UP = 1,//上
	DOWN,//下
	LEFT,//左
	RIGHT//右
}DIRECTION;

//蛇身的節(jié)點類型
typedef struct SnakeNode
{
	//坐標(biāo)
	int x;
	int y;
	//指向下一個節(jié)點的指針
	struct SnakeNode* next;
}SnakeNode, * pSnakeNode;


//貪吃蛇
typedef struct Snake
{
	pSnakeNode _pSnake;//指向蛇頭的指針
	pSnakeNode _pFood;//指向食物的指針
	DIRECTION _dir;//蛇的方向
	GAME_STATE _state;//游戲的運(yùn)行狀態(tài)
	int _FoodWeight;//一個食物的分?jǐn)?shù)
	int _score;//總分?jǐn)?shù)
	int _SleepTime;//休眠時間,時間越短,速度越快,時間越長,速度越慢
}Snake, * pSnake;


//定位光標(biāo)
void SetPos(short x, short y);

//初始化游戲
void GameStart(pSnake ps);

//打印歡迎界面
void WelcomToGame();

//繪制地圖
void CreatMap();

//初始化蛇
void InitSnake(pSnake ps);

//創(chuàng)建食物
void CreatFood(pSnake ps);

//游戲運(yùn)行
void GameRun(pSnake ps);

//蛇走一步的過程
void SnakeMove(pSnake ps);

//判斷蛇要走的下一個節(jié)點是否為食物
int NextIsFood(pSnakeNode next, pSnake ps);

//下一個位置是食物,就可以吃掉
void EatFood(pSnakeNode next, pSnake ps);

//下一個位置不是食物
void NoFood(pSnakeNode next, pSnake ps);

//檢測是否撞墻
void KillByWall(pSnake ps);

//檢測是否撞到自己
void KillBySelf(pSnake ps); 

//結(jié)束游戲(善后工作)
void GameOver(pSnake ps);

Snake.c

#include "Snake.h"


//定位光標(biāo)
void SetPos(short x, short y)
{
	HANDLE houtput = GetStdHandle(STD_OUTPUT_HANDLE);//獲取標(biāo)準(zhǔn)輸出的句柄
	COORD pos = { x, y };
	SetConsoleCursorPosition(houtput, pos);//設(shè)置光標(biāo)的位置
}


//打印歡迎界面
void WelcomToGame()
{
	//首先得定位光標(biāo)
	SetPos(39, 10);
	printf("歡迎來到貪吃蛇小游戲\n");
	SetPos(40, 15);
	system("pause");//暫停
	system("cls");//清理屏幕

	SetPos(28, 10);
	printf("用↑.↓.←.→ 來控制蛇的移動!摁F3加速!摁F4減速!\n");
	SetPos(38, 11);
	printf("游戲即將開始,請做好準(zhǔn)備!\n");
	SetPos(40, 15);
	system("pause");
	system("cls");
}


//繪制地圖
void CreatMap()
{
	//打印上體墻
	for (int i = 0; i <= 28; i++)
	{
		wprintf(L"%lc", WALL);
	}
	SetPos(0, 26);//定位到下體墻的位置
	//打印下體墻
	for (int i = 0; i <= 28; i++)
	{
		wprintf(L"%lc", WALL);
	}
	//打印左體墻
	for (int i = 1; i <= 25; i++)
	{
		SetPos(0, i);
		wprintf(L"%lc", WALL);
	}
	//打印右體墻
	for (int i = 1; i <= 25; i++)
	{
		SetPos(56, i);
		wprintf(L"%lc", WALL);
	}
}


//初始化蛇
void InitSnake(pSnake ps)
{
	//創(chuàng)建一條蛇
	pSnakeNode pcur = NULL;
	pSnakeNode prev = NULL;
	for (int i = 0; i < 5; i++)
	{
		pSnakeNode tmp = (pSnakeNode)malloc(sizeof(SnakeNode));
		if (tmp == NULL)
		{
			perror("InitSnake():malloc:");
			return;
		}
		pcur = tmp;
		pcur->x = POS_X + 2 * i;
		pcur->y = POS_Y;
		pcur->next = NULL;
		if (ps->_pSnake == NULL)
		{
			//直接插入即可
			ps->_pSnake = pcur;
		}
		else
		{
			//尾插
			if (prev != NULL)
				prev->next = pcur;
		}
		prev = pcur;
	}
	pcur = ps->_pSnake;
	//開始在控制臺上打印蛇
	int count = 0;
	while (pcur)
	{
		SetPos(pcur->x, pcur->y);//定位
		if (count == 0)
		{
			count++;
			wprintf(L"%lc", HEAD);//打印蛇頭
		}
		else
		{
			wprintf(L"%lc", BODY);//打印蛇身
		}
		pcur = pcur->next;
	}
	//設(shè)置貪吃蛇的屬性
	ps->_dir = LEFT;//初始時蛇的方向向左
	ps->_FoodWeight = 50;//一個食物50分
	ps->_score = 0;//總分為0
	ps->_SleepTime = 200;//單位是毫秒
	ps->_state = OK;//正常運(yùn)行
}


//創(chuàng)建食物
void CreatFood(pSnake ps)
{
	int x = 0;
	int y = 0;
	//隨機(jī)創(chuàng)建食物(食物的x坐標(biāo)必須是2的倍數(shù),因此要判斷)
again:
	do
	{
		x = rand() % 53 + 2;
		y = rand() % 25 + 1;
	} while (x % 2);
	//食物的坐標(biāo)不能和蛇身沖突
	pSnakeNode pcur = ps->_pSnake;
	//開始尋找看看是否與蛇身沖突
	while (pcur)
	{
		if (pcur->x == x && pcur->y == y)
		{
			goto again;
		}
		pcur = pcur->next;
	}
	//開始創(chuàng)建食物的節(jié)點
	pSnakeNode tmp = (pSnakeNode)malloc(sizeof(SnakeNode));
	if (tmp == NULL)
	{
		perror("CreatFood():malloc:");
		return;
	}
	tmp->x = x;
	tmp->y = y;
	tmp->next = NULL;
	ps->_pFood = tmp;
	//打印食物
	SetPos(x, y);
	wprintf(L"%lc", FOOD);
}


//初始化游戲
void GameStart(pSnake ps)
{
	//設(shè)置窗口大小以及名字
	system("mode con cols=100 lines=30");
	system("title 貪吃蛇");
	//隱藏光標(biāo)信息,為了后續(xù)打印
	HANDLE houtput = GetStdHandle(STD_OUTPUT_HANDLE);//獲取標(biāo)準(zhǔn)輸出的句柄
	CONSOLE_CURSOR_INFO CursorInfo;
	GetConsoleCursorInfo(houtput, &CursorInfo);//獲取光標(biāo)信息
	CursorInfo.bVisible = false;//隱藏光標(biāo)
	SetConsoleCursorInfo(houtput, &CursorInfo);//設(shè)置光標(biāo)狀態(tài)

	//打印歡迎界面和功能介紹
	WelcomToGame();
	//繪制地圖
	CreatMap();
	//初始化蛇
	InitSnake(ps);
	//創(chuàng)建食物
	CreatFood(ps);
}


//打印幫助信息
void PrintHelpInfo()
{
	SetPos(68, 10);
	printf("小提示:");
	SetPos(68, 13);
	printf("不能穿墻,不能咬到自己!");
	SetPos(68, 14);
	printf("用↑.↓.←.→ 來控制蛇的移動!");
	SetPos(68, 15);
	printf("摁F3加速!摁F4減速!");
	SetPos(68, 16);
	printf("加速將增加單個食物的分?jǐn)?shù)!");
	SetPos(68, 17);
	printf("減速將減少單個食物的分?jǐn)?shù)!");
	SetPos(68, 18);
	printf("摁Esc退出游戲!摁空格暫停游戲!");
}


void Pause()
{
	while (1)
	{
		//休眠200毫秒
		Sleep(200);
		//這個只能放到休眠的后面
		if (KEY_PRESS(VK_SPACE))
		{
			break;
		}
	}
}


//判斷蛇要走的下一個節(jié)點是否為食物
int NextIsFood(pSnakeNode next, pSnake ps)
{
	return ((next->x == ps->_pFood->x) && (next->y == ps->_pFood->y));
}


//下一個位置是食物,就可以吃掉
void EatFood(pSnakeNode next, pSnake ps)
{
	//把這個節(jié)點(就是食物節(jié)點)頭插到蛇身就行
	ps->_pFood->next = ps->_pSnake;
	ps->_pSnake = ps->_pFood;
	//釋放掉這個節(jié)點(因為有兩個節(jié)點)
	free(next);
	next = NULL;
	//打印蛇身
	pSnakeNode pcur = ps->_pSnake;
	int count = 0;
	while (pcur)
	{
		SetPos(pcur->x, pcur->y);//定位
		if (count == 0)
		{
			count++;
			wprintf(L"%lc", HEAD);//打印蛇頭
		}
		else
		{
			wprintf(L"%lc", BODY);//打印蛇身
		}
		pcur = pcur->next;
	}
	ps->_score += ps->_FoodWeight;
	//重新創(chuàng)建食物
	CreatFood(ps);
}


//下一個位置不是食物
void NoFood(pSnakeNode next, pSnake ps)
{
	//把下一個位置的節(jié)點頭插到蛇身
	next->next = ps->_pSnake;
	ps->_pSnake = next;
	//把蛇身最后一個節(jié)點的空間釋放掉,順便打印蛇身
	pSnakeNode pcur = ps->_pSnake;
	int count = 0;
	while (pcur->next->next != NULL)
	{
		//遍歷時,可以直接打印
		SetPos(pcur->x, pcur->y);
		if (count == 0)
		{
			count++;
			wprintf(L"%lc", HEAD);
		}
		else
		{
			wprintf(L"%lc", BODY);
		}
		pcur = pcur->next;
	}
	//把最后一個節(jié)點的位置打印成空格
	SetPos(pcur->next->x, pcur->next->y);
	printf("  ");
	free(pcur->next);
	pcur->next = NULL;
}



//蛇走一步的過程
void SnakeMove(pSnake ps)
{
	//創(chuàng)建一個節(jié)點來存放蛇要走的下一個節(jié)點
	pSnakeNode next = (pSnakeNode)malloc(sizeof(SnakeNode));
	if (next == NULL)
	{
		perror("SnakeMove():malloc:");
		return;
	}
	//根據(jù)方向來判斷蛇是怎么走的
	switch (ps->_dir)
	{
	case UP:
		next->x = ps->_pSnake->x;
		next->y = ps->_pSnake->y - 1;
		break;
	case DOWN:
		next->x = ps->_pSnake->x;
		next->y = ps->_pSnake->y + 1;
		break;
	case LEFT:
		next->x = ps->_pSnake->x - 2;
		next->y = ps->_pSnake->y;
		break;
	case RIGHT:
		next->x = ps->_pSnake->x + 2;
		next->y = ps->_pSnake->y;
		break;
	}
	//判斷蛇走的下一個節(jié)點是不是食物
	if (NextIsFood(next, ps))
	{
		EatFood(next, ps);
	}
	else
	{
		NoFood(next, ps);
	}
}


//檢測是否撞墻
void KillByWall(pSnake ps)
{
	//只要判斷蛇頭是否碰到墻就可以了
	if (ps->_pSnake->x == 0 || ps->_pSnake->x == 56
		|| ps->_pSnake->y == 0 || ps->_pSnake->y == 26)
	{
		ps->_state = KILL_BY_WALL; 
	}
}


//檢測是否撞到自己
void KillBySelf(pSnake ps)
{
	//只要判斷蛇頭是否碰到自己的蛇身
	pSnakeNode pcur = ps->_pSnake->next;
	while (pcur)
	{
		if (pcur->x == ps->_pSnake->x && pcur->y == ps->_pSnake->y)
		{
			ps->_state = KILL_BY_SELF;
			break;
		}
		pcur = pcur->next;
	}
}


//游戲運(yùn)行
void GameRun(pSnake ps)
{
	//先打印幫助信息
	PrintHelpInfo();
	//接下來就是通過按鍵來判斷貪吃蛇的運(yùn)行狀態(tài)
	do
	{
		//打印分?jǐn)?shù)顯示
		SetPos(68, 7);
		printf("當(dāng)前總分?jǐn)?shù):%05d", ps->_score);
		SetPos(68, 8);
		printf("當(dāng)前食物分?jǐn)?shù):%02d", ps->_FoodWeight);
		//判斷摁了什么鍵,根據(jù)鍵來判斷要執(zhí)行的命令
		if (KEY_PRESS(VK_UP) && ps->_dir != DOWN)
		{
			ps->_dir = UP;//摁了↑,并且蛇不是往下走,就改變方向
		}
		else if (KEY_PRESS(VK_DOWN) && ps->_dir != UP)
		{
			ps->_dir = DOWN;
		}
		else if (KEY_PRESS(VK_LEFT) && ps->_dir != RIGHT)
		{
			ps->_dir = LEFT;
		}
		else if (KEY_PRESS(VK_RIGHT) && ps->_dir != LEFT)
		{
			ps->_dir = RIGHT;
		}
		else if (KEY_PRESS(VK_SPACE))
		{
			Pause();//暫停
		}
		else if (KEY_PRESS(VK_ESCAPE))
		{
			//退出游戲
			ps->_state = END_NORMAL;
		}
		else if (KEY_PRESS(VK_F3))
		{
			//加速(減少休眠時間)
			if (ps->_SleepTime > 80)//設(shè)置為4檔速度
			{
				ps->_SleepTime -= 30;
				ps->_FoodWeight += 10;
			}
		}
		else if (KEY_PRESS(VK_F4))
		{
			//減速
			if (ps->_FoodWeight > 10)
			{
				ps->_SleepTime += 20;
				ps->_FoodWeight -= 10;
			}
		}
		//蛇開始走
		//走一步,就休息一下
		SnakeMove(ps);//蛇走一步的過程
		Sleep(ps->_SleepTime);
		//檢測是否撞墻
		KillByWall(ps);
		//檢測是否撞到自己
		KillBySelf(ps);
		if (ps->_score > 30000)
		{
			SetPos(20, 13);
			printf("恭喜你!成功通關(guān)!");
			break;
		}
	} while (ps->_state == OK);
}


//結(jié)束游戲(善后工作)
void GameOver(pSnake ps)
{
	SetPos(20, 13);
	switch (ps->_state)
	{
	case KILL_BY_WALL:
		printf("很遺憾!撞墻死亡!");
		break;
	case KILL_BY_SELF:
		printf("很遺憾!撞到自己死亡!");
		break;
	case END_NORMAL:
		printf("玩家主動結(jié)束游戲!");
		break;
	}
	//釋放蛇身鏈表
	pSnakeNode prev = ps->_pSnake;
	pSnakeNode pcur = ps->_pSnake;
	while (pcur)
	{
		prev = pcur->next;
		free(pcur);
		pcur = prev;
	}
}

?好啦!本期貪吃蛇游戲的學(xué)習(xí)之旅到此結(jié)束了!我們下一期再一起學(xué)習(xí)吧!文章來源地址http://www.zghlxwxcb.cn/news/detail-856283.html

到了這里,關(guān)于小游戲貪吃蛇的實現(xiàn)之C語言版的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點擊違法舉報進(jìn)行投訴反饋,一經(jīng)查實,立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費用

相關(guān)文章

  • C語言之實現(xiàn)貪吃蛇小游戲篇(2)

    目錄 ??測試游戲test.c ??游戲頭文件包含函數(shù)聲明snake.h ??游戲?qū)崿F(xiàn)snake.c 屏幕錄制 2023-12-02 204515 ? ?????最后感謝大家的閱讀,若有錯誤和不足,歡迎指正!乖乖敲代碼哦!? 代碼---------→【唐棣棣 (TSQXG) - Gitee.com】 聯(lián)系---------→【郵箱:2784139418@qq.com】

    2024年02月05日
    瀏覽(23)
  • C語言從零實現(xiàn)貪吃蛇小游戲

    C語言從零實現(xiàn)貪吃蛇小游戲

    制作不易,點贊關(guān)注一下唄?。?! 文章目錄 前言 一.? 技術(shù)要點 二、 WIN32API介紹 三、 貪吃蛇游戲設(shè)計與分析? ? ? ? ?1.游戲開始前的初始化 ? ? ? ? 2.游戲運(yùn)行的邏輯? 總結(jié) 當(dāng)我們掌握鏈表這樣的數(shù)據(jù)結(jié)構(gòu)之后,我們就可以用它來做一些小項目,比如童年小游戲貪吃蛇

    2024年02月20日
    瀏覽(27)
  • 【C語言小游戲】貪吃蛇

    【C語言小游戲】貪吃蛇

    ??使?C語?在Windows環(huán)境的控制臺中模擬實現(xiàn)經(jīng)典?游戲貪吃蛇 實現(xiàn)基本的功能: 貪吃蛇地圖繪制 蛇吃?物的功能 (上、下、左、右?向鍵控制蛇的動作) 蛇撞墻死亡 蛇撞??死亡 計算得分 蛇?加速、減速 暫停游戲 游戲指引頁面 游戲頁面 指針; 動態(tài)內(nèi)存; 結(jié)構(gòu)體;

    2024年01月19日
    瀏覽(24)
  • C語言——貪吃蛇小游戲

    C語言——貪吃蛇小游戲

    目錄 一、ncurse 1.1 為什么需要用ncurse: 1.2 ncurse的輸入輸出: 1.2.1 如何使用ncurse: 1.2.2 編譯ncurse的程序: 1.2.3 測試輸入一個按鍵ncurse的響應(yīng)速度: 1.3 ncurse上下左右鍵獲?。?1.3.1 如何查看宏定義的.h文件: 1.3.2 ncurse上下左右鍵獲?。?二、地圖規(guī)劃 2.1 地圖規(guī)劃算法顯示第一

    2024年02月07日
    瀏覽(24)
  • 小游戲:人生中寫的第一個小游戲——貪吃蛇(C語言)

    小游戲:人生中寫的第一個小游戲——貪吃蛇(C語言)

    ????????小編開了一個關(guān)于游戲的專欄,主要是運(yùn)用easyx圖形庫進(jìn)行的。 ? ? ? ?第一章:人生中寫的第一個小游戲——貪吃蛇(C語言) ????????這個游戲的代碼我在gitee上發(fā)布了,大家如果不嫌棄,可以進(jìn)入這個網(wǎng)址進(jìn)行查看和復(fù)制:https://gitee.com/rising-sun-1。 ? ? ?

    2024年02月09日
    瀏覽(32)
  • C語言實戰(zhàn)項目-貪吃蛇小游戲

    C語言實戰(zhàn)項目-貪吃蛇小游戲

    1.定義蛇對象、食物對象 2.初始化蛇、初始化食物 3.控制流程: ( 1)蛇頭和墻壁的碰撞 (2)蛇頭和蛇身體碰撞 (3)蛇頭和食物碰撞 (4)移動速度增大 4.游戲效果: ( 1)蛇身增長 (2)食物消失 -- 新食物產(chǎn)生 (3)分?jǐn)?shù)累加 (4)移動速度增大 (5)蛇的移動 (6)顯示分

    2024年02月19日
    瀏覽(29)
  • C語言結(jié)課實戰(zhàn)項目_貪吃蛇小游戲

    C語言結(jié)課實戰(zhàn)項目_貪吃蛇小游戲

    ??所屬專欄:C語言?? ??作者主頁:嶔某?? 游戲源代碼鏈接: function/貪吃蛇 · 欽某/c-language-learning - 碼云 - 開源中國 (gitee.com) ? 貪吃蛇地圖繪制 ? 蛇吃?物的功能(上、下、左、右?向鍵控制蛇的動作) ? 蛇撞墻死亡 ? 蛇撞??死亡 ? 計算得分 ? 蛇?加速、

    2024年04月26日
    瀏覽(17)
  • 【C語言】做一個貪吃蛇小游戲,完整代碼&附帶視頻演示

    【C語言】做一個貪吃蛇小游戲,完整代碼&附帶視頻演示

    視頻演示: https://www.bilibili.com/video/BV1pt421a7Nu/?spm_id_from=333.999.0.0vd_source=82b65865be0947de29bd55efc8cdb40a 編譯環(huán)境:linux(Vmware16.2.4 + Ubantu20.04.3); 小蛇??只能在固定的范圍內(nèi)活動; 可以利用鍵盤方向鍵控制小蛇??的前進(jìn)方向; 活動范圍內(nèi)會隨機(jī)生成食物; 小蛇??吃到食物,身

    2024年02月21日
    瀏覽(27)
  • TypeScript實現(xiàn)一個貪吃蛇小游戲

    TypeScript實現(xiàn)一個貪吃蛇小游戲

    游戲效果 文件目錄 準(zhǔn)備1 :新建index.html,編寫游戲靜態(tài)頁面 準(zhǔn)備2 :使用less,修改樣式,編寫CSS 準(zhǔn)備3: 創(chuàng)建4個類:食物類-Food、記分牌等級類-ScorePanel、蛇類-Snake、操控類-GameControl 準(zhǔn)備4 :創(chuàng)建index.ts文件,執(zhí)行游戲

    2024年01月19日
    瀏覽(25)
  • 挑戰(zhàn)!貪吃蛇小游戲的實現(xiàn)(2)

    挑戰(zhàn)!貪吃蛇小游戲的實現(xiàn)(2)

    在貪吃蛇小游戲的實現(xiàn)(1)中,我們學(xué)習(xí)了win32 相關(guān)的一些知識,本篇文章,博主將帶領(lǐng)大家從0開始實現(xiàn)貪吃蛇小游戲! locale.h實現(xiàn)本地化 ,該頭文件提供的函數(shù)用于控制C標(biāo)準(zhǔn)庫中對于不同的地區(qū)會產(chǎn)生不一樣行為的部分,如:數(shù)字量的格式,貨幣量的格式,字符集以及日

    2024年02月21日
    瀏覽(25)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包