欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 健康 > 美食 > 【C语言】贪吃蛇小游戏

【C语言】贪吃蛇小游戏

2025/5/21 7:51:35 来源:https://blog.csdn.net/jhj9201633/article/details/148070729  浏览:    关键词:【C语言】贪吃蛇小游戏

文章目录

  • 前言
  • 一、贪吃蛇游戏代码
    • test.c文件
    • Snake.h文件
    • Snake.c文件
  • 二、相关函数的介绍
    • 1.COORD
    • 2.Win32 API的介绍
    • 3.GetStdHandle
    • 4.GetConsoleCursorInfo
    • 5.CONSOLE_CURSOR_INFO
    • 5.SetConsoleCursorInf
    • 6.SetConsoleCursorPosition
    • 7.GetAsyncKeyState
  • 总结


前言

哈喽各位好呀。今天小编来给大家分享一个我们小时候都玩过的小游戏,叫做贪吃蛇。如果大家想玩的话,代码我就放下面啦。


一、贪吃蛇游戏代码

test.c文件

#include"Snake.h"      
void test()//完成游戏的测试逻辑
{int  ch;do{system("cls");//清理界面//创建贪吃蛇Snake snake = { 0 };//初始化游戏GameStart(&snake);//运行游戏GameRun(&snake); //结束游戏---善后工作GameEnd(&snake); SetPut(22, 14); printf("您是否需要再来一局? Y/N");ch = getchar(); getchar(); } while (ch == 'y' || ch == 'Y'); SetPut(0, 27);
}
int main()
{//设置适应本地环境setlocale(LC_ALL, ""); srand((unsigned int)time(NULL));test();
}

Snake.h文件

#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 SNAKE L'蛇'
#define KEY_PRESS(VK) ((GetAsyncKeyState(VK)&0x1) ? 1 : 0)  
enum DIRECTION//蛇的方向
{UP=1,DOWN,LEFT,RIGHT
};
enum GAME_STATUS//蛇的状态
{OK,KILL_BY_WALL,KILL_BY_SELF,END_NOMAL };
//蛇身的节点
typedef struct SnakeNode
{//坐标int x;int y;//指向下一个节点的指针struct SnakeNode* next;
}SnakeNode ,*pSnakeNode; typedef struct Snake
{pSnakeNode _pSanke;//指向蛇头的指针pSnakeNode _pFood;//指向食物的指针enum DIRECTION _dir;//蛇的方向enum GAME_STATUS _stutus;//蛇的状态int _food_weight;//一个食物的分数int _score;//总成绩int _sleep_time;//蛇的速度
}Snake,*pSnake;	void SetPut(short x, short y); //获取光标出现的位置void GameStart(pSnake ps);//开始游戏 
void WelcomeGame();//打印欢迎界面
void GreatMap();//打印地图
void InitGame(pSnake ps);//初始化蛇的相关信息    
void CreateFood(pSnake ps);//食物节点void GameRun(pSnake ps);//游戏运行
void PrintHelpInfo();//打印界面右侧信息
bool NextIsFood(pSnakeNode pn, pSnake ps);//判断转向的下一个位置是否有食物
void EatFood(pSnakeNode pn, pSnake ps);//有食物的情况
void NoFood(pSnakeNode pn, pSnake ps);//没有食物的情况
void KillWall(pSnake ps);//撞墙的情况
void KillSelf(pSnake ps);//撞自己的情况
void SnakeMove(pSnake ps);//移动蛇身一步void GameEnd(pSnake ps);//游戏结束

Snake.c文件

#include"Snake.h"
void SetPut(short x, short y)//光标出现的位置
{COORD pos = { x,y };HANDLE hOutput = NULL;hOutput = GetStdHandle(STD_OUTPUT_HANDLE);//句柄//CONSOLE_CURSOR_INFO CursorInfo;//GetConsoleCursorInfo(hOutput, &CursorInfo); //获取控制台的光标信息//CursorInfo.bVisible = false;//隐藏光标//SetConsoleCursorInfo(hOutput, &CursorInfo);//设置光标的状态 SetConsoleCursorPosition(hOutput, pos);//光标的位置位pos   
}
void WelcomeGame()//欢迎界面的打印
{SetPut(40,14); printf("欢迎来到贪吃蛇小游戏\n"); SetPut(42, 20); system("pause"); system("cls");SetPut(25, 15); wprintf(L"用↑..↓..←..→控制蛇的方向,F3加速,F4减速\n");SetPut(25, 20);wprintf(L"加速可以得到更高的分数\n");SetPut(40, 20);system("pause"); system("cls");
}
void GreatMap()//打印地图
{for (int i = 0; i < 29; i++){wprintf(L"%lc", WALL); }SetPut(0, 26);for (int i = 0; i < 29; i++){wprintf(L"%lc", WALL);}for (int i = 1; i <= 25; i++){SetPut(0,i);wprintf(L"%lc", WALL);}for (int i = 1; i <= 25; i++){SetPut(56, i);wprintf(L"%lc", WALL);}}
void InitGame(pSnake ps)//初始化蛇  
{pSnakeNode cur = NULL; for (int i = 0; i < 5; i++)//申请5个节点{cur =(pSnakeNode)malloc(sizeof(SnakeNode));if (cur == NULL){perror("Snake::malloc fail\n");exit(1);}cur->next = NULL;cur->x = POS_X + 2 * i;cur->y = POS_Y;//头插连接if (ps->_pSanke == NULL){ps->_pSanke=cur; }else{cur->next = ps->_pSanke;ps->_pSanke = cur; }}cur = ps->_pSanke;while (cur)//打印蛇身{SetPut(cur->x, cur->y);wprintf(L"%lc", SNAKE);cur = cur->next;}ps->_dir = RIGHT;ps->_food_weight = 10;ps->_score = 0;ps->_stutus =OK; ps->_sleep_time = 200;}
void CreateFood(pSnake ps)//食物节点的创建
{int x = 0;int y = 0;
gain:do{x = rand() % 53 + 2;  y = rand() % 25 + 1; } while (x % 2 != 0);//食物的位置必须是2的倍数pSnakeNode cur = ps->_pSanke ; //食物节点不能和蛇身重合while (cur){if (x == cur->x && y == cur->y)goto gain; cur = cur->next;}//创建食物节点pSnakeNode pFood = (pSnakeNode)malloc(sizeof(SnakeNode));if (pFood == NULL){perror("malloc fail\n");return;}pFood->x = x; pFood->y = y;pFood->next = NULL;SetPut(pFood->x, pFood->y); wprintf(L"%lc", L'食');ps->_pFood = pFood;
}
void GameStart(pSnake ps)//开始游戏
{//设置窗口大小,隐藏光标system("mode con cols=100 lines=30");system("title 贪吃蛇");HANDLE hOutput = NULL; hOutput = GetStdHandle(STD_OUTPUT_HANDLE);//句柄CONSOLE_CURSOR_INFO CursorInfo;GetConsoleCursorInfo(hOutput, &CursorInfo); //获取控制台的光标信息 CursorInfo.bVisible = false;//隐藏光标SetConsoleCursorInfo(hOutput, &CursorInfo);//设置光标的状态 //打印欢迎界面,功能打印WelcomeGame();//地图的绘制GreatMap();//初始化蛇神InitGame(ps);//创建食物CreateFood(ps);
}
void PrintHelpInfo()
{//打印提⽰信息SetPut(64, 15);printf("不能穿墙,不能咬到⾃⼰\n");SetPut(64, 16); printf("⽤↑.↓.←.→分别控制蛇的移动.");SetPut(64, 17); printf("F3 为加速,F4 为减速\n");SetPut(64, 18);printf("ESC :退出游戏.space:暂停游戏.");SetPut(64, 20); printf("小贾制作\n"); 
}
void pause()//暂停
{while (1){Sleep(200);if (KEY_PRESS(VK_SPACE)) break;}
}
bool NextIsFood(pSnakeNode pn, pSnake ps)//判断转向的下一个位置是否有食物
{return pn->x == ps->_pFood->x && pn->y == ps->_pFood->y; 
}
void EatFood(pSnakeNode pn, pSnake ps)//有食物的情况 
{pn->next = ps->_pSanke;ps->_pSanke = pn;pSnakeNode cur = ps->_pSanke;while (cur){SetPut(cur->x, cur->y);wprintf(L"%lc", SNAKE);cur = cur->next;}ps->_score += ps->_food_weight;free(ps->_pFood ); CreateFood(ps);
}
void NoFood(pSnakeNode pn, pSnake ps)//没有食物的情况
{//头插法pn->next = ps->_pSanke; ps->_pSanke = pn; //打印蛇pSnakeNode cur = ps->_pSanke; while (cur->next->next) {SetPut(cur->x, cur->y); wprintf(L"%lc", SNAKE);  cur = cur->next; }//最后⼀个位置打印空格,然后释放节点SetPut(cur->next->x, cur->next->y); printf(" ");   free(cur->next);   cur->next = NULL; 
}
void KillWall(pSnake ps)//撞墙的情况
{if (ps->_pSanke->x == 0 || ps->_pSanke->y == 26 ||ps->_pSanke->x == 56 || ps->_pFood->y == 0)	ps->_stutus = KILL_BY_WALL;
}
void KillSelf(pSnake ps)//撞自己的情况
{pSnakeNode cur = ps->_pSanke->next ; while (cur){if (ps->_pSanke->x == cur->x && ps->_pSanke->y == cur->y){ps->_stutus = KILL_BY_SELF;break;}cur = cur->next;}
}
void SnakeMove(pSnake ps)//移动蛇身一步
{//创建一个蛇身节点 pSnakeNode pNextNode = (pSnakeNode)malloc(sizeof(SnakeNode)); if (pNextNode == NULL){perror("malloc fail\n");return;}switch (ps->_dir){case UP:{pNextNode->x = ps->_pSanke->x;pNextNode->y = ps->_pSanke->y - 1;}break;case DOWN:{pNextNode->x = ps->_pSanke->x; pNextNode->y = ps->_pSanke->y + 1; }break;case LEFT:{pNextNode->x = ps->_pSanke->x - 2; pNextNode->y = ps->_pSanke->y; }break;case RIGHT:{pNextNode->x = ps->_pSanke->x + 2; pNextNode->y = ps->_pSanke->y;   } break;}if (NextIsFood(pNextNode, ps)) {EatFood(pNextNode, ps); }else//如果没有⻝物{NoFood(pNextNode, ps); }KillWall(ps);KillSelf(ps);
}
void GameRun(pSnake ps)//游戏运行
{//打印右侧帮助信息PrintHelpInfo();do{SetPut(64, 10); printf("得分:%d ", ps->_score );  printf("每个⻝物得分:%d分", ps->_food_weight ); 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_SPACE)){pause();}else if (KEY_PRESS(VK_ESCAPE)){ps->_stutus = END_NOMAL; break;}else if (KEY_PRESS(VK_F3)){if (ps->_sleep_time >= 80){ps->_sleep_time -= 30;ps->_food_weight += 2;//⼀个⻝物分数最⾼是20分}}else if (KEY_PRESS(VK_F4)){if (ps->_sleep_time < 320){ps->_sleep_time += 30;ps->_food_weight  -= 2;//⼀个⻝物分数最低是2分}}//蛇每次⼀定之间要休眠的时间,时间短,蛇移动速度就快Sleep(ps->_sleep_time );  SnakeMove(ps);} while (ps->_stutus  == OK);  	
}void GameEnd(pSnake ps)//游戏结束
{SetPut(22, 12);switch (ps->_stutus){case END_NOMAL:{printf("正常退出\n");}break;case KILL_BY_WALL:{printf("您撞墙了,游戏结束!\n");}break;case KILL_BY_SELF:{printf("您撞上您自己了\n");}break;}pSnakeNode cur = ps->_pSanke; while (cur)//清除蛇身{pSnakeNode dir = cur; cur = cur->next; free(dir);}
}

二、相关函数的介绍

1.COORD

控制台屏幕上的坐标COORD

2.Win32 API的介绍

Windows 这个多作业系统除了协调应⽤程序的执⾏、分配内存、管理资源之外, 它同时也是⼀个很⼤的服务中⼼,调⽤这个服务中⼼的各种服务(每⼀种服务就是⼀个函数),可以帮应⽤程序达到开启视窗、描绘图形、使⽤周边设备等⽬的,由于这些函数服务的对象是应⽤程序(Application), 所以便称之为 Application Programming Interface,简称 API 函数。WIN32 API也就就是Microsoft Windows32位平台的应⽤程序编程接⼝

3.GetStdHandle

GetStdHandle

GetStdHandle是⼀个Windows API函数。它⽤于从⼀个特定的标准设备(标准输⼊、标准输出或标准错误)中取得⼀个句柄(⽤来标识不同设备的数值),使⽤这个句柄可以操作设备。

HANDLE GetStdHandle(DWORD nStdHandle);

实例:

HANDLE hOutput = NULL;
//获取标准输出的句柄(⽤来标识不同设备的数值)
hOutput = GetStdHandle(STD_OUTPUT_HANDLE);

4.GetConsoleCursorInfo

GetConsoleCursorInfo

检索有关指定控制台屏幕缓冲区的光标⼤⼩和可⻅性的信息

BOOL WINAPI GetConsoleCursorInfo(HANDLE hConsoleOutput,PCONSOLE_CURSOR_INFO lpConsoleCursorInfo
);
PCONSOLE_CURSOR_INFO 是指向 CONSOLE_CURSOR_INFO 结构的指针,该结构接收有关主机游标

实例:

HANDLE hOutput = NULL;
//获取标准输出的句柄(⽤来标识不同设备的数值)
hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_CURSOR_INFO CursorInfo;
GetConsoleCursorInfo(hOutput, &CursorInfo);//获取控制台光标信息

5.CONSOLE_CURSOR_INFO

这个结构体,包含有关控制台光标的信息

typedef struct _CONSOLE_CURSOR_INFO {DWORD dwSize;BOOL bVisible;
} CONSOLE_CURSOR_INFO, *PCONSOLE_CURSOR_INFO;
  • dwSize,由光标填充的字符单元格的百分⽐。 此值介于1到100之间。 光标外观会变化,范围从完全填充单元格到单元底部的⽔平线条。
  • bVisible,游标的可⻅性。 如果光标可⻅,则此成员为 TRUE。
//示例:
CursorInfo.bVisible = false; //隐藏控制台光标

5.SetConsoleCursorInf

SetConsoleCursorInfo

设置指定控制台屏幕缓冲区的光标的⼤⼩和可⻅性

BOOL WINAPI SetConsoleCursorInfo(HANDLE hConsoleOutput,const CONSOLE_CURSOR_INFO *lpConsoleCursorInfo
);

实例:

HANDLE hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
//影藏光标操作
CONSOLE_CURSOR_INFO CursorInfo;
GetConsoleCursorInfo(hOutput, &CursorInfo);//获取控制台光标信息
CursorInfo.bVisible = false; //隐藏控制台光标
SetConsoleCursorInfo(hOutput, &CursorInfo);//设置控制台光标状态

6.SetConsoleCursorPosition

SetConsoleCursorPosition

设置指定控制台屏幕缓冲区中的光标位置,我们将想要设置的坐标信息放在COORD类型的pos中,调用SetConsoleCursorPosition函数将光标位置设置到指定的位置。

BOOL WINAPI SetConsoleCursorPosition(HANDLE hConsoleOutput,COORD pos
);

实例:

COORD pos = { 10, 5};HANDLE hOutput = NULL;//获取标准输出的句柄(⽤来标识不同设备的数值)hOutput = GetStdHandle(STD_OUTPUT_HANDLE);//设置标准输出上光标的位置为posSetConsoleCursorPosition(hOutput, pos);

SetPut:封装一个设置光标位置的函数

//设置光标的坐标
void SetPos(short x, short y)
{COORD pos = { x, y };HANDLE hOutput = NULL;//获取标准输出的句柄(⽤来标识不同设备的数值)hOutput = GetStdHandle(STD_OUTPUT_HANDLE);//设置标准输出上光标的位置为posSetConsoleCursorPosition(hOutput, pos);
}

7.GetAsyncKeyState

GetAsyncKeyState

获取按键情况,GetAsyncKeyState的函数原型如下:

SHORT GetAsyncKeyState(int vKey
);

将键盘上每个键的虚拟键值传递给函数,函数通过返回值来分辨按键的状态。GetAsyncKeyState 的返回值是short类型,在上⼀次调⽤ GetAsyncKeyState 函数后,如果返回的16位的short数据中,最⾼位是1,说明按键的状态是按下,如果最⾼是0,说明按键的状态是抬起;如果最低位被置为1则说明,该按键被按过,否则为0。
如果我们要判断⼀个键是否被按过,可以检测GetAsyncKeyState返回值的最低值是否为1

#define KEY_PRESS(VK) ( (GetAsyncKeyState(VK) & 0x1) ? 1 : 0 )

参考:虚拟键码 (Winuser.h) - Win32 apps


总结

以上就是贪吃蛇的全部代码以及一些关于.Win32 API的接口的介绍。当然代码还可以优化许多玩法。小编呢就写这么多了。咋们下一期再见吧!感谢您的参观!
在这里插入图片描述

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词