灵感
本来想做个迷宫小游戏来练习dfs,但是控制台游戏那些输入输出,光标移动之类的代码太过繁琐,于是我觉得自己写一个简易的控制台游戏库,封装一些常用的代码,这样就可以专心制作游戏逻辑而不是一些繁琐的打印之类的操作了。
地图
既然是游戏当然少不了地图,控制台游戏,一般都是二维的,所以需要用二维数组或者一维数组进行储存,外部只需要对这个地图进行操作就可以实现对整个游戏内容的操作了。至于地图用什么类型来储存,这里暂时用int,后期如果需要的话可以考虑用结构体,或者直接使用c++使用类模板。
第一件事情当然是要隐藏光标:
#include<windows.h>
void hideConsoleCursor() {
SetConsoleCursorInfo(GetStdHandle((DWORD)-11), &(CONSOLE_CURSOR_INFO) { 1 });
}
然后就是各种地图的操作函数:
#define Map(x) map[x] //为了不破坏封装性,定义一个操作map的宏
int *map, WIDTH, HEIGHT; //用于存储地图以及其长宽
void initMap(int* m, const int W, const int H); //初始化地图
void drawMap(); //画地图
由于一维数组操作起来相对简单,这里直接采用一维数组进行存储,那么就一定会涉及到坐标之间的转换。其中二维地图和一维地图坐标关系为:
map[coord] = map[x][y]
其中coord = y + x * W,此时可以定义一个coord函数用于根据x,y返回coord,同时反推过程也需要一个函数:
int coord(int x, int y) {
return y + x * WIDTH;
}
void getMapCoord(int coord, int* x, int* y) {
*y = coord % WIDTH;
*x = (coord - *y) / WIDTH;
}
接下来就是地图的显示了,这里用不同色块表示不同的物体,而map储存的正是颜色值这里先随便定义了几个颜色常量:
#define RED 199
#define BLACK 0
#define YELLOW 238
如何显示呢,很容易想到可以,将地图遍历一遍,但是问题又来了,如何刷新地图?
地图的刷新
关于地图的刷新,一般有三种方法:
1.清屏法
2.光标移动法
3.控制台双缓存法
首先来看看清屏法,也就是最容易想到的“cls大法”:
#include"ConsoleGame.h"
int main() {
int map[100], W = 10, H = 10, i;
initMap(map, W, H);
hideConsoleCursor();
for (i = 0; i < 100; ++i) { //这里就随便赋值
Map(i) = i;
}
while (1){
drawMap();
changeTextColor(BLACK);
system("cls");
}
}
但是往往会出现以下结果:
这种方法简单是简单,就是有点费眼,所以我们需要用到后面两种方法。
双缓存法这里就不介绍了,有兴趣可以自行了解,这里主要用到光标移动法。
原理也很简单,不用清屏,只需要在输出的时候将光标移动到(0, 0)位置也就是最开始的位置即可。
void moveCusorTo(int x, int y) {
SetConsoleCursorPosition(GetStdHandle((DWORD)-11), (COORD) { x, y });
}
while (1){
moveCusorTo(0, 0);
drawMap();
}
果然没有出现刚刚的情况了。
这样地图的打印和刷新的问题都解决了。
最终代码如下:
void changeTextColor(int c) {
setColor(c); //color为内部的全局变量,用来记录当前字体颜色
SetConsoleTextAttribute(GetStdHandle((DWORD)-11), getColor());
}
void initMap(int* m, const int W, const int H) {
int i, j;
WIDTH = W;
HEIGHT = H;
map = m;
for (i = 0; i < HEIGHT; ++i) {
for (j = 0; j < WIDTH; ++j) {
map[coord(i, j)] = 0;
}
}
}
void drawMap() {
moveCusorTo(0, 0);
int i, j;
for (i = 0; i < HEIGHT; ++i, _cputs("\n")) {
for (j = 0; j < WIDTH; ++j) {
changeTextColor(map[coord(i, j)]);
_cputs(" ");
}
}
}
控制
这里需要有一个函数来检测按键并返回:
#include<conio.h>
int getKeyState() {
return _kbhit() ? _getch() : 0; //_kbhit():检测是否按键;_getch():返回当前按键值
}
代码
这样就完成了一些基本的操作,最终的代码放到了GitHub上:ConsoleGame
后面我会试着用它制作一些简单的控制台小游戏(现在已经用它完成了贪吃蛇)。
后续若做其他小游戏的时候有其他需求,我会进一步完善。