控制台RPG开发教程6: 筹建地图工作组4(输入与输出结合)


本次教程的内容:

  1. 坐标的概念
  2. 位置记录的概念
  3. 擦除移动法实现英雄移动


我们的地图工作组输入部门已经走在前面了,它们可以正确地接收键盘输入。
但是只有输出部门进行配合,才能实现英雄的移动。
这就必须首先引入坐标的概念。
控制台的坐标,是以左上角为(0,0)点,即X坐标和Y坐标都为0。
向右,x递增,向下,y递增。
所以,对我们看屏幕的用户来说,向上的含义是y减小,向下的含义是y增加。
向左的含义是x减小,向右的含义是y增加。
为了能够在屏幕的任意位置显示字符,我们引入一个新的函数:光标定位函数。

# include <iostream>
# include <conio.h>
# include <windows.h> 
using namespace std;

void gotoxy(unsigned char x,unsigned char y){
    COORD cor;
    HANDLE hout;
    cor.X = x;
    cor.Y = y;
    hout = GetStdHandle(STD_OUTPUT_HANDLE);
    SetConsoleCursorPosition(hout, cor);
}

int main(){
    gotoxy(12, 3);
    cout << "♀";
}

在主函数中。
通过调用这个函数gotoxy(12,3),我们就可以把光标直接设定在第3行,第12列。

注意看最上面,我们又增加了一个地址本:windows.h
在 main函数之上,增加了一个新的函数。
我们无须深究这个函数的含义,只是简单地把它放到代码中,并知道怎样使用它就可以了。
这也编程的基本精神之一,封装复杂性,无须关注底层的实现细节。

但有一点我们必须弄清,当我们在大楼工作室中的精灵读到gotoxy(12,3)指令的时候意味着什么?
首先gotoxy是一个名字,随后精灵会注意到名字后面的括号,于是它知道这不是一个房间地址,而是电话指令。
下一个动作,精灵当然是去查号码本。
但在查看任何的号码本之前,精灵会最先查一下代码附带的函数定义,也是直接的号码定义。
精灵立刻发现这条指令已经有过定义了。
于是精灵立即在工作间里创造了一个虚拟的工作间,以及自己的一个分身,就如同孙悟空把根毫毛变出另外一个孙悟空一样。把这个函数的代码交给它。
然后拿起电话,不是打给任何一个外面世界的工作组,而是打个这个精灵的分身
初始精灵:你好,请帮我处理一下gotoxy操作,参数是12和3。
分身精灵:好的,gotoxy就是我的全部指令任务,我现在开始处理,请稍等。
初始精灵:没问题,我在线等。
分身精灵:你好,我处理完毕了,没有其他汇报的内容了。(没有返回值)
初始精力:谢谢。(挂掉电话)

初始精灵挂掉电话的一瞬间,虚拟工作室和分身精灵都消失了,还原为初始精灵的一根毫毛。
感觉这样的操作太复杂了?对于精灵来说,这个操作花费的额外精力并不多。
精灵用这种方法,让自己的工作显得不那么辛苦和复杂。毕竟只有一个人在干活,太枯燥了。

下一条指令,cout<<"♀"; 就简单多了,光标在哪里,输出就在哪里。

现在让我们把输入部分和输出部门的工作结合起来,以控制英雄的移动。
为了能够控制英雄的移动,我们必须做两件事。
1 首先我们的地图工作组必须记录英雄的当前位置;
2 在接到键盘信息后,在英雄当前的位置上输出空格,以擦掉英雄的显示
3 改变英雄的当前位置,并在新的位置输出英雄的标记看下面的代码:

# include <iostream>
# include <conio.h>
# include <windows.h>
using namespace std;

void gotoxy(unsigned char x,unsigned char y){
    COORD cor;
    HANDLE hout;
    cor.X = x;
    cor.Y = y;
    hout = GetStdHandle(STD_OUTPUT_HANDLE);
    SetConsoleCursorPosition(hout, cor);
}

int main(){
    cout << "■■■■■■■■■■■■" << endl; 
    cout << "♀      ■■          ■ " << endl; 
    cout << "■  ■    ■■  ■■  ■" << endl; 
    cout << "■  ■■        ■      " << endl; 
    cout << "■■■■■■■■■■■■" << endl; 
    int x, y;
    x= 0;
    y= 1;
    int a;
    while(1){
        a= getch();
        if (a==72) {
           // 向上 
           gotoxy(x,y);
           cout << "  ";
           y= y- 1;
           gotoxy(x,y);
           cout << "♀";
        }
        if (a==80) {
           // 向下 
           gotoxy(x,y);
           cout << "  ";
           y= y+ 1;
           gotoxy(x,y);
           cout << "♀";
        }
        if (a==75) {
           // 向左 
           gotoxy(x,y);
           cout << "  ";
           x= x- 2;
           gotoxy(x,y);
           cout << "♀";
        }
        if (a==77) {
           // 向右 
           gotoxy(x,y);
           cout << "  ";
           x= x+ 2;
           gotoxy(x,y);
           cout << "♀";
        }
    }
}

程序有点长,但大部分代码我们都已经熟悉了,比如上面的gotoxy函数在前一个程序中我们已经熟悉了,main函数开头的显示地图,在前面的课程出现过。while循环中检测键盘,并判断方向的代码,我们前面的课程也讲过,只是以前我们只能显示一下想做的事情,现在我们可以做真正的处理了。
我们首先注意x,y 两个房间(变量),它们中记录着英雄当前的位置。一开始在(0,1)位。
注意代码中开头加了双斜线的语句:
 // 向上 
它们不是指令,它们称作注释
如果你还记得,在教程3中,也出现过这种操作。所有的注释精灵不会看到,所以也不会执行。
它们存在的意义是为了方便写程序的人。上次,我们是为了让语句暂时不被运行。这次是为了说明代码的含义。
我们用注释标明方向,否则只看数字,不容易很快反应出来代码的含义。
我们注意到4个方向键触发的代码都具有相似的格式:
前面两行都是一样的。
首先是gotoxy(x,y);
即跳转光标到英雄的当前位置。
然后是cout<< "  ";
注意这里是输出两个空格,因为一个中文字符占位宽度等于两个英文字符。
输出空格,就覆盖了英雄的符号,起到了隐藏的作用。
接下来的一行是不同的,根据不同的按键,相应改变英雄的坐标。
向上是y=y-1;
向下是y=y+1;
向左是x=x-2; 
为什么x是+2呢?同样的道理,因为一个中文字符高度于英文字符一样,但占位宽度等于两个英文字符。
向右是x=x+2; 
后面两行又是一样的。
这里的gotoxy(x,y);
是跳转到了英雄新的位置。
然后是cout << "♀";
在新的位置重新输出英雄的符号。

现在,运行起来程序,用键盘控制,让英雄沿着路走,完全可以让英雄安全地走出迷宫。
但如果你不小心走到了墙上,你会发现英雄会穿墙而过,并且走过之处把墙也消除掉了。
如果你走出了上边或左边的屏幕,你更会发现英雄的移动规律完全乱了。

在后面的课程里,我们会逐步解决这些问题。


课程小结:

本课重点讲解了精灵分身来执行函数的过程。以及通过键盘控制英雄坐标改变的方法。


 

发布了24 篇原创文章 · 获赞 0 · 访问量 4576

猜你喜欢

转载自blog.csdn.net/xiaorang/article/details/104791046