純C語言編寫貪吃蛇(附源碼,無EasyX、MFC)


       大一下學期,我所選的C語言工程實踐是寫一個貪吃蛇游戲。那幾天真的挺肝的,完成本專業的答辯之后就沒怎么動過這程序了。那時候寫的貪吃蛇,還有一個棧溢出的問題沒有解決,是因為當時所學知識有限,還沒想到較好的解決方法。現在大二上學期,在上了好幾節數據結構之后,對棧有了一定的了解,隨着對棧的學習,我想出了解決我寫的貪吃蛇棧溢出的辦法。其實是前兩天剛剛有這個想法,剛剛才測試並實現了,辦法可行。現在我加入了計算機學院的創新開放實驗室,打算做的一個項目是微信小程序。以后想記錄一下我的開發過程和一些經歷,又剛剛完善好貪吃蛇的代碼,就簡單記錄一下吧。
       因為代碼比較長,先把參考資料寫一下,想自己手寫一遍的建議先看參考資料,再看這里的代碼

參考資料

[1] C語言如何編寫貪吃蛇小游戲基礎_百度經驗:
https://jingyan.baidu.com/article/e9fb46e14624487520f76658.html
[2] C語言學習:三天寫好貪吃蛇小游戲(一):
http://baijiahao.baidu.com/s?id=1600645476423742053&wfr=spider&for=pc
[3] C語言學習:三天寫好貪吃蛇小游戲(二):
http://baijiahao.baidu.com/s?id=1600729030233953401&wfr=spider&for=pc
[4] C語言學習:三天寫好貪吃蛇小游戲(三):
http://baijiahao.baidu.com/s?id=1600902215143197241&wfr=spider&for=pc
[5] 用C語言實現一個貪吃蛇游戲 - Calm的博客 - CSDN博客:
https://blog.csdn.net/huaijiu123/article/details/82054208
[6] 誰能解釋一下 HANDLE hConsole =GetStdHandle((STD_OUTPUT_HANDLE))在C語言中是什么意思_百度知道:
https://zhidao.baidu.com/question/529197139.html
[7] 純C語言實現貪吃蛇游戲(VC6.0) - CSDN博客:
https://blog.csdn.net/gin1008/app/article/details/52781106
[8] 在c語言中怎么實現輸入esc退出 其他鍵繼續_百度知道:
https://zhidao.baidu.com/question/403428708.html

源代碼

/*預處理*/
#include <windows.h>
#include <stdio.h>
#include <conio.h>
#include <string.h>
#include <time.h>

/*宏定義*/
#define YES 1
#define NO 0
			//蛇的移動方向
#define U 1	//上
#define D 2	//下
#define L 3	//左
#define R 4	//右
#define RESPEED 250	//蛇的移動速度

/*定義節點*/
typedef struct SNAKE
{
	int x;
	int y;
	struct SNAKE* next;
}snake;

/*全局變量*/
snake* head, * food;	//蛇頭指針,食物指針
snake* q;	//遍歷蛇的時候用到的指針

/*【以下為所有函數的聲明】*/
void HideCursor(void);	//隱藏光標
void color(short int num);	//顏色函數
void StartWindow(void);	//開始界面
int gotoxy(int x, int y);	//定位光標位置
void creatMap(void);	//創建地圖
void notice(int* score, int* highscore, int* Time, int* LongTime);	//提示
void initsnake(void);	//初始化蛇身 
int biteself(unsigned long* sleeptime);	//判斷是否咬到了自己
int createfood(void);	//隨機出現食物
void endgame(int* score, int* highscore, int* endgamestatus, int* Time, int* LongTime);	//結束游戲
void pause(int* PauseBegin, int* PauseEnd);	//暫停游戲

void gamecontrol(unsigned long* sleeptime, int* count, int* score, int* highscore, int* status, int* endgamestatus,
	int* Time, int* LongTime, int* TimeBegin, int* TimeEnd, int* TimePause, int* PauseBegin, int* PauseEnd);	//控制游戲(包含蛇不能穿牆)

void snakemove(unsigned long* sleeptime, int* count, int* score, int* status, int* endgamestatus);	//蛇移動
void gamestart(int* score, int* highscore, int* endgamestatus, int* Time, int* LongTime, int* TimeBegin);	//游戲初始化

void gamecontinue(unsigned long* sleeptime, int* count, int* score, int* highscore, int* status, int* endgamestatus,
	int* Time, int* LongTime, int* TimeBegin, int* TimeEnd, int* TimePause, int* PauseBegin, int* PauseEnd);	//再來一局

void stop(unsigned long* sleeptime);	//蛇停止移動
void start(unsigned long* sleeptime);	//蛇恢復移動
void reset(int* count, int* score, int* Time, int* TimeBegin, int* TimeEnd, int* TimePause, int* PauseBegin, int* PauseEnd);	//重置多項數據
void updatescore(int* score, int* highscore, int* Time, int* LongTime);	//更新多項數據

int main(void)
{
	unsigned long sleeptime = RESPEED;
	int score = 0, highscore = 0, count = 0;	//count是記錄吃到食物的次數
	int status, endgamestatus = 0;	//游戲結束情況,0未開始游戲前退出,1撞到牆,2咬到自己,3主動退出游戲,4通關
	int TimeBegin, TimeEnd;
	int Time, LongTime, TimePause, PauseBegin, PauseEnd;

	Time = LongTime = TimePause = PauseBegin = PauseEnd = 0;

	HideCursor();
	gamestart(&score, &highscore, &endgamestatus, &Time, &LongTime, &TimeBegin);
	gamecontrol(&sleeptime, &count, &score, &highscore, &status, &endgamestatus, &Time, &LongTime, &TimeBegin, &TimeEnd, &TimePause, &PauseBegin, &PauseEnd);
	endgame(&score, &highscore, &endgamestatus, &Time, &LongTime);
	gamecontinue(&sleeptime, &count, &score, &highscore, &status, &endgamestatus, &Time, &LongTime, &TimeBegin, &TimeEnd, &TimePause, &PauseBegin, &PauseEnd);

	return 0;
}

void HideCursor(void)	//隱藏光標
{
	CONSOLE_CURSOR_INFO cursor_info = { 1, 0 };
	SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &cursor_info);
}

void color(short int num)
{
	HANDLE hConsole = GetStdHandle((STD_OUTPUT_HANDLE));
	SetConsoleTextAttribute(hConsole, num);
}

void StartWindow(void)
{
	short int i;

	system("mode con cols=120 lines=30");	//設置窗口大小

	printf("溫馨提示:請使用鍵盤操作(鼠標點擊可能會導致程序出錯)\n");
	printf("╔═══════════════════════════════════════════════════╗ \n");
	for (i = 0; i < 26; i++)
	{
		printf("║						  ║ \n");
	}
	printf("╚═══════════════════════════════════════════════════╝ \n");
	gotoxy(23, 2);
	color(3);
	printf("貪吃蛇");
	for (i = 15; ; i--)
	{
		gotoxy(18, 4);
		color(i);
		printf("按任意鍵加載程序");
		Sleep(600);
		if (i == 1)
		{
			i = 15;
		}
		if (kbhit())	//判斷是否按鍵,等待輸入按鍵為0,按鍵為1
		{
			break;
		}
	}
	gotoxy(10, 4);
	printf("1.開始游戲          2.退出游戲");
	getch();
}

int gotoxy(int x, int y)
{
	HANDLE handle;	//定義句柄變量handle,創建一個句柄
	COORD pos;	//定義結構體coord (坐標系coord)
	pos.X = x;	//橫坐標x
	pos.Y = y;	//縱坐標y
	handle = GetStdHandle(STD_OUTPUT_HANDLE);	//獲取控制台輸出句柄(值為-11)
	SetConsoleCursorPosition(handle, pos);	//移動光標
	return YES;
}

void creatMap(void)
{
	int i;
	//地圖大小:長24×寬20
	for (i = 2; i < 52; i += 2)	//打印上下邊框
	{
		color(195);
		gotoxy(i, 6);
		printf("■");
		gotoxy(i, 27);
		printf("■");
	}
	for (i = 7; i < 28; i++)	//打印左右邊框
	{
		gotoxy(2, i);
		printf("■");
		gotoxy(50, i);
		printf("■");
	}
}

void notice(int* score, int* highscore, int* Time, int* LongTime)
{
	system("title 2018051170 Project:貪吃蛇");
	gotoxy(4, 4);
	color(15);
	printf("得分:%3d 最高分:%3d 生存:%4ds 最久生存:%4ds", *score, *highscore, *Time, *LongTime);
	gotoxy(60, 7);
	printf("Author: 2018051170 Project: 貪吃蛇");
	gotoxy(60, 9);
	printf("游戲說明:");
	gotoxy(60, 10);
	printf("不能穿牆,不能咬到自己");
	gotoxy(60, 11);
	printf("↑ ↓ ← →控制蛇的移動");
	gotoxy(60, 12);
	printf("ESC:退出游戲	空格:暫停游戲");
}

void initsnake(void)
{
	int i;
	snake* tail;

	tail = (snake*)malloc(sizeof(snake));	//從蛇尾開始,插頭法,以x,y設定開始的位置 
	tail->x = 26;
	tail->y = 14;
	tail->next = NULL;
	for (i = 1; i < 3; i++)
	{
		head = (snake*)malloc(sizeof(snake));
		head->next = tail;
		head->x = 26 - 2 * i;
		head->y = 14;
		tail = head;
	}
	while (tail != NULL)	//從頭到為,輸出蛇身
	{
		gotoxy(tail->x, tail->y);
		if (i == 3)
		{
			color(2);
			printf("●");
			i++;
		}

		else if (tail != NULL)
		{
			color(2);
			printf("■");
		}
		tail = tail->next;
	}
}

int biteself(unsigned long* sleeptime)
{
	snake* self;

	self = head->next;
	while (self != NULL)
	{
		if (self->x == head->x && self->y == head->y)
		{
			stop(sleeptime);
			return YES;
		}
		self = self->next;
	}
	return NO;
}

int createfood(void)
{
	snake* food_1;

	food_1 = (snake*)malloc(sizeof(snake));
	srand((unsigned)time(NULL));	//產生一個隨機數

	while ((food_1->x % 2) != 0)	//保證其為偶數,使得食物能與蛇頭對其
	{
		food_1->x = rand() % 50;	//保證其在牆壁里X1 < X < X2
		if (food_1->x <= 4)
		{
			food_1->x = food_1->x + 4;
		}
	}
	food_1->y = rand() % 27;	//保證其在牆壁里Y1 < Y < Y2
	if (food_1->y < 7)
	{
		food_1->y = food_1->y + 7;
	}
	q = head;

	while (q != NULL)	//判斷蛇身是否與食物重合
	{
		if (q->x == food_1->x && q->y == food_1->y)
		{
			free(food_1);
			return 1;
		}

		if (q->next == NULL)
		{
			break;
		}
		q = q->next;
	}

	gotoxy(food_1->x, food_1->y);
	food = food_1;
	color(3);
	printf("★");
	return 0;
}

void endgame(int* score, int* highscore, int* endgamestatus, int* Time, int* LongTime)
{
	color(15);
	gotoxy(60, 14);
	if (*endgamestatus == 0)
	{
		printf("您退出了游戲。");
	}
	else
	{
		if (*endgamestatus == 1)
		{
			printf("您撞到牆了,游戲結束。");
		}
		else if (*endgamestatus == 2)
		{
			printf("您咬到自己了,游戲結束。");
		}
		else if (*endgamestatus == 3)
		{
			printf("您已經結束了游戲。");
		}
		else if (*endgamestatus == 4)
		{
			printf("恭喜您通關了游戲!");
		}
		gotoxy(60, 15);
		printf("您的得分是: %d", *score);
		updatescore(score, highscore, Time, LongTime);
	}
}

void pause(int* PauseBegin, int* PauseEnd)
{
	*PauseBegin = time(NULL);
	while (1)
	{
		Sleep(300);
		if (GetAsyncKeyState(VK_SPACE))
		{
			*PauseEnd = time(NULL);
			break;
		}
	}
}

void gamecontrol(unsigned long* sleeptime, int* count, int* score, int* highscore, int* status, int* endgamestatus,
	int* Time, int* LongTime, int* TimeBegin, int* TimeEnd, int* TimePause, int* PauseBegin, int* PauseEnd)
{
	*status = L;
	while (1)
	{
		*TimeEnd = time(NULL);
		*TimePause = *TimePause + *PauseEnd - *PauseBegin;
		*PauseBegin = *PauseEnd = 0;
		*Time = *TimeEnd - *TimeBegin - *TimePause;

		//實時更新得分
		gotoxy(4, 4);
		color(15);
		printf("得分:%3d 最高分:%3d 生存:%4ds 最久生存:%4ds", *score, *highscore, *Time, *LongTime);

		//如果撞牆,停止蛇的移動
		if (head->x == 2 || head->x == 50 || head->y == 6 || head->y == 27)
		{
			stop(sleeptime);
			*endgamestatus = 1;
			break;
		}
		//如果咬到自己(在biteself函數里停止蛇的移動)
		if (biteself(sleeptime) == 1)
		{
			*endgamestatus = 2;
			break;
		}
		//如果通關
		if (*endgamestatus == 4)
		{
			break;
		}
		//讀取到【↑】且蛇頭指向不為【↓】
		if (GetAsyncKeyState(VK_UP) && *status != D)
		{
			*status = U;
		}
		//讀取到【↓】且蛇頭指向不為【↑】
		else if (GetAsyncKeyState(VK_DOWN) && *status != U)
		{
			*status = D;
		}
		//讀取到【←】且蛇頭指向不為【→】
		else if (GetAsyncKeyState(VK_LEFT) && *status != R)
		{
			*status = L;
		}
		//讀取到【→】且蛇頭指向不為【←】
		else if (GetAsyncKeyState(VK_RIGHT) && *status != L)
		{
			*status = R;
		}
		else if (GetAsyncKeyState(VK_SPACE))	//讀取到【空格】
		{
			pause(PauseBegin, PauseEnd);
		}
		else if (GetAsyncKeyState(VK_ESCAPE))	//讀取到【ESC】
		{
			stop(sleeptime);
			*endgamestatus = 3;
			break;
		}

		Sleep(*sleeptime);
		snakemove(sleeptime, count, score, status, endgamestatus);
	}
}

void snakemove(unsigned long* sleeptime, int* count, int* score, int* status, int* endgamestatus)
{
	int i = 0, flag = 1;
	snake* nexthead;
	nexthead = (snake*)malloc(sizeof(snake));

	if (*count == 477)
	{
		stop(sleeptime);
		*endgamestatus = 4;
	}
	else
	{
		if (*status == U)
		{
			nexthead->x = head->x;
			nexthead->y = head->y - 1;
			if (nexthead->x == food->x && nexthead->y == food->y) //如果前面有食物
			{
				nexthead->next = head;
				head = nexthead;
				q = head;
				while (q != NULL)
				{
					gotoxy(q->x, q->y);
					if (i == 0)
					{
						color(2);
						printf("●");
						i++;
					}
					else
					{
						color(2);
						printf("■");
					}
					q = q->next;
				}
				(*score)++;
				(*count)++;
				if (*count != 477)
				{
					while (flag)
					{
						flag = createfood();
					}
				}
			}
			else	//如果沒有食物
			{
				nexthead->next = head;
				head = nexthead;
				q = head;
				while (q->next->next != NULL)
				{
					gotoxy(q->x, q->y);
					if (i == 0)
					{
						color(2);
						printf("●");
						i++;
					}
					else
					{
						color(2);
						printf("■");
					}
					q = q->next;
				}
				gotoxy(q->next->x, q->next->y);
				color(0);
				printf("  ");
				free(q->next);
				q->next = NULL;
			}
		}
		if (*status == D)
		{
			nexthead->x = head->x;
			nexthead->y = head->y + 1;
			if (nexthead->x == food->x && nexthead->y == food->y)	//如果前面有食物
			{
				nexthead->next = head;
				head = nexthead;
				q = head;
				while (q != NULL)
				{
					gotoxy(q->x, q->y);
					if (i == 0)
					{
						color(2);
						printf("●");
						i++;
					}
					else
					{
						color(2);
						printf("■");
					}
					q = q->next;
				}
				(*score)++;
				(*count)++;
				if (*count != 477)
				{
					while (flag)
					{
						flag = createfood();
					}
				}
			}
			else	//如果沒有食物
			{
				nexthead->next = head;
				head = nexthead;
				q = head;
				while (q->next->next != NULL)
				{
					gotoxy(q->x, q->y);
					if (i == 0)
					{
						color(2);
						printf("●");
						i++;
					}
					else
					{
						color(2);
						printf("■");
					}
					q = q->next;
				}
				gotoxy(q->next->x, q->next->y);
				color(0);
				printf("  ");
				free(q->next);
				q->next = NULL;
			}
		}
		if (*status == L)
		{
			nexthead->x = head->x - 2;
			nexthead->y = head->y;
			if (nexthead->x == food->x && nexthead->y == food->y)	//如果前面有食物
			{
				nexthead->next = head;
				head = nexthead;
				q = head;
				while (q != NULL)
				{
					gotoxy(q->x, q->y);
					if (i == 0)
					{
						color(2);
						printf("●");
						i++;
					}
					else
					{
						color(2);
						printf("■");
					}
					q = q->next;
				}
				(*score)++;
				(*count)++;
				if (*count != 477)
				{
					while (flag)
					{
						flag = createfood();
					}
				}
			}
			else	//如果沒有食物
			{
				nexthead->next = head;
				head = nexthead;
				q = head;
				while (q->next->next != NULL)
				{
					gotoxy(q->x, q->y);
					if (i == 0)
					{
						color(2);
						printf("●");
						i++;
					}
					else
					{
						color(2);
						printf("■");
					}
					q = q->next;
				}
				gotoxy(q->next->x, q->next->y);
				color(0);
				printf("  ");
				free(q->next);
				q->next = NULL;
			}
		}
		if (*status == R)
		{
			nexthead->x = head->x + 2;
			nexthead->y = head->y;
			if (nexthead->x == food->x && nexthead->y == food->y)	//如果前面有食物
			{
				nexthead->next = head;
				head = nexthead;
				q = head;
				while (q != NULL)
				{
					gotoxy(q->x, q->y);
					if (i == 0)
					{
						color(2);
						printf("●");
						i++;
					}
					else
					{
						color(2);
						printf("■");
					}
					q = q->next;
				}
				(*score)++;
				(*count)++;
				if (*count != 477)
				{
					while (flag)
					{
						flag = createfood();
					}
				}
			}
			else	//如果沒有食物
			{
				nexthead->next = head;
				head = nexthead;
				q = head;
				while (q->next->next != NULL)
				{
					gotoxy(q->x, q->y);
					if (i == 0)
					{
						color(2);
						printf("●");
						i++;
					}
					else
					{
						color(2);
						printf("■");
					}
					q = q->next;
				}
				gotoxy(q->next->x, q->next->y);
				color(0);
				printf("  ");
				free(q->next);
				q->next = NULL;
			}
		}
	}
}

void gamestart(int* score, int* highscore, int* endgamestatus, int* Time, int* LongTime, int* TimeBegin)
{
	int tmp, flag = 1;

	StartWindow();
	while (1)
	{
		tmp = getch();
		if (tmp == 50)	//數字2的鍵碼值為50
		{
			endgame(score, highscore, endgamestatus, Time, LongTime);
			exit(0);
		}
		else if (tmp == 49)	//數字1的鍵碼值為49
		{
			break;
		}
	}
	creatMap();
	notice(score, highscore, Time, LongTime);
	initsnake();
	while (flag)
	{
		flag = createfood();
	}
	*TimeBegin = time(NULL);	//開始程序計時
}

void gamecontinue(unsigned long* sleeptime, int* count, int* score, int* highscore, int* status, int* endgamestatus,
	int* Time, int* LongTime, int* TimeBegin, int* TimeEnd, int* TimePause, int* PauseBegin, int* PauseEnd)
{
	char note[4];

	gotoxy(60, 16);
	printf("再來一局?(yes or 任意其他字符)");
	gets(note);
	if (strcmp(note, "yes") == 0)
	{
		system("cls");
		start(sleeptime);
		reset(count, score, Time, TimeBegin, TimeEnd, TimePause, PauseBegin, PauseEnd);
		gamestart(score, highscore, endgamestatus, Time, LongTime, TimeBegin);
		gamecontrol(sleeptime, count, score, highscore, status, endgamestatus, Time, LongTime, TimeBegin, TimeEnd, TimePause, PauseBegin, PauseEnd);
		endgame(score, highscore, endgamestatus, Time, LongTime);
		gamecontinue(sleeptime, count, score, highscore, status, endgamestatus, Time, LongTime, TimeBegin, TimeEnd, TimePause, PauseBegin, PauseEnd);
	}
	else
	{
		gotoxy(60, 17);
		printf("您已經結束了游戲。");
	}
}

void stop(unsigned long* sleeptime)
{
	*sleeptime = 1000000000;
}

void start(unsigned long* sleeptime)
{
	*sleeptime = RESPEED;
}

void reset(int* count, int* score, int* Time, int* TimeBegin, int* TimeEnd, int* TimePause, int* PauseBegin, int* PauseEnd)
{
	*score = *count = *Time = *TimeBegin = *TimeEnd = *TimePause = *PauseBegin = *PauseEnd = 0;
}

void updatescore(int* score, int* highscore, int* Time, int* LongTime)
{
	if (*score > * highscore)
	{
		*highscore = *score;
	}
	if (*Time > * LongTime)
	{
		*LongTime = *Time;
	}
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM