C语言贪吃蛇代码

C语言贪吃蛇实现-CSDN博客

目录

一、 snake.h

二、snake.c

三、Test.c


一、 snake.h

#pragma once
#define _CRT_SECURE_NO_WARNINGS 1
#include
#include
#include
#include
#include

#define ROW 27  //游戏区行数
#define COL 57  //游戏区列数


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

#define Origin_x 24  // 初始蛇头的x坐标
#define Origin_y 5   // 初始蛇头的y坐标

//检测按键是否被按过,间返回的虚拟值按位与上1,相同为1,相异为0,进行检测
//封装为一个宏
#define KEY_PRESS(vk) (GetAsyncKeyState(vk)&0x1?1:0)


//贪吃蛇游戏状态
enum GAMSTATUS {
	OK=1, //正常运行
	EXIT, //按ESC键退出
	KILL_BY_WALL, //撞墙了!
	KILL_BY_SELF  //咬到自己了!
};

//贪吃蛇行走方向
enum SNAKEWAY {
	UP = 1, //前进
	DOWN,   //向下
	LEFT,   //左拐
	RIGHT  //右拐
};

//贪吃蛇,蛇身节点的定义
typedef struct SnakeNode {
	//节点的位置
	int x;
	int y;
	//下一个蛇身节点
	struct SnakeNode* next;
}SnakeNode;



//整局游戏贪吃蛇的维护
typedef struct Snake {
	//贪吃蛇,蛇头指针,方便找到贪吃蛇的位置/维护整条蛇的指针
	SnakeNode* SnakePhead;
	//指向食物的指针
	SnakeNode* FoodNode;
	//玩家当前得分
	int Scour;
	//每个食物的得分
	int FoofScour;
	//蛇休眠的时间,休眠的时间越短,蛇的速度越快,休眠的时间月长,蛇的速度越慢
	int SleepTime;
	//贪吃蛇游戏状态
	enum GAMSTATUS Status;
	//贪吃蛇行进的方向
	enum SNAKEWAY way;
}Snake;


//游戏开始前的准备
void GameStart(Snake*ps);
//游戏开始欢迎界面
void welcome();
//绘制地图
void GameMap();
//初始化蛇
void InitSnake(Snake*ps);
//定位光标位置
void SearchLocal(int x, int y);
//打印蛇身
void SnakePrint(Snake* ps);
//创建食物
void CreatFood(Snake* ps);


//贪吃蛇游戏运行
void GameRun(Snake*ps);
//贪吃蛇开始移动
void SnakeMove(Snake*ps);
//下一个位置是否位食物;
int NextFood(Snake* ps, SnakeNode* pnext);
//吃食物
void EatFood(Snake* ps, SnakeNode* pnext);
//不吃食物
void NotEatFood(Snake* ps, SnakeNode* pnext);
//检测是否穿墙
void Kill_Wall(Snake* ps);
//检测是否咬到自己
void Kill_Self(Snake* ps);

//贪吃蛇游戏结束的善后
void GameEnd(Snake* ps);

二、snake.c

#include"snake.h"

//定位光标位置
void SearchLocal(int x,int y) {
	//获取控制台的句柄,控制权限,HANDLE 结构体指针
	HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
	COORD pos = { x,y };
	// 获取设备句柄,传入坐标COORD
	SetConsoleCursorPosition(handle, pos);
}

//初始化贪吃蛇界面
void welcome() {
	
	//将光标定位到界面的中间位置
	SearchLocal(35, 10);
	printf("欢迎来到贪吃蛇小游戏\n");
	SearchLocal(38, 20);
	system("pause");
	system("cls");

	//功能介绍
	SearchLocal(15, 10);
	printf("用↑ . ↓ . ← . → 来控制蛇的移动,F3为加速按键,F4为减速\n");
	SearchLocal(35, 12);
	printf("加速能够获得更高的分数!!!!");
	SearchLocal(38, 20);
	system("pause");
	system("cls");
}

//绘制地图
void GameMap() {
	//上
	SearchLocal(0, 0);
	for (int i = 0; i < COL; i += 2) {
		wprintf(L"%c", WALL);
	}
	//左
	for (int i = 1; i < ROW; i++) {
		SearchLocal(0, i);
		wprintf(L"%lc", WALL);
	}
	//右
	for (int i = 1; i < ROW; i++) {
		SearchLocal(COL-1, i);
		wprintf(L"%lc", WALL);
	}
	//下
	SearchLocal(0, ROW-1);
	for (int i = 0; i < COL; i += 2) {
		wprintf(L"%lc", WALL);
	}
}

//打印蛇身
void SnakePrint(Snake* ps) {
	SnakeNode* pcur = ps->SnakePhead;
	while (pcur) {
		SearchLocal(pcur->x, pcur->y);
		wprintf(L"%lc", BODY);
		pcur = pcur->next;
	}
}

//初始化蛇
void InitSnake(Snake*ps) {
	//创建5个蛇身节点
	SnakeNode* pcur = NULL;
	for (int i = 0; i < 5; i++) {
		pcur = (SnakeNode*)malloc(sizeof(SnakeNode));
		if (pcur == NULL) {
			perror("malloc");
			return;
			//exit(1)
		}
		//头插
		pcur->x = Origin_x+2*i;
		pcur->y = Origin_y;
		pcur->next = NULL;
		if (ps->SnakePhead == NULL) {    
			ps->SnakePhead = pcur;
		}
		else {
			pcur->next = ps->SnakePhead;
			ps->SnakePhead = pcur;
		}
	}
	
	//打印蛇身
	SnakePrint(ps);

	//初始化
	ps->Scour = 0;
	ps->FoodNode = NULL;
	ps->FoofScour = 10;
	ps->SleepTime = 200;
	ps->Status = OK;
	ps->way = RIGHT;
}

//创建食物
void CreatFood(Snake* ps) {
	//随机生成食物的坐标(x,y)
	//1.不能超过墙,且不能重叠 x:2~54 -- 52+2    y:1~24  -- 23+1
	//2.食物不能与蛇身重叠,遍历蛇身

	//创建食物节点
	SnakeNode* FoodNode = (SnakeNode*)malloc(sizeof(SnakeNode));
	if (FoodNode == NULL) {
		perror("creat FoodNode fail");
		return;
	}

	int x = 0;
	int y = 0;
	again:
	do {
		x = rand() % (COL-4) + 2;
		y = rand() % (ROW-2) + 1;
	} while (x % 2 != 0); //1.不能超过墙,且不能重叠

	//2.食物不能与蛇身重叠,遍历蛇身
	SnakeNode* pcur = ps->SnakePhead;
	while (pcur) {
		if (x == pcur->x && y == pcur->y) {
			goto again;
		}
		pcur = pcur->next;
	}

	//真正创建了属于食物的坐标
	FoodNode->x = x;
	FoodNode->y = y;
	FoodNode->next = NULL;

	ps->FoodNode = FoodNode;

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

void GameStart(Snake* ps) {
	//设定控制台屏幕大小
	system("mode con cols=100 lines=30");
	//设置控制台标题
	system("title 贪吃蛇");
	//设定光标,进行隐藏
	//获取控制台句柄
	HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
	//创建结构体来接收控制台光标的数据
	//有两个参数:dwSize 光标占空比; bVisible 光标可见度 默认true
	CONSOLE_CURSOR_INFO cursor_info = { 0 };
	GetConsoleCursorInfo(handle, &cursor_info);
	//隐藏光标
	cursor_info.bVisible = false;
	//将修改的光标属性值传给控制台进行控制,参数类型跟GetConsoleCursorInfo一样
	SetConsoleCursorInfo(handle, &cursor_info);
	//游戏开始欢迎界面
	welcome();
	//绘制地图
	GameMap();
	//贪吃蛇初始化
	InitSnake(ps);
	//创建食物
	CreatFood(ps);
}


//打印帮助信息
void PrintOption() {
	
	SearchLocal(63, 17);
	printf("用↑ . ↓ . ← . → 来控制蛇的移动");
	SearchLocal(63, 18);
	printf("space(空格)为暂停/回到游戏按键");
	SearchLocal(68, 19);
	printf("F3为加速按键,F4为减速"); 
	SearchLocal(72, 20);
	printf("ESC为退出按键");
	SearchLocal(63, 21);
	printf("注意:不能撞墙,不能咬到自己!!!");
}

//休眠函数
void pause() {
	while (1) {
		Sleep(200);
		if (KEY_PRESS(VK_ESCAPE)) {
			break;
		}
	}
}

//下一个位置是否位食物;
int NextFood(Snake* ps, SnakeNode* pnext) {
	if (pnext->x == ps->FoodNode->x && pnext->y == ps->FoodNode->y) {
		return 1;
	}
	else{
		return 0;
	}
}

//吃食物
void EatFood(Snake* ps, SnakeNode* pnext) {
	pnext->next = ps->SnakePhead;
	ps->SnakePhead = pnext;

	//得分增加
	ps->Scour += ps->FoofScour;

	//释放旧的食物
	free(ps->FoodNode);
	ps->FoodNode = NULL;

	//重新创建食物
	CreatFood(ps);
}

//不吃食物
void NotEatFood(Snake* ps, SnakeNode* pnext) {
	pnext->next = ps->SnakePhead;
	ps->SnakePhead = pnext;
	SnakeNode* pcur = ps->SnakePhead;
	while (pcur->next->next) {
		pcur = pcur->next;
	}
	//到达蛇尾,记录蛇尾位置用两个空格替换,然后进行删除
	SearchLocal(pcur->next->x, pcur->next->y);
	printf("  ");

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


//检测是否穿墙
void Kill_Wall(Snake* ps) {
	if (ps->SnakePhead->x == 0 ||
		ps->SnakePhead->x == (COL-1) ||
		ps->SnakePhead->y == 0 ||
		ps->SnakePhead->y == (ROW-1)) 
	{
		ps->Status = KILL_BY_WALL;
	}
}

//检测是否咬到自己
void Kill_Self(Snake* ps) {
	SnakeNode* pcur = ps->SnakePhead->next;
	while (pcur) {
		if (ps->SnakePhead->x == pcur->x && ps->SnakePhead->y == pcur->y) {
			ps->Status = KILL_BY_SELF;
			return;
		}
		pcur = pcur->next;
	}
}

//贪吃蛇开始移动
void SnakeMove(Snake*ps){
	//创建指针记录蛇移动的下一个位置
	SnakeNode* pnext = (SnakeNode*)malloc(sizeof(SnakeNode));
	if (pnext == NULL) {
		perror("SnakeMove::malloc");
		return;
	}
	pnext->next = NULL;

	//记录蛇移动的下一个位置
	switch (ps->way){
	case UP:
		pnext->x = ps->SnakePhead->x;
		pnext->y = ps->SnakePhead->y - 1;
		break;
	case DOWN:
		pnext->x = ps->SnakePhead->x;
		pnext->y = ps->SnakePhead->y + 1;
		break;
	case LEFT:
		pnext->x = ps->SnakePhead->x-2;
		pnext->y = ps->SnakePhead->y;
		break;
	case RIGHT:
		pnext->x = ps->SnakePhead->x + 2;
		pnext->y = ps->SnakePhead->y;
		break;
	}

	//判断下一个位置是否为食物
	//是食物,吃掉 --- 头插
	if (NextFood(ps,pnext)) {
		EatFood(ps, pnext);
	}
	//不是食物,头插删除尾节点
	else {
		NotEatFood(ps, pnext);
	}
	//打印蛇身
	SnakePrint(ps);

	//检测是否穿墙
	Kill_Wall(ps);
	//检测是否咬到自己
	Kill_Self(ps);
}



//贪吃蛇游戏运行
void GameRun(Snake* ps) {
	//打印操作介绍
	PrintOption();
	do{
		//打印当前得分情况
		SearchLocal(65, 11);
		printf("当前得分:%d",ps->Scour);
		SearchLocal(78, 11);
		printf("当前食物分值:%02d", ps->FoofScour);
		//检测按键是否按过
		if (KEY_PRESS(VK_UP)&& ps->way !=DOWN) {
			ps->way = UP;
		}
		else if(KEY_PRESS(VK_DOWN) && ps->way != UP) {
			ps->way = DOWN;
		}
		else if (KEY_PRESS(VK_LEFT) && ps->way != RIGHT) {
			ps->way = LEFT;
		}
		else if (KEY_PRESS(VK_RIGHT) && ps->way != LEFT) {
			ps->way = RIGHT;
		}
		else if (KEY_PRESS(VK_ESCAPE)) {
			ps->way = EXIT;
			break;
		}
		//空格进入暂停,死循环睡眠,在次按下空格进行游戏
		else if (KEY_PRESS(VK_SPACE)) {
			pause();
		}
		//F3加速,睡眠时间减少,食物分值增加,限制条件睡眠时间不为负数
		else if (KEY_PRESS(VK_F3)) {
			//时间不能为负,每次睡眠时间-30,至多减到20;
			if (ps->SleepTime > 20) {
				ps->SleepTime -= 30;
				ps->FoofScour += 2;
			}
		}
		//F4减速,睡眠时间增加,食物分值减少,限制条件食物分值不为0
		else if (KEY_PRESS(VK_F4)) {
			if (ps->FoofScour > 2) {
				ps->SleepTime += 30;
				ps->FoofScour -= 2;
			}
		}
		//贪吃蛇开始移动
		SnakeMove(ps);
		//睡眠一下
		Sleep(ps->SleepTime);

	} while (ps->Status == OK);
}

//贪吃蛇游戏结束的善后
void GameEnd(Snake* ps) {
	SearchLocal(15, 10);
	//打印结束状态
	switch (ps->Status) {
	case EXIT:
		printf("正常退出,游戏结束了");
		break;
	case KILL_BY_WALL:
		printf("很遗憾,游戏结束,你撞到墙了!!!");
		break;
	case KILL_BY_SELF:
		printf("不小心咬到自己了,游戏结束了!!!");
		break;
	}

	//释放空间
	SnakeNode* pcur = ps->SnakePhead;
	SnakeNode* del = NULL;
	while (pcur) {
		del = pcur->next;
		free(pcur);
		pcur = del;
	}
	free(ps->FoodNode);
	ps = NULL;

}

三、Test.c

#include"snake.h"

void snakegame() {
	
	int ch = 0;
	do {
		//创建贪吃蛇
		Snake snake = { 0 };
		//贪吃蛇游戏界面初始化
		GameStart(&snake);
		//贪吃蛇游戏运行
		GameRun(&snake);
		//贪吃蛇游戏结束的善后
		GameEnd(&snake);
		SearchLocal(15, 8);
		printf("要再来一局吗?? Y/N:");
		ch = getchar();
		getchar();// 清理\n
		SearchLocal(0, 27);
	} while (ch == 'Y' || ch == 'y');
}

int main() {
	//修改适配本地中文环境
	setlocale(LC_ALL, "");

	贪吃蛇游戏
	snakegame();

	return 0;
}

你可能感兴趣的:(c语言,开发语言)