C语言贪吃蛇项目——第二部分绘制菜单和初始界面
1.了解Windows下的终端控制头文件及其API
1.1#include <windows.h>
我们需要了解该头文件其中的
1.HANDLE检索指定标准设备的句柄,知道怎么标准输出设备;
2.结构体COORD来设置光标;
3.了解SetConsoleCursorPosition()函数怎么使用
利用上面的内容自行设定gotoxy()函数
void gotoxy(int x,int y)
{
HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
COORD pos = {
.X = x,
.Y = y};
SetConsoleCursorPosition(handle,pos);
}
1.2.#include <conio.h>
我们需要了解该头文件其中的
1.kbhit()函数,作用是判断键盘是否有输入,有输入返回1,否则返回0
2.getch()函数,作用是获取输入的键值,不需要回车
3.getchar()函数,作用是获取输入的键值,需要回车
4.gotoxy()函数,在当代编译器中不可用,需要自行实现(在上面)
2.绘制游戏欢迎界面
2.1绘制边界
首先,我们先来绘制游戏中的边界,就是该墙体,它用于确定游戏的边界限制。主要是运用for()函数嵌套循环和putchar()函数输出。最后输出一个30*20的边界。
void draw_wall(void)
{
gotoxy(0,0);
for(int y=0;y<=HEIGHT;y++)
{
for(int x=0;x<=WIDTH;x++)
{
if(x==0||x==WIDTH)
putchar('*');
else if(y==0||y==HEIGHT)
putchar('*');
else
putchar(' ');
}
puts("");
}
}
2.2绘制开始游戏和结束游戏的图标
接下来,我们先来定义char start_game[]和char exit_game[]的数组,并找到在游戏中间的位置,在该位置设立开始游戏和结束游戏的光标,通过puts()函数输出开始游戏和结束游戏的图标。
这段代码定义了两字符串常量
start_game
和exit_game
分别存储了 "START GAME" 和 "EXIT GAME" 字符串。另外,还定义了两个 COORD 结构体类型的变量start_pos
和exit_pos
,分别表示开始游戏选项和退出游戏选项在屏幕中的位置。函数
draw_menu
负责在屏幕上绘制菜单,通过调用gotoxy
函数将光标移动到start_pos
和exit_pos
所表示的位置,然后使用puts
将对应的字符串输出到屏幕上,最终展示了开始游戏选项和退出游戏选项。
const char start_game[] = "START GAME";
const char exit_game[] = "EXIT GAME";
COORD start_pos = {
.X = WIDTH/2 - strlen(start_game)/2,
.Y = HEIGHT/2
};
COORD exit_pos = {
.X = WIDTH/2 - strlen(exit_game)/2,
.Y = HEIGHT/2 + 2
};
void draw_menu(void)
{
gotoxy(start_pos.X,start_pos.Y);
puts(start_game);
gotoxy(exit_pos.X,exit_pos.Y);
puts(exit_game);
}
2.3键盘控制函数
通过这样的方式,用户可以在控制台中看到可视化的提示,并通过按键来控制游戏的开始和结束。这是一个简单但有效的方法来增强用户体验。
具体功能如下:
- 函数名为get_key,返回一个整型值。
- 使用kbhit()函数来检测是否有按键按下,若有键按下则返回非零值。
- 使用getch()函数来获取用户按下的键值。
- 如果获取的键值为224,则表示键值为特殊键,需要再次调用getch()获取具体的特殊键值。
- 根据用户按下的键值,将其转换为相应的操作指令:
- 'w'/'W'/72:表示向上移动操作,返回1。
- 's'/'S'/80:表示向下移动操作,返回2。
- 'a'/'A'/75:表示向左移动操作,返回3。
- 'd'/'D'/77:表示向右移动操作,返回4。
- 13:表示中心操作,返回5。
int get_key(void)
{
int kb = kbhit();
if(kb == 0)
return 0;
int key = getch();
if(key == 224)
key = getch();
if(key == 'w' || key == 'W' || key == 72) //Turn up
return 1;
else if(key == 's' || key == 'S' || key == 80) //Turn down
return 2;
else if(key == 'a' || key == 'A' || key == 75) //Turn left
return 3;
else if(key == 'd' || key == 'D' || key == 77) //Turn right
return 4;
else if(key == 13) //Center
return 5;
}
2.4方向键选择菜单
本函数是为了能够上下选择进入游戏或者离开游戏
这段代码实现了一个简单的菜单选择功能。首先定义了一个函数select_menu(),该函数没有参数,返回一个整型值。在函数中,通过COORD结构体定义了菜单项的起始位置start_pos和退出位置exit_pos,然后通过gotoxy函数将光标移动到起始位置,并输出一个'O'表示当前选择的菜单项。
接着进入一个无限循环,不断监听键盘输入。在每次循环中,通过get_key()函数获取键盘输入的键值。如果输入的是上下方向键(Up或Down),则根据当前选择的菜单项位置进行切换:如果当前在起始位置,则切换到退出位置,反之亦然。
如果按下确认键(Center),则根据当前选择的菜单项位置判断返回值:如果在起始位置则返回1,表示选择了菜单项1;如果在退出位置则返回0,表示选择了退出。
总之,这段代码实现了一个简单的菜单选择功能,允许用户通过上下方向键选择菜单项,通过确认键确定选择的菜单项,并返回相应的整数值。
int select_menu(void)
{
COORD menu_int_pos = start_pos;
gotoxy(start_pos.X - 2,start_pos.Y);
putchar('O');
while (1)
{
int key = get_key();
if(key == Up || key == Down)
{
if(menu_int_pos.X == start_pos.X && menu_int_pos.Y == start_pos.Y)
{
gotoxy(start_pos.X - 2,start_pos.Y);
putchar(' ');
gotoxy(exit_pos.X-2,exit_pos.Y);
putchar('O');
menu_int_pos = exit_pos;
}
else if(menu_int_pos.X == exit_pos.X && menu_int_pos.Y == exit_pos.Y)
{
gotoxy(exit_pos.X - 2,exit_pos.Y);
putchar(' ');
gotoxy(start_pos.X-2,start_pos.Y);
putchar('O');
menu_int_pos = start_pos;
}
}
if(key == Center)
{
gotoxy(0,HEIGHT+2);
if(menu_int_pos.X == start_pos.X && menu_int_pos.Y == start_pos.Y)
{
return 1;
}
else if(menu_int_pos.X == exit_pos.X && menu_int_pos.Y == exit_pos.Y)
{
return 0;
}
}
}
}
int main()
{
draw_wall();
draw_menu();
int menu = select_menu();
if(menu == 0) return 0;
return 0;
}
3.绘制蛇身和随机刷新食物
3.1绘制游戏开始的最初蛇身
这段代码定义了一个静态的 COORD 类型的数组 snake,长度为 1024,用来存储蛇身体的各个部分的坐标。同时还定义了一个静态的整型变量 snake_body_length,表示蛇的身体长度。
函数
draw_int_snake
负责初始化蛇的初始位置和外观。首先将蛇头的坐标设置为屏幕中央位置,用字符 'O' 表示蛇头并输出到屏幕上。然后将蛇身体的第二个部分的坐标设置在蛇头的左边一个单位,用字符 '*' 表示蛇的身体并输出到屏幕上。最后,将蛇的身体长度设置为 1。这段代码的功能是在屏幕上绘制一个初始状态的蛇,包括蛇头和一个蛇身体部分,用字符 'O' 和 '*' 表示。同时记录蛇的身体长度为 1。
static COORD snake[1024];
static int snake_body_length = 0;
void draw_int_snake(void)
{
snake[0].X = WIDTH/2;
snake[0].Y = HEIGHT/2;
gotoxy(snake[0].X,snake[0].Y);
putchar('O');
snake[1].X = WIDTH/2-1;
snake[1].Y = HEIGHT/2;
gotoxy(snake[1].X,snake[1].Y);
putchar('*');
snake_body_length = 1;
}
3.2随机刷新食物
本模块的功能是在游戏窗口中随机生成食物的位置,供蛇来吃。
- 在程序中引入随机数函数的库,比如在C语言中使用stdlib.h库的rand()函数。
- 利用rand()函数生成随机数,限定在游戏窗口内食物出现的范围内,得到食物的随机位置。
void generate_food_pos(int * outx ,int * outy )
{
while(1)
{
int isuseful = 1;
int x = rand() % WIDTH;
int y = rand() % HEIGHT;
if(x == 0 || y == 0) continue;
for(int i=0; i<=snake_body_length; i++)
{
if(x == snake[i].X && y == snake[i].Y)
{
isuseful = 0;
break;
}
}
if(isuseful == 0) continue;
*outx = x;
*outy = y;
break;
}
}
3.3绘画食物
本模块的作用是将食物的位置信息传递给绘制食物的函数,将食物绘制在游戏窗口中。
void draw_int_food(void)
{
int x;
int y;
generate_food_pos(&x,&y);
gotoxy(x,y);
putchar('@');
}