c语言游戏贪吃蛇源码_C语言经典游戏——贪吃蛇

108af8fb12e210a0c6105b91924678f1.png

这次玩个小项目,经典游戏《贪吃蛇》,先放一张路飞4档蛇人的图镇镇场。


你所需要具备的知识(转而言之小项目所涉及到的,不了解的话我之前文章都有涉及,可以回头看看):

  • 指针
  • 函数之通信
  • 多线程(不涉及锁)
  • 链表
  • 文件的操作

贪吃蛇框架设计(也没那么高大尚,你可以理解为有啥功能):

  • 地图构建
  • 创建一条蛇
  • 方向和暂停功能
  • 蛇的运动逻辑
  • 自撞和撞墙的失败检测
  • 计分系统
  • 分数存储(非易失存储上)
  • 游戏难度处理

PS:

  • 如果可以尽量少用全局变量
  • 函数间通讯入参是指针
  • 不影响功能的前提下,耗时操作尽量用线程
  • 文件的操作要格外小心
  • 全局变量的命名、局部变量的命名 最好统一规范,这个的好处在于你代码越多所越体现而出

废话上说,直接上代码!

snake.c

/*
 * Project Name:Gluttonous Snake 
 * Version:1.0
 */

#include<stdio.h>
#include<conio.h>
#include<windows.h>
#include<stdlib.h>
#include<time.h>
#include <pthread.h>
#include"snake.h"

int g_WaitTime = 300;
int g_Score = 0;
int g_EndGameStatus = 0;
snake *g_Head;
snake *g_P;
int g_Status = R;
int g_Key;
int g_Pos = 0;
int foodX, foodY;
pthread_t ThreadSaveScore;

void Pos(int x, int y) //光标定位
{
	COORD pos;
	HANDLE hOutput;
	pos.X = x;
	pos.Y = y;
	hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
	SetConsoleCursorPosition(hOutput, pos);
}

void Stop() //暂停函数 
{
	while (1)
	{
		if (g_Key = getch() == ' ')
			break;
	}
}

void EndGame() //游戏结束调度
{
	system("cls");
	Pos(27, 13);
	if (g_EndGameStatus == 1)
		printf("您撞到墙了");

	if (g_EndGameStatus == 2)
		printf("您咬到了自己");
	Pos(27, 14);
	printf("您的得分为 %d", g_Score);

	exit(0);
}

void Welcome() //欢迎界面
{
	Pos(27, 13);
	printf("欢迎来到贪吃蛇游戏!");
	Pos(27, 14);
	printf("Weclome to Gluttonous Snake!");
	Pos(27, 15);
	system("pause");
	system("cls");
}

int BitSelf() //自撞检测
{
	g_P = g_Head->next;
	while (g_P)
	{
		if (g_P->x == g_Head->x && g_P->y == g_Head->y) {
			return True;
		}
		g_P = g_P->next;
	}
	return False;
}

void CreatMap() //地图创建
{
	int i, j;
	for (i = 0; i <= MAX_LEN; i++) {
		for (j = 0; j <= MAX_WIDE; j++)
		{
			Pos(i, 0);
			printf("@");
			Pos(i, MAX_WIDE);
			printf("@");
			Pos(0, j);
			printf("@");
			Pos(MAX_LEN, j);
			printf("@");
		}
	}
}

void CreateMapThread() //地图创建线程
{
	pthread_t ThreadCreateMap;
	pthread_create(&ThreadCreateMap, NULL, CreatMap, NULL);

	pthread_join(ThreadCreateMap, NULL);
	sem_destroy(&ThreadCreateMap);
}

void CrossWall() //撞墙检测
{
	if (g_Head->x == 0 || g_Head->y == 0 || g_Head->x == MAX_LEN || g_Head->y == MAX_WIDE)
	{
		g_EndGameStatus = 1;
		EndGame();
	}
}

void CreatFood() //食物创建
{
	srand(time(NULL));
	foodX = rand() % (MAX_LEN - 1) + 1;
	foodY = rand() % (MAX_WIDE -1) + 1;
	Pos(foodX, foodY);
	printf("*");
} 

void MovingCheck(int *xFlag,int *yFlag) //移动检测
{
	CrossWall();

	if (BitSelf())
	{
		g_EndGameStatus = 2;
		EndGame();
	}

	switch (g_Status) {
	case R:
		*xFlag = 1;
		*yFlag = 0;
		return;
	case L:
		*xFlag = -1;
		*yFlag = 0;
		return;
	case U:
		*xFlag = 0;
		*yFlag = -1;
		return;
	case D:
		*xFlag = 0;
		*yFlag = 1;
		return;
	default:
		return;
	}
}

void SnakeMoving() //蛇移动处理函数
{
	int xFlag = 0;
	int yFlag = 0;
	snake *newhead;
	newhead = (snake*)malloc(sizeof(snake));
	MovingCheck(&xFlag, &yFlag);
	if (g_Head->x == foodX && g_Head->y == foodY)
	{
		g_Score = g_Score + 10;
		newhead->x = g_Head->x + xFlag;
		newhead->y = g_Head->y + yFlag;
		newhead->next = g_Head;
		g_Head = newhead;
		g_P = g_Head;
		while (g_P)
		{
			Pos(g_P->x, g_P->y);
			printf("*");
			g_P = g_P->next;
		}
		CreatFood();
	}
	else
	{
		newhead->x = g_Head->x + xFlag;
		newhead->y = g_Head->y + yFlag;
		newhead->next = g_Head;
		g_Head = newhead;
		g_P = g_Head;
		while (g_P->next->next)
		{
			Pos(g_P->x, g_P->y);
			printf("*");
			g_P = g_P->next;
		}
		Pos(g_P->next->x, g_P->next->y);
		printf(" ");

		free(g_P->next);
		g_P->next = NULL;
	}
}

void UserContrl() //用户控制检测
{
	if (kbhit())
		g_Key = getch();
	switch (g_Key)
	{
	case KEY_RIGHT:
		if (g_Status != L)
			g_Status = R;
		break;
	case KEY_LEFT:
		if (g_Status != R)
			g_Status = L;
		break;
	case KEY_UP:
		if (g_Status != D)
			g_Status = U;
		break;
	case KEY_DOWN:
		if (g_Status != U)
			g_Status = D;
		break;
	case KEY_SPACE:
		Stop();
		break;
	default:
		break;
	}
}

void SnakeSpeed() //蛇移动速度处理
{
	int flag[5] = { 50, 100, 150, 200 ,300 };

	if ((g_Score == flag[g_Pos]) && (g_Pos < 5)) {
		g_WaitTime = g_WaitTime - 50;
		g_Pos++;
	}
	Sleep(g_WaitTime);
}

void SaveScore() //存储分数
{
	int res;
	int HistoryScore = GetHistoryBest();
	FILE *fp;
	while (1) {
		fp = fopen(SCOREPATH, "wt+");
		if (fp == NULL) {
			printf("open a null file");
		}
		
		if (HistoryScore < g_Score) {
			fprintf(fp, "%dn", g_Score);
		} else {
			fprintf(fp, "%dn", HistoryScore);
		}
		fclose(fp);
		Sleep(50);
	}
}

void SaveScoreThread() //存储分数线程
{
	pthread_create(&ThreadSaveScore, NULL, SaveScore, NULL);
}

int GetHistoryBest() {
	int HistoryScore = 0;
	FILE *fp;
	fp = fopen(SCOREPATH, "rt+");
	if (fp == NULL) {
		printf("open a null file");
		return False;
	}

	rewind(fp);
	fscanf(fp, "%d", &HistoryScore);

	fclose(fp);
	return HistoryScore;
}

void GameProcess() //游戏处理
{
	int res;
	res = GetHistoryBest();

	Pos(80, 4);
	printf("操作说明");
	Pos(80, 5);
	printf("W A S D 分别对应上 左 下 右 ");
	Pos(80, 6);
	printf("按空格键暂停");
	Pos(80, 18);
	printf("历史最高分: %d", res);

	while (1)
	{
		Pos(80, 20);
		printf("游戏分数:%d", g_Score);
		UserContrl();
		SnakeSpeed();
		SnakeMoving();
	}
}

void InitSnake() //蛇的初始化
{
	int i;
	snake *tail;
	g_Head = (snake*)malloc(sizeof(snake));
	g_Head->x = MAX_LEN / 2;
	g_Head->y = MAX_WIDE / 2;
	g_Head->next = NULL;
	for (i = 1; i < 4; i++)
	{
		tail = (snake*)malloc(sizeof(snake));
		tail->x = MAX_LEN / 2 + i * 1;
		tail->y = MAX_WIDE / 2;
		tail->next = g_Head;
		g_Head = tail;
	}

	while (tail)
	{
		Pos(tail->x, tail->y);
		printf("*");
		tail = tail->next;
	}
}

int main()
{
	Welcome();         //欢迎界面
	CreateMapThread(); //地图创建线程
	CreatFood();       //食物创建
	InitSnake();       //蛇的初始化
	SaveScoreThread(); //分数存档线程
	GameProcess();     //游戏处理
	return 0;
}

snake.h

#define KEY_UP    'w' // 向上方向键   
#define KEY_DOWN  's' // 向下方向键
#define KEY_RIGHT 'd' // 向右方向键
#define KEY_LEFT  'a' // 向左方向键
#define KEY_SPACE ' ' 

#define R 1           //向右的状态量 
#define L 2           //向左的状态量 
#define U 3           //向上的状态量 
#define D 4           //向下的状态量 

#define True  1
#define False 0

#define MAX_LEN  54
#define MAX_WIDE 26

#define SCOREPATH "score.txt"

typedef struct node
{
	int x;
	int y;
	struct node*next;
}snake;

最后,别忘了创建个score.txt里面空就好~大功告成!

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
windows api 做的贪吃蛇 #include #include"resource.h" #include"Node.h" #include #include TCHAR szAppname[] = TEXT("Snack_eat"); #define SIDE (x_Client/80) #define x_Client 800 #define y_Client 800 #define X_MAX 800-20-SIDE //点x的范围 #define Y_MAX 800-60-SIDE //点y的范围 #define TIME_ID 1 #define SECOND 100 #define NUM_POINT 10 //点的总个数 #define ADD_SCORE 10 LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) { HWND hwnd; //窗口句柄 MSG msg; //消息 WNDCLASS wndclass; //窗口类 HACCEL hAccel;//加速键句柄 wndclass.style = CS_HREDRAW | CS_VREDRAW; //窗口的水平和垂直尺寸被改变时,窗口被重绘 wndclass.lpfnWndProc = WndProc; //窗口过程为WndProc函数 wndclass.cbClsExtra = 0; //预留额外空间 wndclass.cbWndExtra = 0; //预留额外空间 wndclass.hInstance = hInstance; //应用程序的实例句柄,WinMain的第一个参数 wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION); //设置图标 wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); //载入预定义的鼠标指针 wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); //设置画刷 wndclass.lpszMenuName = szAppname; //设置菜单 wndclass.lpszClassName = szAppname; //设置窗口类的名字 if (!RegisterClass(&wndclass))//注册窗口类 { MessageBox(NULL, TEXT("这个程序需要windows NT!"), szAppname, MB_ICONERROR); return 0; } hwnd = CreateWindow(szAppname, TEXT("Snack_eat"),//CreateWindow函数调用时,WndProc将受到WM_CREATE WS_OVERLAPPEDWINDOW&~WS_THICKFRAME& ~WS_MAXIMIZEBOX,//普通的层叠窗口&禁止改变大小&禁止最大化 CW_USEDEFAULT, //初始x坐标(默认) CW_USEDEFAULT, //初始y坐标 x_Client, //初始x方向尺寸 770 y_Client, //初始y方向尺寸 750 NULL, //父窗口句柄 NULL, //窗口菜单句柄 hInstance, //程序实例句柄 WinMain函数中第二个参数 NULL); //创建参数 ShowWindow(hwnd, iCmdShow);//显示窗口,iCmdShow是WinMain的第四个参数,决定窗口在屏幕中的初始化显示形式,例:SW_SHOWNORMAL表示正常显示 UpdateWindow(hwnd);//使窗口客户区重绘,通过向WndProc发送一条WM_PAINT消息而完成的 hAccel = LoadAccelerators(hInstance, szAppname);//加载加速键 while (GetMessage(&msg, NULL, 0, 0)) { if (!TranslateAccelerator(hwnd, hAccel, &msg)) { TranslateMessage(&msg); DispatchMessage(&msg); } }/* while (GetMessage(&msg, NULL, 0, 0))//GetMessage函数从消息队列中得到消息,填充msg。如果msg.message等于WM_QUIT,返回0,否则返回非0 { TranslateMessage(&msg);//将msg返回给windows已进行某些键盘消息的转换 DispatchMessage(&msg);//将msg再次返回给windows }*/ return msg.wParam;//msg.wParam是PostQuitMessage函数的参数值,通常是0 } ...

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值