C语言贪吃蛇小游戏

头文件: game.h

#ifndef __Game__
#define __Game__

#include <stdio.h>
#include<Windows.h>
#include<time.h>
#include<conio.h>
#include<string.h>

// 墙的字节数,-1是因为字符串末尾的 “\0”
#define WALLSIZE  (sizeof("■") - 1)

// 地图行列的宽高
static int rowSize = 20;
static int colSize = 20;
// 判断食物状态
static int food = 0;
// 食物的位置
static int rowFood = -1;
static int colFood = -1;
// 创建蛇
typedef struct Snake *pSnake;
typedef struct Snake
{
	int x;
	int y;
	pSnake next;
} Snake;
// 蛇长度
static int SnakeLength = 3;
// 蛇头朝向,0,1,2,3 对于 上下左右
static int snakeDirection = 0;
// 保存上一次的按键
static char click = ' ';
// 保存暂停前的按键
static char LastPause = ' ';
// 游戏结束的标志,默认为0
static int gameIsOver = 0;

// 设置控制台输出位置
void setRow_Col(int row, int column, char* str);
// 打印地图
void printMap();
// 生成食物
void setFood(pSnake Head);
// 创建蛇头
void setSankeHead(Snake* Head);
// 设置蛇的结点内容
void setSnakeNode(pSnake Head);
// 显示蛇,修改的地图的内容
void printSnake(pSnake Head);
// 创建一条蛇,最大长度为 5 ,最小为 3,默认为3
void creatSnake(pSnake Head, int length);
// 清除蛇
void delSnake(pSnake Head);
// 蛇的自动移动
void SnakeAutoMove(pSnake Head);
// 设置蛇出界的结点,使其恢复
void LeaveWall(Snake * Node);
// 吃食物
void EatFood(pSnake Head);
// 判断游戏结束
void gameOVver(pSnake Head);
// 游戏界面
int GameMain();

#endif // !__Game__

函数:

#define _CRT_SECURE_NO_WARNINGS
#include "game.h"

// 设置控制台输出位置,和内容
void setRow_Col(int row, int column, char* str)
{
	COORD pos;
	HANDLE pOutCmd;
	pos.X = row * WALLSIZE;
	pos.Y = column;
	pOutCmd = GetStdHandle(STD_OUTPUT_HANDLE);
	SetConsoleCursorPosition(pOutCmd, pos);
	printf("%s", str);
}
// 打印地图,并初始化一些内容
void printMap()
{
	for (int i = 0; i < rowSize; i++)
		for (int j = 0; j < colSize; j++)
			if (i == 0 || j == 0 || j == (colSize - 1) || i == (rowSize - 1))
				setRow_Col(i, j, "■");

	// 根据方向设置click的默认值
	switch (snakeDirection)
	{
		case 0:click = 'w'; break;
		case 1:click = 's'; break;
		case 2:click = 'a'; break;
		case 3:click = 'd'; break;
	}
}
// 生成食物
void setFood(pSnake Head)
{
	// 判断食物是否存在,被吃时 food 为 0
	if (food == 1) return;

	srand((int)time(NULL));

GetFood:
	// 随机生成食物的位置
	rowFood = rand() % (rowSize - 1);
	colFood = rand() % (colSize - 1);


	// 处理边界
	while( rowFood <= 1)
		rowFood = rand() % (rowSize - 1);
	while( colFood <= 1)
		colFood = rand() % (colSize - 1) ;

	// 判断是否有蛇
	if (Head != NULL)
	{
		Snake * demo = Head;
		// 判断生成的食物是否与蛇重合
		for (int i = 0; i < SnakeLength; i++)
		{
			if (rowFood == demo->x && colFood == demo->y)
				goto GetFood;
		}
	}

	// 设置食物的位置
	setRow_Col(rowFood, colFood, "★");
	// 修改食物的状态
	food = 1;
}

// 创建蛇头
void setSankeHead(Snake * Head)
{
	// 初始化蛇头,设置内容
	int headRow = rand() % ( rowSize / 4) + rowSize / 4;
	int headcol = rand() % ( colSize / 4) + colSize / 4;
	Head->x = headRow;
	Head->y = headcol;
	Head->next = NULL;
	// 设置蛇头朝向
	srand((int)time(NULL));
	snakeDirection = rand() % 4;
}
// 设置蛇的结点内容
void setSnakeNode(pSnake Head)
{
	Snake* demo = Head;
	// 创建节点
	Snake* pNode = (pSnake)malloc(sizeof(Snake));
	// 根据蛇初始移动方向,设置身体朝向
	pNode->x = demo->x;
	pNode->y = demo->y;
	switch (snakeDirection)
	{
		case 0:		pNode->y++;		break;
		case 1:		pNode->y--;		break;
		case 2:		pNode->x++;		break;
		case 3:		pNode->x--;		break;
		default:	pNode->y++;		break;
	}
	pNode->next = NULL;
	demo->next = pNode;
}
// 显示蛇,修改的地图的内容
void printSnake(pSnake Head)
{
	Snake* demo = Head;

	for (int i = 0; i < SnakeLength; i++)
	{
		if (i == 0)
			setRow_Col(demo->x, demo->y, "◆");
		else
			setRow_Col(demo->x, demo->y, "●");
		demo = demo->next;
	}
}
// 创建一条蛇,最大长度为 5 ,最小为 3,默认为3
void creatSnake(pSnake Head, int length)
{
	if (length < 3 || length > 5)
		length = 3;
	// 设置蛇长度
	SnakeLength = length;

	// 创建蛇头
	setSankeHead(Head);

	Snake* demo = Head;
	// 创建蛇身
	for (int i = 0; i < SnakeLength -1; i++)
	{
		setSnakeNode(demo);
		demo = demo->next;
	}
	// 打印蛇
	printSnake(Head);
}
// 清除蛇
void delSnake(pSnake Head)
{
	Snake* demo = Head;
	for (int i = 0; i < SnakeLength; i++)
	{
		setRow_Col(demo->x, demo->y, "  ");
		demo = demo->next;
	}
}
// 蛇的自动移动
void SnakeAutoMove(pSnake Head)
{
	Snake* demo = Head;
	// 清除蛇
	delSnake(demo);
	/*
		保存前一个节点内容,然后赋给下一个节点
	*/
	int ChangeRow = demo->x;
	int ChangeCol = demo->y;
	// 根据蛇的移动方向,修改蛇头的朝向
	switch (snakeDirection)
	{
		case 0:demo->y--; break;
		case 1:demo->y++; break;
		case 2:demo->x--; break;
		case 3:demo->x++; break;
		default:demo->y--; break;
	}
	// 用于交换ChangeRow、ChangeCol 与 demo
	int tX, tY;
	// setRow_Col(rowSize, colSize, "");	// 设置控制台打印位置
	for (int i = 0; i < SnakeLength; i++)
	{
		// 当蛇出界,则使其恢复
		LeaveWall(demo);
		// printf("(%d,%d) ", ChangeRow, ChangeCol); // 之前打印蛇结点的位置
		demo = demo->next;
		// 判断是否到达结尾,也可以 根据 蛇长 修改 for循环上的 SnakeLength 为 ( SnakeLength - 1 )
		if (demo == NULL) break;
		// 把上一个节点的内容设置到当前节点,并保存当前节点内容
		{
			tX = demo->x;
			demo->x = ChangeRow;
			ChangeRow = tX;
		}
		{
			tY = demo->y;
			demo->y = ChangeCol;
			ChangeCol = tY;
		}
	}
	// 打印蛇
	printSnake(Head);
}
// 当蛇出界,则使其恢复,可以修改为游戏结束的标志(撞墙)
void LeaveWall(Snake * Node)
{
	/*
		边界为rowSize,colSize
		但控制台的 行列 是以0开始的
		当到达 行 首 ,为  0 时,即到达 左墙,而右墙为 rowSize-1 ,故修改其值为 rowSize-1 -1
		当到达 行 尾 ,为 rowSize-1 时,即到达 右墙,而左墙 为 0 ,则修改其值为 1
		列同理
	*/ 
	if (Node->x >= rowSize -1)
		Node->x = 1;
	if (Node->y >= colSize -1 )
		Node->y = 1;
	if (Node->x < 1)
		Node->x = rowSize - 1 - 1;
	if (Node->y < 1)
		Node->y = colSize - 1 - 1;
}
// 按键移动蛇
void SnakeKeyMove(pSnake Head)
{
	// 创建蛇的副本
	pSnake snake = Head;
	// 修改控制台光标位置
	setRow_Col(rowSize, colSize, "");
	// 获取输入字符
	char  c = _getch();

	/*
		保存暂停前的方向,则保存之前的移动方向(按键值)
	*/ 
	if(c == 'p' || c == 'P')
		LastPause = click;

	// 根据字符修改蛇的移动方向,并阻止非法输入
	switch (c)
	{
		case 'w':
		case 'W': snakeDirection = 0; break;
		case 'S':
		case 's': snakeDirection = 1; break;
		case 'A':
		case 'a': snakeDirection = 2; break;
		case 'D':
		case 'd': snakeDirection = 3; break;
		case 'P':
		case 'p':; break;
		default:
			return;
			break;
	}
	// 保存当前输入内容
	click = c;
}
// 吃食物
void EatFood(pSnake Head)
{
	Snake* demo = Head;
	// 判断食物与蛇头是否重合
	if (demo->x == rowFood && demo->y == colFood)
	{
		// 修改食物状态
		food = 0;
		// 创建食物
		setFood(Head);
		// 获取蛇尾
		while (demo->next != NULL)
			demo = demo->next;
		// 创建新的结点
		setSnakeNode(demo);
		// 蛇长增加
		SnakeLength++;
	}
}
// 蛇咬到自己,游戏结束
void gameOVver(pSnake Head)
{
	Snake* demo = Head;
	int HeadRow = demo->x;
	int HeadCol = demo->y;
	for (int i = 0; i < SnakeLength; i++)
	{
		demo = demo->next;
		// 判断是否到达结尾,也可以 根据 蛇长 修改 for循环上的 SnakeLength 为 ( SnakeLength - 1 )
		if (demo == NULL) break;
		if (HeadRow == demo->x)
			if (HeadCol == demo->y)
				gameIsOver = 1;
	}
}
int GameMain()
{
	// 打印地图
	printMap();
	// 创建头节点
	pSnake snake = (pSnake)malloc(sizeof(Snake));
	// 创建蛇
	creatSnake(snake,5);
	char pause = ' ';
	while (1)
	{
		// 判断食物与蛇的状态
		EatFood(snake);
		// 获取是否按键
		if(_kbhit())
			// 进行按键移动
			SnakeKeyMove(snake);
		// 暂停
		if ( click == 'p' || click == 'P')
		{
			pause = _getch();
			while (pause != 'p' && pause != 'P')
			{
				pause = _getch();
			}
			if (pause == 'P' || pause == 'p')
				click = LastPause;
		}
		// 蛇的自动移动
		SnakeAutoMove(snake);
		// 创建食物
		setFood(snake);

		gameOVver(snake);
		if (gameIsOver)
		{
			setRow_Col(rowSize, colSize, "");
			break;
		}
			
		// 设置控制台输出位置
		setRow_Col(rowSize, colSize,"");
		// 移动速度
		Sleep(200);
	}
	return 1;
}

main.c

#define _CRT_SECURE_NO_WARNINGS

#include"game.h"
int main()
{
	
	GameMain();
	system("cls");
	setRow_Col(20,15,"游戏结束\n");
	getchar();
	system("pause");
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值