概要
本文是我想玩所以跟着UP主编写,发现真的好多自己不知道的东西,很多都是自己没用过的类型
其中使用较多的都是windows的API模型。
整体架构流程
简单赘述:
- 老规矩,搭建hello word 基础框架。
- 确定游戏窗口大小并进行绘制。
- 对蛇和果实进行绘画。
- 对蛇进行移动控制。
- 进行碰撞处理并刷新果实。
- 添加得分板。
技术名词解释
一些没用过的函数,类型
- COORD是Windows API中的坐标结构体类型,表示屏幕坐标。
- ULONGLONG适合存储文件
- boolean数据类型 boolean变量存储为8位数值形式,但只能是false或true 且默认值为false.
- STD_OUTPUT_HANDLE\t标准输出句柄
- GetStdHandle是一个Windows API函数
技术细节
- 处理光标:首先先读取命令行现在的 CONSOLE_CURSOR_INFO 结构体信息,需要用到API函数GetConsoleCursorInfo。GetConsoleCursorInfo 需要用到输出句柄,可以通过API函数GetStdHandle获得。\n\n然后改变结构体信息,再使用API函数SetConsoleCursorInfo
- 隐藏光标:\n\nHANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);\nCONSOLE_CURSOR_INFO cci;\nGetConsoleCursorInfo(hOut,&cci);\ncci.bVisible=false;\nSetConsoleCursorInfo(hOut,&cci);
- 碰撞检测是降低精度,提高果实碰撞率
- 移动控制需要进行反向处理,防止掉头
- 果实需要刷新
小结
附源码如下:
#include<stdio.h>
#include<Windows.h>
#include<conio.h>
#include<time.h>
//窗口
#define WIDTH 90
#define HEIGHT 25
#define TICK 80
#define APPLE_DELAY 10000
//枚举数据
typedef enum
{
UP,
DOWN,
LEFT,
RIGHT
}Direction;
//初始
int size;
COORD* body;
Direction direction;
COORD apple , tail;
char key;
HANDLE hdl;
ULONGLONG start, apple_event , tick_event , now;
boolean is_death;
int dx, dy;
//游戏窗口
void draw_wall()
{
for (int i = 0; i <= HEIGHT; i++)
{
for (int j = 0; j <= WIDTH; j++)
{
if (i == HEIGHT || i == 0)putchar('=');
else if (j == WIDTH || j == 0)putchar('=');
else putchar(' ');
}
puts("");
}
}
//得分
void draw_score()
{
COORD pos = { WIDTH + 5, HEIGHT / 2 };
SetConsoleCursorPosition(hdl, pos);
printf("SCORE:");
}
//果实
void init_apple()
{
int flag = 1;
while (flag)
{
flag = 0;
apple.X = rand() % WIDTH;
apple.Y = rand() % HEIGHT;
for (int i = 0; i < size; i++)
{
if (body[i].X == apple.X && body[i].Y == apple.Y)
{
flag = 1;
}
}
}
}
//蛇的初始化
void init_snake()
{
is_death = FALSE;
size = 2;
body[0].X = WIDTH / 2;
body[0].Y = HEIGHT / 2;
body[1].X = WIDTH / 2 -1;
body[1].Y = HEIGHT / 2;
direction = RIGHT;
key = 'D';
dx = 1;
dy = 0;
}
// 清除
void remove_obj(COORD obj)
{
SetConsoleCursorPosition(hdl, obj);
putchar(' ');
}
//苹果刷新
void update_screen()
{
remove_obj(tail);
for (int i = 0; i < size; i++)
{
SetConsoleCursorPosition(hdl, body[i]);
if (i == 0)putchar('@');
else putchar('*');
}
SetConsoleCursorPosition(hdl, apple);
putchar('#');
COORD pos = { WIDTH + 11, HEIGHT / 2 };
SetConsoleCursorPosition(hdl, pos);
printf("%d", size);
}
// 按键检测
void get_direction()
{
while (_kbhit())
{
key = _getch();
switch (key)
{
case 'W':case 'w':case 72:
if (direction != DOWN)
{
direction = UP;
dx = 0;
dy = -1;
}
break;
case 'A':case 'a':case 75:
if (direction != RIGHT)
{
direction = LEFT;
dx = -1;
dy = 0;
}
break;
case 'S':case 's':case 80:
if (direction != UP)
{
direction = DOWN;
dx = 0;
dy = 1;
}
break;
case 'D':case 'd':case 77:
if (direction != LEFT)
{
direction = RIGHT;
dx = 1;
dy = 0;
}
break;
}
}
}
//碰撞检测
void tick()
{
//判断是否撞墙
if (body[0].X < 0 || body[0].X >= WIDTH || body[0].Y < 0 || body[0].Y >= HEIGHT)
{
is_death = TRUE;
return;
}
//画苹果
update_screen();
//按键检测
get_direction();
//判断是否撞到自己
for (int i = 1; i < size; i++)
{
if (body[i].X == body[0].X && body[i].Y == body[0].Y)
{
is_death = TRUE;
return;
}
}
//判断是否吃到苹果
if (apple.X == body[0].X && apple.Y == body[0].Y)
{
init_apple();
size++;
}
//更改蛇的位置
tail = body[size - 1];
for (int i = size - 1; i > 0; i--)
{
body[i] = body[i - 1];
}
body[0].X += dx;
body[0].Y += dy;
}
//主函数
int main()
{
//初始化:光标
hdl = GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_CURSOR_INFO cci = { 1 , 0 };
SetConsoleCursorInfo(hdl, &cci);
SetConsoleTitle("SNAKE!!!");
srand((unsigned)time(NULL)); //随机数种子
//蛇的初始化,在堆区生成蛇的数组
body = (COORD*)malloc(sizeof(COORD) * HEIGHT * WIDTH); //开辟空间
//绘制游戏界面
draw_wall();
draw_score();
//绘制苹果,蛇
init_snake();
init_apple();
//对时间进行初始化
start = GetTickCount64();
tick_event = start + TICK;
apple_event = start + APPLE_DELAY;
//
while (1)
{
now = GetTickCount64();
if (now > tick_event)
{
tick();
if (is_death == TRUE)
break;
tick_event += TICK;
}
if (now > apple_event)
{
remove_obj(apple);
init_apple();
apple_event += APPLE_DELAY;
}
}
free(body); //释放空间
return 0;
}
搞定。