大家好久不见,我是残念我回来了,希望在你看完之后,能对你有所帮助,有什么不足请指正!共同学习交流
本文由:残念ing原创CSDN首发,如需要转载请通知
个人主页:残念ing-CSDN博客,欢迎各位→点赞👍 + 收藏⭐️ + 留言📝
📣系列专栏:残念ing 的C语言系列专栏——CSDN博客
头文件和主函数的声明
snake.h
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<windows.h>
#include<stdbool.h>
#include<locale.h>
#define WALL L'■'
#define SNAKE L'●'
#define HEADSNAKE L'○'
#define FOOD L'★'
#define POS_X 24
#define POS_Y 5
#define KEY_PRESS(VK) ((GetAsyncKeyState(VK)&0x1)? 1:0)
//游戏状态
enum GAME_STATUS
{
OK = 1,//正常运行
ESC,//正常退出
KILL_BY_WALL,//撞墙了
KILL_BY_SELF//撞到自己了
};
//⽅向
enum DIRECTION
{
UP = 1,
DOWN,
LEFT,
RIGHT
};
//蛇身结点的定义
typedef struct SnakeNode
{
int x;
int y;
struct SnakeNode* next;
}SnakeNode,* pSnakeNode;
//typedef struct SnakeNode* pSnakeNode;
//蛇
typedef struct Snake
{
pSnakeNode pSnake;//维护整条蛇的指针,指向蛇头
pSnakeNode pFood;//指向食物的指针
int Score;//当前累计的分数
int FoodWeight;//一个食物的分数
int SleepTime;//整条蛇的睡眠时间,休眠的时间越短,蛇的速度越快,休眠的时间越长,蛇的速度越慢
enum GAME_STATUS status;//游戏当前的状态
enum DIRECTION dir;//蛇当前走的方向
}Snake,* pSnake;
//定位控制台光标位置
void setpos(int x, int y);
//游戏准备
void GameStart(pSnake ps);
//打印欢迎界面
void WelcomeToGame();
//绘制地图
void CreateMap();
//初始化贪吃蛇
void InintSnake(pSnake ps);
//创建食物
void CreateFood(pSnake ps);
//运行整个游戏的逻辑
void GameRun(pSnake ps);//玩游戏的过程
//打印帮助信息
void printfHelpInfo();
//每次的移动
void SnakeMove(pSnake ps);
//判断蛇头下一步要走的位置是不是食物 是返回1,不是返回0;
int NextIsFood(pSnake ps, pSnakeNode pnext);
//是食物就吃
void EatFood(pSnake ps, pSnakeNode pnext);
//不是食物
void NotEatFood(pSnake ps, pSnakeNode pnext);
//检测撞墙
void KillByWall(pSnake ps);
//检测撞到自己
void KillBySelf(pSnake ps);
//游戏结束的善后
void GameEnd(pSnake ps);//善后工作
主函数的详细实现
snake.c
#define _CRT_SECURE_NO_WARNINGS 1
#include"snake.h"
//将光标位置设置到指定的位置
void setpos(int x, int y)
{
//获取句柄
HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
//设置光标的坐标
COORD tmp = { x,y };
SetConsoleCursorPosition(handle, tmp);
}
void WelcomeToGame()
{
setpos(40,10);
printf("欢迎来到贪吃蛇小游戏!!!");
setpos(43, 20);
system("pause");//请按任意键继续进行下一步
system("cls");//清屏
setpos(10, 10);
printf("请用 ↑ ↓ ← → 分别来控制蛇的移动,SHIFT为加速,CTRL为减速");
setpos(40, 12);
printf("注意:加速将会使你得到更多分");
setpos(43, 20);
system("pause");//请按任意键继续进行下一步
system("cls");//清屏
}
//打印墙
void CreateMap()
{
//上
setpos(0, 0);
for (int i = 0; i <= 56; i += 2)
{
wprintf(L"%lc", WALL);
}
//下
setpos(0, 26);
for (int i = 0; i <= 56; i += 2)
{
wprintf(L"%lc", WALL);
}
//左
for (int i = 0; i <=25; i++)
{
setpos(0, i);
wprintf(L"%lc", WALL);
}
//右
for (int i = 0; i <=25; i++)
{
setpos(56, i);
wprintf(L"%lc", WALL);
}
}
//初始化蛇
void InintSnake(pSnake ps)
{
pSnakeNode cur=NULL;
for (int i = 0; i < 5; i++)
{
cur = (pSnakeNode)malloc(sizeof(SnakeNode));
if (cur == NULL)
{
perror("InintSnake():malloc");
return;
}
cur->x = POS_X + 2 * i;
cur->y = POS_Y;
cur->next = NULL;
//头插
if (ps->pSnake == NULL)
{
ps->pSnake = cur;
}
else
{
cur->next = ps->pSnake;
ps->pSnake = cur;
}
}
//打印蛇
cur = ps->pSnake;
while (cur)
{
setpos(cur->x, cur->y);
wprintf(L"%lc", SNAKE);
cur = cur->next;
}
//贪吃蛇的基本属性初始化
ps->dir = RIGHT;
ps->FoodWeight = 10;
ps->pFood = NULL;
ps->Score = 0;
ps->SleepTime = 200;
ps->status = OK;
}
//创建食物
void CreateFood(pSnake ps)
{
int x = 0;
int y = 0;
again:
do
{
x = rand() % 53 + 2;
y = rand() % 24 + 1;
} while (x % 2 != 0);
//坐标和蛇的身体的每个节点的做坐标比较
pSnakeNode cur = ps->pSnake;
while (cur)
{
if (x == cur->x && y == cur->y)
{
goto again;
}
cur = cur->next;
}
//创建食物
pSnakeNode pFood = (pSnakeNode)malloc(sizeof(SnakeNode));
if (pFood == NULL)
{
perror("CreateFood()::malloc()");
return;
}
pFood->x = x;
pFood->y = y;
ps->pFood = pFood;
setpos(x, y);
wprintf(L"%lc", FOOD);
}
void GameStart(pSnake ps)
{
//设置控制台的信息,窗口大小,窗口名
system("mode con cols=100 lines=30");//设置窗口的长和宽
system("title 贪吃蛇");//设置窗口名
//隐藏关标
HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);//获取标准输出的句柄
CONSOLE_CURSOR_INFO CursorInfo;
GetConsoleCursorInfo(handle, &CursorInfo);//获取控制台光标信息
CursorInfo.bVisible = false;//隐藏控制台光标
SetConsoleCursorInfo(handle, &CursorInfo);//设置控制台光标的状态
//打印欢迎信息
WelcomeToGame();
//绘制地图
CreateMap();
//初始化蛇
InintSnake(ps);
//创建食物
CreateFood(ps);
}
void printfHelpInfo()
{
setpos(63, 15);
printf("注意:不能穿墙,不能咬到自己");
setpos(63, 16);
printf("用↑↓← →分别来控制蛇的移动");
setpos(63, 17);
printf("SHIFT为加速,CTRL为减速");
setpos(63, 18);
printf("Esc为退出游戏,space为暂停游戏");
}
void pause()
{
while (1)
{
Sleep(100);
if (KEY_PRESS(VK_SPACE))
{
break;
}
}
}
int NextIsFood(pSnake ps, pSnakeNode pnext)
{
if (ps->pFood->x == pnext->x && ps->pFood->y == pnext->y)
{
return 1;
}
else
return 0;
}
void EatFood(pSnake ps, pSnakeNode pnext)
{
pnext->next = ps->pSnake;
ps->pSnake = pnext;
//打印蛇
pSnakeNode cur = ps->pSnake;
while (cur)
{
setpos(cur->x, cur->y);
wprintf(L"%lc", SNAKE);
cur = cur->next;
}
ps->Score += ps->FoodWeight;
//释放旧的食物
free(ps->pFood);
//新建食物
CreateFood(ps);
}
void NotEatFood(pSnake ps, pSnakeNode pnext)
{
//头插法
pnext->next = ps->pSnake;
ps->pSnake = pnext;
//释放尾结点
pSnakeNode cur = ps->pSnake;
while (cur->next->next)
{
setpos(cur->x, cur->y);
wprintf(L"%lc", SNAKE);
cur = cur->next;
}
//将尾节点的位置打印成空白字符
setpos(cur->next->x, cur->next->y);
printf(" ");
free(cur->next);
cur->next = NULL;//易错
}
void KillByWall(pSnake ps)
{
if (ps->pSnake->x == 0 || ps->pSnake->x == 56 || ps->pSnake->y == 0 || ps->pSnake->y == 26)
{
ps->status = KILL_BY_WALL;
}
}
void KillBySelf(pSnake ps)
{
pSnakeNode cur = ps->pSnake->next;
while (cur)
{
if (cur->x == ps->pSnake->x && cur->y == ps->pSnake->y)
{
ps->status = KILL_BY_SELF;
return;
}
cur = cur->next;
}
}
void SnakeMove(pSnake ps)
{
pSnakeNode pnext = (pSnakeNode)malloc(sizeof(SnakeNode));
if (pnext == NULL)
{
perror("SnakeMove()::malloc()");
return;
}
pnext->next = NULL;
switch (ps->dir)
{
case UP:
pnext->x = ps->pSnake->x;
pnext->y = ps->pSnake->y - 1;
break;
case DOWN:
pnext->x = ps->pSnake->x;
pnext->y = ps->pSnake->y + 1;
break;
case LEFT:
pnext->x = ps->pSnake->x - 2;
pnext->y = ps->pSnake->y;
break;
case RIGHT:
pnext->x = ps->pSnake->x + 2;
pnext->y = ps->pSnake->y;
break;
}
//下一个坐标是不是食物
if (NextIsFood(ps, pnext))
{
//是食物就吃
EatFood(ps, pnext);
}
else
{
//不是食物就走
NotEatFood(ps, pnext);
}
//检测撞墙
KillByWall(ps);
//检测撞到自己
KillBySelf(ps);
}
void GameRun(pSnake ps)
{
//打印帮助信息
printfHelpInfo();
//检测按键
do
{
//当前的分数情况
setpos(63,10);
printf("总得分:%5d 每个食物: %02d",ps->Score,ps->FoodWeight);
//检查按键
// 上 下 左 右 ESC 空格 shift Ctrl
if (KEY_PRESS(VK_UP) && ps->dir != DOWN)
{
ps->dir = UP;
}
else if (KEY_PRESS(VK_DOWN) && ps->dir != UP)
{
ps->dir = DOWN;
}
else if (KEY_PRESS(VK_LEFT) && ps->dir != RIGHT)
{
ps->dir = LEFT;
}
else if (KEY_PRESS(VK_RIGHT) && ps->dir != LEFT)
{
ps->dir = RIGHT;
}
else if (KEY_PRESS(VK_ESCAPE))
{
ps->status = ESC;
break;
}
else if (KEY_PRESS(VK_SPACE))
{
//游戏要暂定
pause();//暂定和回复暂定
}
else if(KEY_PRESS(VK_RSHIFT))
{
if (ps->SleepTime >= 80)
{
ps->SleepTime -= 30;
ps->FoodWeight += 2;
}
}
else if (KEY_PRESS(VK_RCONTROL))
{
if (ps->FoodWeight > 2)
{
ps->SleepTime += 30;
ps->FoodWeight -= 2;
}
}
//睡眠一下
Sleep(ps->SleepTime);
//走一步
SnakeMove(ps);
} while (ps->status==OK);
}
void GameEnd(pSnake ps)
{
setpos(17, 15);
switch (ps->status)
{
case ESC:
printf("退出游戏\n");
break;
case KILL_BY_WALL:
printf("撞到墙了!!!!,游戏结束\n");
break;
case KILL_BY_SELF:
printf("咬到自己了!!!!,游戏结束\n");
break;
}
//释放贪吃蛇的链表资源
pSnakeNode cur = ps->pSnake;
pSnakeNode del = NULL;
while (cur)
{
del = cur;
cur = cur->next;
free(del);
}
free(ps->pFood);
ps = NULL;
}
关于代码的测试
snake_test.c
#define _CRT_SECURE_NO_WARNINGS 1
#include "snake.h"
void test()
{
int ret = 0;
do
{
ret = 0;
Snake snake = { 0 };
GameStart(&snake);//游戏开始前的初始化
GameRun(&snake);//玩游戏的过程
GameEnd(&snake);//游戏的善后
Sleep(800);
system("cls");//清屏
setpos(40, 15);
printf("要再来一次吗???(Y/N)");
ret=getchar();
getchar();//清理\n
} while (ret=='Y'||ret=='y');
}
int main()
{
//修该适合本地中文环境
setlocale(LC_ALL, "");
test();//贪吃蛇的测试
return 0;
}
这是详细代码,之后会给大家详细解答。