1.5 将功能函数存放到外部文件
毫无疑问,迟早你都会需要用到一些独特而又复杂的物品。到现在为止,所有描述物品的常用方法基本上只是增加或减少某种状态值,但是,这只是一些很简单的事情,因为每个物品只需要通知游戏引擎它想要修改哪个状态值以及修改多少即可。但问题是迟早有一天你会对此感到厌倦,因为使用这样一种系统所能实现的功能是非常有限的。
那么,如果想创建一个可以实现某些具体功能的物品,这时又将会出现什么样的问题呢?如果并不只是一个简单的“告诉我改变什么状态以及应该变化多少”的问题时会怎么样?如果是一个要求所有级别低于某个值的ogres都逃离打斗现场的物体又会是怎么样呢?或者可能是一个用于存放宴会当中所有带有红色斗蓬的巫师的魔法值的物体,以及可以使某个玩家看见隐藏的藏宝箱的物体呢?这些都是一些很具体的任务。那么你究竟又该怎么做呢?是不是仅仅只是在物体列表中添加一些新的物体描述类型呢?
const HEAL = 0;
const MAGIC_RESTORE = 1;
const ARMOR_REPAIR = 2;
const TELEPORT = 3;
const MAKE_ALL_OGRES_BELOW_LEVEL_6_RUN_AWAY = 4;
const MAGIC_RESTORE_FOR_EVERY_WIZARD_WITH_RED_CLOAK = 5;
const MAKE_INVISIBLE_TREASURE_CHESTS_VISIBLE = 6;
我们不可能避免这些问题的出现。对于一个相对复杂的RPG游戏来说,你可能需要使用和现实生活中实际用到的同样数目的物体。细心的读者可能会再次发现硬编码是一种相当危险的方法。你刚刚把一些内容从游戏引擎的源代码中划分出来,开始为具体的物体编写代码,而对于现在这种方法,当每次在某些地方进行修改以后也都需要重新进行编译。这难道不是和我们最先试图解决的问题非常雷同吗?
而真正的问题在于无论物体结构中具有多少个部分,都不能很好地解决像前面提及的这些具体的物体问题。它们太复杂、太具体,而且甚至还会包含有条件逻辑(确定怪兽的等级、巫师斗蓬的颜色,以及藏宝箱是不是可以看得见)。真正实现这些物体的唯一方法就是对它们编程加以实现,就像你为游戏中其他任何一个部分编码一样。你非常有必要这样做,如果不使用if条件句你还会有什么其他方法可以用来检查条件吗?但是为了编写实际的代码,你就又需要采用过去那种方法——将每个物体都直接编码到游戏引擎当中?还有其他方法可以不使用一组数值而直接将代码存放到物体的描述当中吗?即便是有,最后你又如何执行它呢?
答案就是脚本。脚本可以使你真正在游戏引擎之外编写代码,然后再将这些代码加载到游戏引擎之中并对它加以执行。一般情况下,脚本是按照它们自己的语言格式进行编写的,这些语言和C/C++有些相似(不过通常要简单一些)。这两种类型的代码之间是分开的。脚本使用它们自己的编译器,而且它对游戏引擎没有任何影响,除非你希望它这么做。本质上,对于那些现在只是简单包含一些具有赋值的结构体的物体文件,你都可以写出一段代码来替代它们,而且这些代码几乎可以实现所有你所能提出的设想。想不想设计这样一个物体,只有当你星期四上午八点带着某种武器站在某个城堡的附近使用它时,这种武器才能发挥作用?没有问题,这种物体我们也可以实现!
脚本就像是运行在游戏内部的小程序,它们的工作原理和其他的普通程序一样。你可以使用一个普通的文本编辑器来编写它们,然后使用一个编译器来编译通过,最后提供一个编译后文件。但是,二者之间的区别在于这些可执行文件并不像其他普通的可执行文件一样可以在计算机的CPU上直接运行。同时,游戏和脚本之间是分离的。你可以像加载图形、声音,甚至早期的物体描述文件一样加载脚本。但是,你并不在显示器上将它们显示出来或者是通过喇叭把它们播放出来,取而代之的是,你可以执行它们。它们也可以和你的游戏进行通信,而游戏也可以作出应答。
想到你可能会解决如此众多的事情,你是不是觉得有点不知所措了呢?或许你有这种感觉,因为它可以解决的事情实在是太多了。设想一下你突然可以拥有这么多自由选择的权利——你可以单独编写运行在你游戏内部的小程序了!突然间,你的物体也可以像游戏中的其他部分一样进行编写,具有很多控制行为和实现细节,同时它们还是外部文件而且能够自包含。
总之,前面已经概括介绍了虚拟RPG游戏中的一些内容。现在你已基本了解了什么是脚本编程,下面将要学习的是如何更加清楚地了解脚本是如何运行的。






