1.地图绘制;
2.上下左右键控制蛇的动作;
3.蛇撞墙死亡;
4.蛇撞自己死亡;
5.计算得分;
6.蛇加速,减速;
7.暂停游戏。
windows作为开发系统为程序员提供的一些函数接口,用以实现一些功能。
注:只在windows系统中可用。
cmd的程序---终端/控制台程序---运行起来的黑框
mode con cols=100 lines=30
#include
int main()
{
system("mode con cols=50 lines=20");//这个函数就能执行系统命令
printf("hehe\n");
return 0;
}
title 贪吃蛇
system("title 贪吃蛇");
system("pause");
注:会自动打印 “ 请按任意键继续. . . ”。
system("cls");
1.需包含
2.COORD为描述坐标所需结构体。
3.横轴向右为x轴正方向,纵轴向下为y轴正方向。
COORD pos = { 3,5 };
GetStdHandle是一个API函数。它用于从一个特定的标准设备(标准输入,标准输出,标准错误)中取得一个句柄(设备的控制权限),用来操作设备。
HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);//获得标准输出的句柄
检索有关指定控制台屏幕缓冲区光标大小和可见性信息。
它包含了有关控制台光标的信息。
typedef struct _CONSOLE_CURSOR_INFO {
DWORD dwSize;
BOOL bVisible;
}CONSOLE_CURSOR_INFO,*PCONSOLE_CURSOR_INFO;
dwSize:此值介于1到100之间。光标外观发生变化,从完全填充到单元底部的水平线条。
bVisible:光标的可见性。
例:隐藏光标:
cursor_info.bVisible = false;
设置有关指定控制台屏幕缓冲区光标大小和可见性信息。
e.g:
int main()
{
HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);//获得标准输出的句柄
CONSOLE_CURSOR_INFO cursor_info;
GetConsoleCursorInfo(handle,&cursor_info);
cursor_info.dwSize = 1;
SetConsoleCursorInfo(handle,&cursor_info);
return 0;
}
设置有关指定控制台屏幕缓冲区光标位置。
用法:将坐标信息放在COORD类型的pos中,调用SetConsoleCursorPosition函数将光标位置设置到指定的位置。
例:封装一个SetPos函数,用来设置光标位置:
void SetPos(int x, int y)
{
HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
COORD pos = { x,y };
SetConsoleCursorPosition(handle, pos);
}
1.功能:获取按键情况。
上下左右键对应的虚拟键代码:
VK_LEFT---0x25 ; VK_UP---0x26 ; VK_RIGHT---0x27 ; VK_DOWN---0x28 ;
2.返回值:
short类型。最高位:1为按下,0为抬起;最低位:1为按下过,0为未按过。
例:封装一个检测vk这个虚拟键值对应的按键是否被按过的宏:
#define PRESS_KET(vk)(GetAsyncKeyState(vk)&0x1?1:0)
由于贪吃蛇墙体,蛇身等字块为宽字符,而c语言默认不包含宽字符,故需要在locale上进行修改。
locale是c语言针对不同地区字符的区别,所提供的标准和当前地区的语言设置。
如想输出宽字符,需将locale改为Chinese。
程序员可指定部分设置进行地区修改,各部分称为类项。
char* setlocale ( int category , const chat* locale )
第一个参数为修改类项;
第二个参数只有两个取值:“C”和“ ”(本地模式)
#include
int main()
{
setlocale(LC_ALL, "");
wchar_t ch1 = L'几';//宽字符的类型
wchar_t ch2 = L'个';
printf("ab\n");
wprintf(L"%lc\n", ch1);//打印宽字符
wprintf(L"%lc\n", ch2);
wprintf(L"%lc\n", ch1);
wprintf(L"%lc\n", ch2);
return 0;
}
x轴坐标需为偶数,其他详见2.3 。
enum DIRECTION
{
UP = 1,
DOWN,
LEFT,
RIGHT
};
enum GAME_STATUS
{
OK,
END_NORMAL,
KILL_BY_WALL,
KILL_BY_SELF
};
//贪吃蛇的节点
typedef struct SnakeNode
{
int x;
int y;
struct SnakeNode* next;
}SnakeNode,*pSnakeNode;
//贪吃蛇的结构
typedef struct Snake
{
pSnakeNode _psnake;//指向贪吃蛇头节点的指针
pSnakeNode _pFood;//指向食物节点的指针
int _Score;//贪吃蛇积累的总分
int _FoodWeight;//一个食物的分数
int _SleepTime;//每走一步休息的时间,时间越短速度越快
enum DIRECTION _Dir;//描述蛇的方向
enum GAME_STATUS _Status;//游戏的状态:正常,退出,撞墙,撞到自己
}Snake,*pSnake;
#pragma once
#include
#include
#include
#include
#include
#include
#define WALL L'□'
#define BODY L'●'
#define FOOD L'★'
#define POS_X 24
#define POS_Y 5
#define PRESS_KET(vk)(GetAsyncKeyState(vk)&0x1?1:0)
enum DIRECTION
{
UP = 1,
DOWN,
LEFT,
RIGHT
};
enum GAME_STATUS
{
OK,
END_NORMAL,
KILL_BY_WALL,
KILL_BY_SELF
};
//贪吃蛇的节点
typedef struct SnakeNode
{
int x;
int y;
struct SnakeNode* next;
}SnakeNode,*pSnakeNode;
//贪吃蛇的结构
typedef struct Snake
{
pSnakeNode _psnake;//指向贪吃蛇头节点的指针
pSnakeNode _pFood;//指向食物节点的指针
int _Score;//贪吃蛇积累的总分
int _FoodWeight;//一个食物的分数
int _SleepTime;//每走一步休息的时间,时间越短速度越快
enum DIRECTION _Dir;//描述蛇的方向
enum GAME_STATUS _Status;//游戏的状态:正常,退出,撞墙,撞到自己
}Snake,*pSnake;
//1.游戏开始 - 初始化游戏
void GameStart(pSnake ps);
void WelcomeToGame();//游戏开始的欢迎界面
void CreateMap();//打印地图
void InitSnake(pSnake ps);//初始化蛇
void CreateFood(pSnake ps);//创建食物
//2.游戏运行
void GameRun(pSnake ps);
void PrintHelpInfo();//打印辅助信息
void SnakeMove(pSnake ps);//蛇的移动
int NextIsFood(pSnake ps, pSnakeNode pNext);//判断下一个位置是否是食物
void KillByWall(pSnake ps);//蛇是否撞墙
void KillBySelf(pSnake ps);//蛇是否自杀
//3.游戏结束
void GameEnd(pSnake ps);
#include"snake.h"
//1.游戏开始 - 初始化游戏
void SetPos(int x, int y)
{
HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
COORD pos = { x,y };
SetConsoleCursorPosition(handle, pos);
}
void WelcomeToGame()
{
//定位光标
SetPos(40, 15);
printf("欢迎来到贪吃蛇小游戏!");
SetPos(40, 25);
system("pause");
system("cls");
SetPos(25, 15);
printf("使用↑.↓.←.→控制蛇的移动,F3是加速,F4是减速");
SetPos(40, 25);
system("pause");
system("cls");
}
void CreateMap()
{
//上
SetPos(0, 0);
int i = 0;
for (i = 0; i <= 56; i += 2)
{
wprintf(L"%lc", WALL);
}
//下
SetPos(0, 26);
for (i = 0; i <= 56; i += 2)
{
wprintf(L"%lc", WALL);
}
//左
for (i = 1; i <= 25; i++)
{
SetPos(0, i);
wprintf(L"%lc", WALL);
}
//右
for (i = 1; i <= 25; i++)
{
SetPos(56, i);
wprintf(L"%lc", WALL);
}
}
void InitSnake(pSnake ps)
{
pSnakeNode cur = NULL;
int i = 0;
for (i = 0; i < 5; i++)
{
cur = (pSnakeNode)malloc(sizeof(SnakeNode));
if (cur == NULL)
{
perror("InitSnake()::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", BODY);
cur = cur->next;
}
ps->_Status = OK;
ps->_Score = 0;
ps->_pFood = NULL;
ps->_SleepTime = 200;
ps->_FoodWeight = 10;
ps->_Dir = RIGHT;
}
void CreateFood(pSnake ps)
{
int x;
int y;
again:
do
{
x = rand() % 53 + 2;
y = rand() % 25 + 1;
} while (x % 2 != 0);
//坐标不能和蛇的身体冲突
pSnakeNode cur = ps->_psnake;
if (cur->x == x && cur->y == y)
{
goto again;
}
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 cursor_info;
GetConsoleCursorInfo(handle, &cursor_info);
cursor_info.bVisible = false;
SetConsoleCursorInfo(handle, &cursor_info);
//打印欢迎界面
WelcomeToGame();
//创建地图
CreateMap();
//初始化贪吃蛇
InitSnake(ps);
//创建食物
CreateFood(ps);
}
//2.游戏运行
void PrintHelpInfo()//打印辅助信息
{
SetPos(64, 15);
printf("1.不能撞墙,不能咬自己。");
SetPos(64, 16);
printf("2.使用↑、↓、←、→控制蛇的移动。");
SetPos(64, 17);
printf("3.F3加速,F4减速。");
SetPos(64, 18);
printf("4.ESC退出,空格暂停。");
SetPos(64, 20);
printf("几个几个@版权");
}
int NextIsFood(pSnake ps, pSnakeNode pNext)//判断下一个位置是否是食物
{
if (ps->_pFood->x == pNext->x && ps->_pFood->y == pNext->y)
return 1;
else return 0;
}
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 (ps->_psnake->x == cur->x && ps->_psnake->y == cur->y)
{
ps->_Status = KILL_BY_SELF;
}
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))//是
{
//头插
pNext->next = ps->_psnake;
ps->_psnake = pNext;
//打印蛇身
SetPos(ps->_psnake->x, ps->_psnake->y);
wprintf(L"%lc", BODY);
//处理食物
free(ps->_pFood);
ps->_Score += ps->_FoodWeight;
CreateFood(ps);
}
else//不是
{
//头插
pNext->next = ps->_psnake;
ps->_psnake = pNext;
//删除最后节点并打印蛇身
SetPos(ps->_psnake->x, ps->_psnake->y);
wprintf(L"%lc", BODY);
pSnakeNode cur = ps->_psnake;
while (cur->next->next)
{
cur = cur->next;
}
SetPos(cur->next->x, cur->next->y);
printf(" ");
free(cur->next);
cur->next = NULL;
}
//蛇是否撞墙
KillByWall(ps);
//蛇是否自杀
KillBySelf(ps);
}
void GameRun(pSnake ps)
{
PrintHelpInfo();
do
{
//打印按键得分
SetPos(64, 10);
printf("得分:%05d", ps->_Score);
SetPos(64, 11);
printf("每个食物的分数:%2d", ps->_FoodWeight);
//判断按键情况
if (PRESS_KET(VK_UP) && ps->_Dir != DOWN)
{
ps->_Dir = UP;
}
else if (PRESS_KET(VK_DOWN) && ps->_Dir != UP)
{
ps->_Dir = DOWN;
}
else if (PRESS_KET(VK_LEFT) && ps->_Dir != RIGHT)
{
ps->_Dir = LEFT;
}
else if (PRESS_KET(VK_RIGHT) && ps->_Dir != LEFT)
{
ps->_Dir = RIGHT;
}
else if (PRESS_KET(VK_ESCAPE))
{
ps->_Status = END_NORMAL;
}
else if (PRESS_KET(VK_SPACE))
{
while (1)
{
Sleep(100);
if (PRESS_KET(VK_SPACE))
{
break;
}
}
}
else if (PRESS_KET(VK_F3))//加速
{
if (ps->_SleepTime >= 80)
{
ps->_SleepTime -= 30;
ps->_FoodWeight += 2;
}
}
else if (PRESS_KET(VK_F4))//减速
{
if (ps->_SleepTime <= 320)
{
ps->_SleepTime += 30;
ps->_FoodWeight -= 2;
}
}
//蛇的移动
Sleep(ps->_SleepTime);
SnakeMove(ps);
} while (ps->_Status == OK);
}
//3.游戏结束
void GameEnd(pSnake ps)
{
SetPos(20, 12);
switch (ps->_Status)
{
case END_NORMAL:
printf("退出游戏\n");
break;
case KILL_BY_SELF:
printf("撞自己了,游戏结束。\n");
break;
case KILL_BY_WALL:
printf("撞墙了,游戏结束。\n");
break;
}
SetPos(0, 27);
//释放蛇身节点
pSnakeNode cur = ps->_psnake;
while (cur)
{
pSnakeNode del = cur;
cur = cur->next;
free(del);
}
ps->_psnake = NULL;
}
#include"snake.h"
#include
#include
int main()
{
//设置程序适应本地环境
setlocale(LC_ALL, "");
srand(time(NULL));
Snake snake = { 0 };
//1.游戏开始 - 初始化游戏
GameStart(&snake);
//2.游戏运行
GameRun(&snake);
//3.游戏结束
GameEnd(&snake);
return 0;
}
c语言学习收关,撒花