//头文件GameSnake.h
#pragma once
//实现头文件的包含,贪吃蛇身子,贪吃蛇游戏,函数声明
#include <stdio.h>
#include <graphics.h>
#include <mmsystem.h>
#pragma comment(lib,"winmm.lib")
#include <stdlib.h>
#include <Windows.h>
#include <stdbool.h>
#include <locale.h>
#include <time.h>
#define WALL L'□'
#define BODY L'●'
#define FOOD L'★'
#define KEY_PRESS(VK) ((GetAsyncKeyState(VK)&0x1) ? 1 : 0)
//蛇的初始位置
#define POS_X 34
#define POS_Y 12
//方向
enum DIRECTION {
UP =1,
DOWN,
LEFT,
RIGHT
};
enum STATUS {
OK, //正常游戏
KILL_BY_WALL, //撞墙
KILL_BY_SELF, //被自己杀死
END_NORMAL //正常结束
};
//蛇身节点
typedef struct SnakeNode {
short x;
short y;
struct SnakeNode* next;
}SnakeNode,*pSnakeNode;
//贪吃蛇维护
typedef struct Snake {
pSnakeNode SnakeHead;//贪吃蛇蛇身维护
pSnakeNode pFood;//食物
int FoodWeight;//食物分数
int Score;//总分数
int speed;
int SleepTime;//每走一步休眠时间
enum DIRECTION dir;//默认方向向上
enum STATUS status;
}Snake,*pSnake;
void GameStart(pSnake ps);
void InitSnake(pSnake ps);
void CreateFood(pSnake ps);
void PrintHelpInfo(pSnake ps);
void GameRun(pSnake ps);
void SnakeMove(pSnake ps);
int NextIsFood(pSnakeNode nextnode, pSnake ps);
void EatFood(pSnakeNode nextnode, pSnake ps);
void NoFood(pSnakeNode nextnode, pSnake ps);
void GameEnd(pSnake ps);
int KillByWall(pSnake ps);
int KillBySelf(pSnake ps);
void SetPos(short x, short y);
//实现文件GameSnake.c
#define _CRT_SECURE_NO_WARNINGS 1
#include "GameSnake.h"
void SetPos(short x, short y)
{
COORD pos = { x,y };
HANDLE hOutput = NULL;
//获取句柄
hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
//设置标准输出上光标的位置为pos
SetConsoleCursorPosition(hOutput, pos);
}
void CreatMap()
{
//首先定位到(0,0)
SetPos(0, 0);
int i = 0;
//打印围墙
for (i = 0; i < 58; i += 2)
{
wprintf(L"%c", WALL);
}
SetPos(0, 26);
for (i = 0; i < 58; i += 2)
{
wprintf(L"%c", WALL);
}
for (i = 1; i < 26; i++)
{
SetPos(0, i);
wprintf(L"%c", WALL);
}
for (i = 1; i < 26; i++)
{
SetPos(56, i);
wprintf(L"%c", WALL);
}
}
void InitSnake(pSnake ps) {
pSnakeNode pcur = NULL;
for (int i = 0; i < 5; i++)
{
pcur = (pSnakeNode)malloc(sizeof(SnakeNode));
if (pcur == NULL)
{
perror("init malloc");
exit(1);
}
pcur->x = POS_X +2 * i;
pcur->y = POS_Y;
pcur->next = NULL;
if (ps->SnakeHead == NULL)
{
ps->SnakeHead = pcur;
}
else {
pcur->next = ps->SnakeHead;
ps->SnakeHead = pcur;
}
//SetPos(pcur->x, pcur->y);
//wprintf(L"%c", BODY);
}
pcur = ps->SnakeHead;
while (pcur) {
SetPos(pcur->x, pcur->y);
wprintf(L"%c", BODY);
pcur = pcur->next;
}
ps->FoodWeight = 1;
ps->Score = 0;
ps->SleepTime = 200;
ps->dir = RIGHT;
ps->status = OK;
ps->speed = 10;
}
void Welcome() {
SetPos(40, 12);
printf("欢迎来到我的游戏场地!");
SetPos(40, 13);
printf("贪吃蛇小游戏!!!!!");
SetPos(40, 20);
system("pause");
system("cls");
SetPos(30, 13);
printf("用W.A.S.D分别控制蛇的方向");
SetPos(30, 14);
printf("Q为加速,E为减速,加速可以获得更多的道哦");
SetPos(38, 20);
system("pause");
system("cls");
}
void CreateFood(pSnake ps)
{
//确保食物会出现在2的倍数上且食物不在墙里
//所以食物的x>2并且y>1
//采用时间戳随机获得0到54的数字和0到27的数字
int x = 0;
int y = 0;
again:
do
{
x = rand() % 53 + 2;
y = rand() % 25 + 1;
} while (x % 2 != 0);
//食物不在蛇肚子里
pSnakeNode pcur = ps->SnakeHead;
while (pcur) {
if (pcur->x == x && pcur->y == y)
{
goto again;
}
pcur = pcur->next;
}
//创建食物
pSnakeNode Food = (pSnakeNode)malloc(sizeof(SnakeNode));
if (Food == NULL)
{
perror("malloc food");
exit(1);
}
else {
Food->x = x;
Food->y = y;
SetPos(x, y);
wprintf(L"%c", FOOD);
ps->pFood = Food;
}
}
void PrintHelpInfo(pSnake ps)
{
SetPos(60, 10);
printf("请遵守以下规则.");
SetPos(60, 11);
printf("用W.A.S.D控制蛇的方向, Q为加速,E为减速.");
SetPos(60, 12);
printf("ESC :退出游戏.space:暂停游戏.");
SetPos(60, 13);
printf("务必记住不要撞墙也不要咬到自己!!");
}
int NextIsFood(pSnakeNode nextnode, pSnake ps)
{
return (nextnode->x == ps->pFood->x) && (nextnode->y == ps->pFood->y);
}
void EatFood(pSnakeNode nextnode, pSnake ps)
{
//将食物节点头插到🐍,原位置变为空白
nextnode->next = ps->SnakeHead;
ps->SnakeHead = nextnode;
pSnakeNode cur = ps->SnakeHead;
//打印蛇
while (cur)
{
SetPos(cur->x, cur->y);
wprintf(L"%c", BODY);
cur = cur->next;
}
//加分
ps->Score += ps->FoodWeight;
//释放食物节点
free(ps->pFood);
CreateFood(ps);
}
void NoFood(pSnakeNode nextnode, pSnake ps)
{
//头插法
nextnode->next = ps->SnakeHead;
ps->SnakeHead = nextnode;
pSnakeNode cur = ps->SnakeHead;
//打印蛇
while (cur->next->next)
{
SetPos(cur->x, cur->y);
wprintf(L"%c", BODY);
cur = cur->next;
}
//最后⼀个位置打印空格,然后释放节点
SetPos(cur->next->x, cur->next->y);
printf(" ");
free(cur->next);
cur->next = NULL;
}
void SnakeMove(pSnake ps)
{
//创建下一个节点
pSnakeNode nextnode = (pSnakeNode)malloc(sizeof(SnakeNode));
if (nextnode == NULL)
{
perror("malloc nextnode");
exit(1);
}
//确定下一个节点的坐标,根据蛇头方向和dir方向确定
switch (ps->dir)
{
case UP:
nextnode->x = ps->SnakeHead->x;
nextnode->y = ps->SnakeHead->y-1;
break;
case DOWN:
nextnode->x = ps->SnakeHead->x;
nextnode->y = ps->SnakeHead->y+1;
break;
case RIGHT:
nextnode->x = ps->SnakeHead->x+2;
nextnode->y = ps->SnakeHead->y;
break;
case LEFT:
nextnode->x = ps->SnakeHead->x-2;
nextnode->y = ps->SnakeHead->y;
break;
}
//如果下一个就是食物
if(NextIsFood(nextnode, ps))
{
EatFood(nextnode,ps);
}
else//如果没有⻝物
{
NoFood(nextnode, ps);
}
KillByWall(ps);
KillBySelf(ps);
}
void pause()
{
while (1)
{
Sleep(300);
if (KEY_PRESS(VK_SPACE))
{
break;
}
}
}
void GameStart(pSnake ps)
{
//开始游戏首先先把基本场地搞出来
system("mode con cols=100 lines=30");
system("title 贪吃蛇");
//精细化游戏场地
//1.先把光标隐藏
/// 获取标准输出的句柄(⽤来标识不同设备的数值)
HANDLE hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
//影藏光标操作
CONSOLE_CURSOR_INFO CursorInfo;
GetConsoleCursorInfo(hOutput, &CursorInfo);//获取控制台光标信息
CursorInfo.bVisible = false; //隐藏控制台光标
SetConsoleCursorInfo(hOutput, &CursorInfo);//设置控制台光标状态
//打印欢迎界面
Welcome();
//创建游戏场地
CreatMap();
//创建🐍身
InitSnake(ps);
//创建食物
CreateFood(ps);
//打印提示信息
PrintHelpInfo(ps);
}
int KillByWall(pSnake ps)
{
if ((ps->SnakeHead->x == 0)
|| (ps->SnakeHead->x == 56)
|| (ps->SnakeHead->y == 0)
|| (ps->SnakeHead->y == 26))
{
ps->status = KILL_BY_WALL;
return 1;
}
return 0;
}
int KillBySelf(pSnake ps)
{
pSnakeNode cur = ps->SnakeHead->next;
while (cur)
{
if ((ps->SnakeHead->x == cur->x)
&& (ps->SnakeHead->y == cur->y))
{
ps->status = KILL_BY_SELF;
return 1;
}
cur = cur->next;
}
return 0;
}
void GameRun(pSnake ps)
{
//移动🐍
do {
SetPos(60, 15);
printf("您当前的速度为:%d.", ps->speed);
SetPos(60, 16);
printf("可获得的道的数量:%d.",ps->FoodWeight);
SetPos(60, 17);
printf("您当前的道的数量为:%d.", ps->Score);
if (KEY_PRESS(0x57) && ps->dir != DOWN)
{
ps->dir = UP;
}
else if (KEY_PRESS(0x53) && ps->dir != UP)
{
ps->dir = DOWN;
}
else if (KEY_PRESS(0x41) && ps->dir != RIGHT)
{
ps->dir = LEFT;
}
else if (KEY_PRESS(0x44) && ps->dir != LEFT)
{
ps->dir = RIGHT;
}
else if (KEY_PRESS(VK_SPACE))
{
pause();
}
else if (KEY_PRESS(VK_ESCAPE))
{
ps->status = END_NORMAL;
break;
}
else if (KEY_PRESS(0x51))
{
if (ps->SleepTime >= 50)
{
ps->speed += 2;
ps->SleepTime -= 30;
ps->FoodWeight += 2;
}
}
else if (KEY_PRESS(0x45))
{
if (ps->SleepTime < 300)
{
ps->speed -= 2;
ps->SleepTime += 30;
ps->FoodWeight -= 2;
if (ps->SleepTime == 350)
{
ps->FoodWeight = 1;
}
}
}
//蛇每次⼀定之间要休眠的时间,时间短,蛇移动速度就
Sleep(ps->SleepTime);
SnakeMove(ps);
} while (ps->status==OK);
}
void GameEnd(pSnake ps)
{
pSnakeNode cur = ps->SnakeHead;
SetPos(24, 12);
switch (ps->status)
{
case END_NORMAL:
printf("您主动退出游戏\n");
break;
case KILL_BY_SELF:
printf("您撞上自己了 ,游戏结束!\n");
break;
case KILL_BY_WALL:
printf("您撞墙了,游戏结束!\n");
break;
}
//释放蛇身的节点
while (cur)
{
pSnakeNode del = cur;
cur = cur->next;
free(del);
}
//释放食物
free(ps->pFood);
}
//测试文件test.c
#define _CRT_SECURE_NO_WARNINGS 1
#include "GameSnake.h"
#include <graphics.h>
void Game()
{
int ch = 0;
srand((unsigned int)time(NULL));
setlocale(LC_ALL, "");
Snake snake = { 0 };
do {
GameStart(&snake);
GameRun(&snake);
GameEnd(&snake);
SetPos(20, 15);
printf("还要在来一次吗?(Y/N)");
ch = getchar();
getchar();//清理'\n'
} while (ch=='Y'||ch=='y');
}
int main()
{
/*initgraph(1024, 494);
loadimage(0, L"src/bg.jpg");
mciSendString(L"play src/bg.mp3 repeat", 0, 0, 0);
system("pause");*/
Game();
return 0;
}