三、游戏操作指南——guide函数
说明按键对应的功能,很简单就不赘述了
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");}
四、游戏的主体gamebody()
①简化通用的游戏框架
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};//将“是否可见”设置为falseSetConsoleCursorInfo(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; //初始化“标准生成速度”
}
⑥show函数的实现
遍历canvas数组,根据canvas数组中的内容决定打印什么:
- backspace → 空格
- enemy → 敌机(@)
- bullet → 子弹(|)
-
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("@");elseprintf(" ");}printf("|\n"); //打印游戏右边框}for (int j = 0; j < width; j++) //打印游戏底边框printf("-");printf("\n[得分:>%d\n", score); //打印游戏分数和血量printf("[生命值:>%d\n", HP); }