说明按键对应的功能,很简单就不赘述了
void guide()
{
printf("******************\n");
printf("** 游戏操作指南 **\n");
printf("**--------------**\n");
printf("** w->上移 **\n");
printf("** s->下移 **\n");
printf("** a->左移 **\n");
printf("** d->右移 **\n");
printf("** q->返回 **\n");
printf("** ESC->暂停 **\n");
printf("** 空格->射击 **\n");
printf("******************\n\n\n");
}
void gamebody()
{
Initgame(); //初始化游戏函数
while(1)
{
show(); //展示函数
updateWithInput(); //与用户输入有关的更新,
updateWithoutInput();//与用户输入无关的更新,如子弹、敌机的移动
}
}
以这个游戏框架为基础,我们建立起我们的设计逻辑
在正式介绍gamebody函数之前,我们先看看定义在头文件的全局变量以及他们的作用
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <windows.h>
#include <time.h>
#include <conio.h> //需要用到的函数头文件
#define height 25 //宏定义游戏边界的高度
#define width 50 //宏定义游戏边界的宽度
#define enemy_max 5 //宏定义敌人的最多数量
enum Option //枚举增加代码可读性
{
EXIT,
PLAY,
GUIDE,
};
enum Condition //表示游戏幕布上的情况
{
backspace, //空
enemy, //敌人
bullet, //子弹
};
int canvas[height][width]; //游戏幕布存储对应位置上的Condition信息
int score; //记录游戏分数
int x, y; //飞机头部的xy坐标
int Std_Speed; //敌机标准下落速度,与之后的加速下落有关
int Std_Time; //敌机生成的标准速度,与之后的加速生成有关
int HP; //玩家生命值
int enemy_num; //此时的敌机数量
void gamebody();
③清屏函数的实现
我们的游戏画面完全是靠printf函数打印出来的,因此清屏函数是必不可少的。
直接使用system("cls")函数会造成屏幕画面闪烁严重,因此我们可以自行封装一个gotoxy函数,函数的功能是将光标移到原点,从原点开始重新绘制,相当于实现清屏的效果。虽然还是会闪烁,但防屏闪效果有了显著提升。
首先给大家介绍几个平时不常用的函数:
①SetConsoleCursorPosition
头文件:#include<windows.h>
参数①:hConssoleOutput → 指向屏幕缓冲区的句柄
参数②:dwCursorPosition → 指定包含新光标位置的COORD结构
函数功能:设置光标在指定的控制台屏幕缓冲区中的位置
COORD结构体:
②GetStdHandle函数
void gotoxy(int x, int y)
{
HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
COORD pos;
pos.X = x;
pos.Y = y;
SetConsoleCursorPosition(handle, pos);
}
④光标隐藏函数
光标一直闪烁会影响我们的游戏体验,所以我们封装一个HideCursor函数。光标的信息定义在CONSOLE_CURSOR_INFO结构体中,其具体定义如下:
dwSize结构体成员指定这光标的大小,bVisible决定光标是否可见,因此我们只需对将它设置为false即可。实际的修改还需要借助SetConsoleCursorInfo函数
参数①:标准输出设备的句柄,我们可以用上面提到的GetStdHandle函数获取
参数②:CONSOLE CURSOR INFO结构体类型的指针,该结构体包含屏幕缓冲区新规范
有了上面的知识,我们可以写下这样的代码:
?
void HideCursor()
{
CONSOLE_CURSOR_INFO cursor_info = {1, 0};//将“是否可见”设置为false
SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &cursor_info);
}
⑤Initgame函数
因为我们使用了全局变量,并且要求设计出来的游戏能能够重复的play,所以我们在每次游戏开始时都要对全局变量进行必要的 初始化
void Initgame()
{
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++) //将幕布首先初始化为空格
canvas[i][j] = backspace;
}
HP = 3;
score = 0;
x = width / 2; //初始化飞机位置
y = height / 2;
enemy_num = 0;
Std_Speed = 60; //初始化“标准下落速度”
Std_Time = 60; //初始化“标准生成速度”
}
遍历canvas数组,根据canvas数组中的内容决定打印什么:
void show()
{
gotoxy(0, 0); //在打印之前先清屏
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
if (i == y && j == x) //打印飞机
printf("*");
else if (i == y + 1 && j == x - 2)
{
printf("*****");
j += 4;
}
else if (i == y + 2 && j == x - 1)
{
printf("* *");
j += 2;
}
else if (canvas[i][j] == bullet) // 打印子弹
printf("|");
else if (canvas[i][j] == enemy)
printf("@");
else
printf(" ");
}
printf("|\n"); //打印游戏右边框
}
for (int j = 0; j < width; j++) //打印游戏底边框
printf("-");
printf("\n[得分:>%d\n", score); //打印游戏分数和血量
printf("[生命值:>%d\n", HP);
}