C语言贪吃蛇

学习C语言基础期间无聊,随便写了个小游戏,没有学GUI,
就用纯字符写了个贪吃蛇来玩,经过五次的bug修复,总算做出了点样子
虽然网上这样的源码一so一堆,但还是靠自己的思路写了出来
有什么不足还请指出,但是望大佬勿喷...
下面是可以直接在Windows系统的编译器上编译执行的源代码:

#include <time.h>
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
#include <string.h>
#include <windows.h>
//#pragma warning(disable:4996)
//↑移除Visual Studio的4996警告

void food(int fxy[], int xy[][1369]);
void move(int dir, int xy[][1369]);
void GUI(char s[][39][3], char chs[][3], int xy[][1369], int size, int fxy[], int time);
void udlr(char s[][39][3], char chs[][3]);
void snake(int fxy[], int xy[][1369], int size);


void food(int fxy[], int xy[][1369]) {
	srand(time(NULL));
	//以時間為種子產生隨機數
	fxy[0] = rand() % 37 + 1;
	fxy[1] = rand() % 37 + 1;
	//分別賦值給食物的x和y坐標
}

void cls() {
	//解決system("cls")導致的閃爍問題
	COORD point = { 0,0 };
	//光標要移動到的坐標
	HANDLE HOutput = GetStdHandle(STD_OUTPUT_HANDLE);
	SetConsoleCursorPosition(HOutput, point);
	//移動光標至命令行最前端
}

void move(int dir, int xy[][1369]) {
	//判斷蛇頭移動方向,并對蛇頭的x或y坐標進行相應的加減
	if (dir == 1)
		xy[0][0] -= 1;
	else if (dir == 2)
		xy[0][0] += 1;
	else if (dir == 3)
		xy[1][0] -= 1;
	else if (dir == 4)
		xy[1][0] += 1;
}

void snake(int fxy[], int xy[][1369], int size) {
	//蛇身體的移動,xy[2][1369]存放了蛇頭及身體的坐標
	int i;
	for (i = 0; i < size - 1; i++) {
		xy[0][size - i - 1] = xy[0][size - i - 2];
		xy[1][size - i - 1] = xy[1][size - i - 2];
	}
}

void GUI(char s[][39][3], char chs[][3], int xy[][1369], int size, int fxy[], int time) {
	int x, y, z, i = 0;
	char ui[39][79] = { "" }, gui[6241] = { "" }, enter[] = { "\n" };
	//s[39][39][3]表示39*39的 長度為3 的字符串二維數組,用於第一次存放遊戲界面佈局
	//ui[39][79]表示39個長度為79的字符串的數組,用於第二次存放遊戲界面的佈局
	//gui[6241]用於第二次存放遊戲界面的佈局,以達到三次性輸出到屏幕上的目的
	//↓循環給s數組賦值,形成 遊戲界面佈局
	for (x = 0; x < 39; x++) {
		for (y = 0; y < 39; y++) {
			if (!x || !y || x == 38 || y == 38)
				for (z = 0; z < 3; z++)
					s[x][y][z] = chs[0][z];
			else
				for (z = 0; z < 3; z++)
					s[x][y][z] = chs[1][z];
		}
	}
	//↓循環將食物替換進遊戲界面佈局
	for (z = 0; z < 3; z++) {
		s[fxy[0]][fxy[1]][z] = chs[3][z];
	}
	//↓循環將蛇替換進遊戲界面佈局
	for (i = 0; i < size; i++) {
		//↓蛇頭
		if (!i)
			for (z = 0; z < 3; z++) {
				s[xy[0][i]][xy[1][i]][z] = chs[4][z];
			}
		//↓蛇身
		else
			for (z = 0; z < 3; z++) {
				s[xy[0][i]][xy[1][i]][z] = chs[2][z];
			}
	}
	//↓循環將s賦值給ui,并將ui賦值給gui
	for (i = 0, x = 0; x < 39; x++, i++) {
		for (y = 0; y < 39; y++)
			strcat(ui[i], s[x][y]);
		strcat(gui, ui[i]);
		strcat(gui, enter);
	}
	//↓輸出遊戲界面
	printf("%s按ESC退出遊戲\n當前速度:%4d\n當前分數:%4d", gui, time, (size - 1) * 10);
}

void udlr(char s[][39][3], char chs[][3]) {
	int mark_arrow = 0, ch = 0, dir = 0, xy[2][1369] = { {19},{19} }, fxy[2] = { 0 };
	int size = 1, time, state = 0, i;
	//↓第一次調用,初始化食物坐標
	food(fxy, xy);
	while (1) {
		//↓檢測緩衝區中是否有數據
		if (kbhit()) {
			ch = getch();
			//將緩衝區中的數據以字符的形式讀出至ch
			//↓循環監聽,直到按Esc鍵退出
			if (ch == 27) {
				system("cls");
				puts("遊戲已退出");
				break;
			}
			//↓判斷是否為控制字符
			if (ch == 224) {
				mark_arrow = 1;
				continue;
			}
			//↓判斷方向,72↑,80↓,75←,77→
			if (mark_arrow) {
				if (ch == 72)
					dir = 1;
				else if (ch == 80)
					dir = 2;
				else if (ch == 75)
					dir = 3;
				else if (ch == 77)
					dir = 4;
				mark_arrow = 0;
				continue;
			}
		}
		//↓循環判斷蛇頭是否碰到了蛇身
		for (i = 1; i < size; i++) {
			if (xy[0][i] == xy[0][0] && xy[1][i] == xy[1][0]) {
				state = 1;
				break;
			}
		}
		//↓判斷蛇頭是否碰了壁,是否碰到了蛇身
		if (xy[0][0] < 1 || xy[0][0] > 37 || xy[1][0] < 1 || xy[1][0] > 37 || state) {
			printf("\n遊戲結束\n總得分:%4d", (size - 1) * 10);
			break;
		}
		//↓判斷蛇頭是否吃到了食物
		if (xy[0][0] == fxy[0] && xy[1][0] == fxy[1]) {
			//↓蛇身體長度+1
			size++;
			//↓重置食物位置
			food(fxy, xy);
		}
		snake(fxy, xy, size);
		move(dir, xy);
		cls();
		time = 170 - (size - 1) * 2;
		//暫停時間(ms),蛇的速度,越小越快
		//↓防止暫停時間小於1ms
		if (time <= 0)
			time = 1;
		GUI(s, chs, xy, size, fxy, time);
		//↓暫停函數
		Sleep(time);
	}
}


void start() {
	char s[39][39][3];
	char chs[5][3] = { {"■"}, {"□"}, {"●"}, {"★"},{"◆"} };
	//chs[5][3]表示5個長度為3的特殊字符數組,用於存放遊戲界面佈局的組成元素
	puts("按任意鍵開始遊戲");
	system("pause");
	udlr(s, chs);
	system("pause");
}

int main() {
	start();
	return 0;
}

点赞

发表评论

电子邮件地址不会被公开。必填项已用 * 标注