C语言贪吃蛇代码

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

目录

一、 snake.h

二、snake.c

三、Test.c


一、 snake.h

#pragma once
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
#include<windows.h>
#include<stdbool.h>
#include<locale.h>

#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语言编写通常涉及基本的游戏循环、键盘输入处理、屏幕刷新以及蛇的位置更新等部分。以下是简化的C语言贪吃蛇代码结构的大致概述: 1. **初始化**: - 初始化游戏窗口大小、蛇的初始位置、速度和长度。 - 创建食物随机生成的函数。 2. **游戏主循环**: ```c while (game_not_over) { // 获取玩家输入 int direction = check_key_input(); // 更新蛇的位置并检查边界条件 move_snake(direction); // 检查蛇是否吃到食物,若吃到则增长长度 if (snake_eats_food()) { grow_snake(); } // 检查蛇头是否撞到自身或其他边界,游戏结束 if (is_collision()) { game_over(); } // 渲染当前状态(这里通常需要依赖特定的终端库) display_snake(); delay(); // 暂停一段时间防止过快 } ``` 3. **关键函数**: - `check_key_input()`:检测玩家按下的是上、下、左、右哪个方向键。 - `move_snake(int dir)`:根据方向改变蛇的位置,并可能调整头部和身体的连接。 - `snake_eats_food()`:判断蛇头是否与食物在同一位置。 - `grow_snake()`:增加蛇的身体长度。 - `is_collision()`:检查是否有边界碰撞或蛇头自相撞的情况。 - `display_snake()`:打印蛇的当前位置,通常是通过字符表示。 - `delay()`:暂停一小段时间模拟游戏帧率。 4. **变量和数据结构**: - 使用数组或链表来表示蛇的身体部分。 - 保持全局变量如分数、生命值等信息。 这是一个非常基础的框架,实际完整代码会更复杂,包括错误处理、用户界面改进等。如果你想学习详细的C语言贪吃蛇代码,可以从网上找到一些开源项目作为参考,例如GitHub上有许多这样的代码实例可供研究。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值