头文件: 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;
}