本篇仅提供C语言代码,详细讲解在这篇博客:C语言:贪吃蛇游戏(从0开始完整版)-CSDN博客
1、运行演示
QQ2024618-155655
2、代码构成(vs编译器)
3、C语言代码
3.1 头文件Snake.h
#pragma once
#include <locale.h>
#include <windows.h>
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#define POS_X 24
#define POS_Y 5
#define WALL L'□'
#define BODY L'●'
#define FOOD L'★'
//类型的声明
//蛇的方向
enum DIRECTION
{
UP = 1,
DOWN,
LEFT,
RIGHT
};
//蛇的状态
//正常、撞墙、撞到自己、正常退出
enum GAME_STATUS
{
OK, //正常
KILL_BY_WALL, //撞墙
KILL_BY_SELF, //撞到自己
END_NORMAL //正常退出
};
//蛇身的节点类型
typedef struct SnakeNode
{
//坐标
int x;
int y;
//指向下一个节点的指针
struct SnakeNode* next;
}SnakeNode, * pSnakeNode;
//贪吃蛇
typedef struct Snake
{
pSnakeNode _pSnake;//指向蛇头的指针
pSnakeNode _pFood;//指向食物节点的指针
enum DIRECTION _dir;//蛇的方向
enum GAME_STATUS _status;//游戏的状态
int _food_weight;//一个食物的分数
int _score; //总成绩
int _sleep_time; //休息时间,时间越短,速度越快,时间越长,速度越慢
}Snake, * pSnake;
//函数的声明
//
//
//定位光标位置
void SetPos(int x, int y);
//欢迎界面的打印
void WelcomeToGame();
//游戏的初始化
void GameStart(pSnake ps);
//创建地图
void CreateMap();
//初始化蛇身
void InitSnake(pSnake ps);
//创建食物
void CreateFood(pSnake ps);
//游戏运行的逻辑
void GameRun(pSnake ps);
//蛇的移动-走一步
void SnakeMove(pSnake ps);
//判断下一个坐标是否是食物
int NextIsFood(pSnakeNode next, pSnake ps);
//下一个位置是食物,就吃掉食物
void EatFood(pSnakeNode next, pSnake ps);
//下一个位置不是食物
void NoFood(pSnakeNode next, pSnake ps);
//检测蛇是否撞墙
void KillByWall(pSnake ps);
//检测蛇是否撞到自己
void KillBySelf(pSnake ps);
//游戏善后的工作
void GameEnd(pSnake ps);
3.2 Snake.c(游戏相关代码)
#define _CRT_SECURE_NO_WARNINGS 1
#include "snake.h"
void SetPos(int x, int y)
{
HANDLE hOutput = NULL;
//获取标准输出的句柄(⽤来标识不同设备的数值)
hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
COORD pos = { x,y };
SetConsoleCursorPosition(hOutput, pos);
}
void WelcomeToGame()
{
SetPos(40, 12);
wprintf(L"欢迎来到贪吃蛇小游戏!");
SetPos(43, 17);
system("pause");
system("cls");
SetPos(25, 14);
wprintf(L"用 ↑. ↓ . ← . → 来控制蛇的移动,按F3加速,F4减速\n");
SetPos(40, 16);
wprintf(L"加速能够得到更高的分数\n");
SetPos(43, 20);
system("pause");
system("cls");
}
//●
void CreateMap()
{
//上围墙
for (int i = 0; i < 29; i++)
{
wprintf(L"%c", WALL);
}
//下围墙
SetPos(0, 26);
for (int i = 0; i < 29; i++)
{
wprintf(L"%c", WALL);
}
//左围墙
for (int i = 1; i < 26; i++)
{
SetPos(0, i);
wprintf(L"%c", WALL);
}
//右围墙
{
for (int i = 1; i < 26; i++)
{
SetPos(56, i);
wprintf(L"%c", WALL);
}
}
}
#include <errno.h>
//初始化蛇身
void InitSnake(pSnake ps)
{
pSnakeNode cur = NULL;
for (int i = 0; i < 5; i++)
{
cur = (pSnakeNode)malloc(sizeof(SnakeNode));
if (cur == NULL)
{
perror("InitSnake::malloc() fail\n");
return;
}
cur->x = POS_X + i * 2;
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", BODY);
cur = cur->next;
}
//设置贪吃蛇的属性
ps->_dir = RIGHT;//默认向右
ps->_score = 0;
ps->_food_weight = 10;
ps->_sleep_time = 200;//单位是毫秒
ps->_status = OK;
}
//创建食物
void CreateFood(pSnake ps)
{
#if 1
int x = 0;
int y = 0;
again:
do
{
x = rand() % 53 + 2;//2~54
y = rand() % 25 + 1;//1~25
} while (x % 2 != 0);//只能为2的倍数
pSnakeNode cur = ps->_pSnake;
while (cur)
{
//不能和蛇身的坐标重合
if (cur->x == x && cur->y == 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;
pFood->next = NULL;
SetPos(x, y);
wprintf(L"%lc", FOOD);
ps->_pFood = pFood;
#endif
}
void GameStart(pSnake ps)
{
system("mode con cols=100 lines=30");
system("title 贪吃蛇");
HANDLE houtput = GetStdHandle(STD_OUTPUT_HANDLE);
//隐藏光标操作
CONSOLE_CURSOR_INFO CursorInfo;
GetConsoleCursorInfo(houtput, &CursorInfo);//获取控制台光标信息
CursorInfo.bVisible = false; //隐藏控制台光标
SetConsoleCursorInfo(houtput, &CursorInfo);//设置控制台光标状态
WelcomeToGame();
CreateMap();
InitSnake(ps);
CreateFood(ps);
}
void HelpInfor(pSnake ps)
{
SetPos(60, 12);
printf("不能穿墙,不能咬伤自己");
SetPos(60, 13);
printf("用 ↑. ↓ . ← . → 来控制蛇的移动");
SetPos(60, 14);
printf("按F3加速,F4减速");
SetPos(60, 15);
printf("ESC:退出游戏 space:暂停游戏");
SetPos(60, 18);
printf("由用户 小丁爱养花 制作");
}
//最⾼位是1,说明按键的状态是按下,
// 如果最⾼是0,说明按键的状态是抬起
#define KeyPress(VK) (GetAsyncKeyState(VK)&1)
void Pause()
{
while (1)
{
Sleep(200);
if (KeyPress(VK_SPACE))
{
break;
}
}
}
//判断下一个坐标是否是食物
int NextIsFood(pSnakeNode next, pSnake ps)
{
if (next->x == ps->_pFood->x && next->y == ps->_pFood->y)
{
return 1;
}
else
{
return 0;
}
}
//下一个位置是食物,就吃掉食物
void EatFood(pSnakeNode next, pSnake ps)
{
ps->_pFood->next = ps->_pSnake;
ps->_pSnake = ps->_pFood;
free(next);
next = NULL;
pSnakeNode cur = ps->_pSnake;
while (cur)
{
SetPos(cur->x, cur->y);
wprintf(L"%lc", BODY);
cur = cur->next;
}
ps->_score += ps->_food_weight;
CreateFood(ps);
}
//下一个位置不是食物
void NoFood(pSnakeNode next, pSnake ps)
{
next->next = ps->_pSnake;
ps->_pSnake = next;
pSnakeNode cur = ps->_pSnake;
pSnakeNode prev = NULL;
while (cur->next != NULL)
{
prev = cur;
SetPos(cur->x, cur->y);
wprintf(L"%lc", BODY);
cur = cur->next;
}
SetPos(cur->x, cur->y);
wprintf(L" ");
if (prev)
{
prev->next = NULL;
}
free(cur);
cur = NULL;
}
//检测蛇是否撞墙
void KillByWall(pSnake ps)
{
if (ps->_pSnake->x <= 1|| ps->_pSnake->x >= 56
|| ps->_pSnake->y <= 0|| ps->_pSnake->y >= 26)
{
ps->_status = KILL_BY_WALL;
}
}
//检测蛇是否撞到自己
void KillBySelf(pSnake ps)
{
pSnakeNode body = ps->_pSnake->next;
while (body)
{
if (ps->_pSnake->x == body->x && ps->_pSnake->y == body->y)
{
ps->_status = KILL_BY_SELF;
break;
}
body = body->next;
}
}
//蛇的移动-走一步
void SnakeMove(pSnake ps)
{
pSnakeNode next = (pSnakeNode)malloc(sizeof(SnakeNode));
if (next == NULL)
{
perror("CreateFood()::malloc()");
return;
}
next->next = NULL;
if (ps->_dir == UP)
{
next->x = ps->_pSnake->x;
next->y = ps->_pSnake->y - 1;
}
else if (ps->_dir == DOWN)
{
next->x = ps->_pSnake->x;
next->y = ps->_pSnake->y + 1;
}
else if (ps->_dir == LEFT)
{
next->x = ps->_pSnake->x - 2;
next->y = ps->_pSnake->y;
}
else if (ps->_dir == RIGHT)
{
next->x = ps->_pSnake->x + 2;
next->y = ps->_pSnake->y;
}
if (NextIsFood(next, ps))
{
EatFood(next, ps);
}
else
{
NoFood(next, ps);
}
//检测蛇是否撞墙
KillByWall(ps);
//检测蛇是否撞到自己
KillBySelf(ps);
}
//游戏运行的逻辑
void GameRun(pSnake ps)
{
HelpInfor(ps);
do
{
SetPos(60, 7);
printf("得分:%d 每个食物得分:%d", ps->_score, ps->_food_weight);
if (KeyPress(VK_UP) && ps->_dir != DOWN)
{
ps->_dir = UP;
}
else if (KeyPress(VK_DOWN) && ps->_dir != UP)
{
ps->_dir = DOWN;
}
else if (KeyPress(VK_LEFT) && ps->_dir != RIGHT)
{
ps->_dir = LEFT;
}
else if (KeyPress(VK_RIGHT) && ps->_dir != LEFT)
{
ps->_dir = RIGHT;
}
else if (KeyPress(VK_SPACE))
{
Pause();
}
else if (KeyPress(VK_ESCAPE))
{
ps->_status = END_NORMAL;
}
else if (KeyPress(VK_F3))
{
if (ps->_sleep_time > 80)
{
ps->_sleep_time -= 30;
ps->_food_weight += 2;
}
}
else if (KeyPress(VK_F4))
{
if (ps->_food_weight > 2)
{
ps->_sleep_time += 30;
ps->_food_weight -= 2;
}
}
SnakeMove(ps);
Sleep(ps->_sleep_time);
} while (ps->_status == OK);
}
//游戏善后的工作
void GameEnd(pSnake ps)
{
SetPos(24, 12);
switch(ps->_status)
{
case KILL_BY_WALL:
wprintf(L"!!!您撞上墙壁了,游戏结束!!!");
break;
case KILL_BY_SELF:
wprintf(L"!!!您撞上自己了,游戏结束!!!");
break;
case END_NORMAL:
wprintf(L"!!!您主动退出游戏,游戏结束!!!");
break;
}
pSnakeNode cur = ps->_pSnake;
pSnakeNode prev = NULL;
while (cur)
{
prev = cur;
cur = cur->next;
free(prev);
}
prev = cur = NULL;
}
3.3 test.c(运行相关代码)
#define _CRT_SECURE_NO_WARNINGS 1
#include "snake.h"
//
void TestSnack()
{
//char ch = '\0';
int ch = 0;
do {
system("cls");
Snake snake = { 0 };
GameStart(&snake);
GameRun(&snake);
GameEnd(&snake);
SetPos(20, 15);
printf("是否开始新的一局游戏?Y/N:");
ch = getchar();
//while (getchar() != '\n');
while (getchar() != '\n');
system("cls");
} while (ch == 'y' || ch == 'Y');
SetPos(5, 26);
}
int main()
{
setlocale(LC_ALL, "");
srand((unsigned int)time(NULL));
TestSnack();
return 0;
}