第六章 数据类型:object 第一节 序言 这是 Lpc 入门的最后一节,到现在,如果前面几章都读过了,你应该 能写出一些简单的 object,比如 room 。而且能给 room 写一些简单的 特写,通过添加一些函数。 第二节 作为数据类型的 object 2.1 数据类型 object 在这一章中,你将了解更复杂一些的数据类型:object。一个 object 类型的变量是指向一个装入内存的真正存在的 object 。象别的数据类 型一样,你用 object 后面跟一个变量名来声明: object oTest; 它有些特殊,它几乎没有什么操作符可以作用 object 这种数据类型。 其实,也是的,让一个 room / npc 那是什么东西?而且一般的 efun, 比如 write(), say() 也是不能操作 object 的,但是你会了解到,对于 object 这中数据类型,有一些很重要的 efun。 2.2 efun: this_object() 这个 efun 返回一个 object,当前被执行的函数所在的那个 object。 也就是说,在一个文件中,this_object() 提交的 object 是这样的: 如果这个文件写的 object 如果自己被复制装入内存单独存在,那么就 是这个 object,如果这个文件被继承了,那么就是继承的文件进行上一 个过程,看它是不是单独存在,也就是没有再继承的文件了。可能有些 难也理解,让我们看这个例子,比如你写了一个 object 叫 name.c,它 被 player.c 继承了,那么 this_object() 实际返回的是 player.c 那个 object,而不是 name.c 。我们再来看一个使用 this_object() 的实例: 你想让一个 npc 走到一朵花旁边闻一下,但是条件是那个 npc 能自 由运动,比如:没有晕倒,没有在战斗。 你可以这么做: void eventSmellFlower() { if( this_object()->can_act() ) { write( this_object()->query( "name" ) + "走到花的边上闻了闻。\n" ); this_object()->add( "kee", 5 ); } } can_act() 在 npc.c 里面是没有定义的,而且可能它继承的任何 object 中也没有定义。那么,如果写成这样: if ( can_act() ),driver 没有 在当前文件和继承的所有文件里面找到 can_act(),那就会有个编译错 误的,但是 this_object()->can_act() 就不会出现这样的错误,就算是 can_act() 根本不存在,那么结果是返回 0 ,就是 if 测试的表达式的 结果是假的。这样有人会问:那这个 efun 有必要存在吗?driver 在 编译是会自动搜索它继承的所有 object,不是自然有 this_object 了 吗? 确实,但是有时,这个 object (暂时叫做 A )会被别的 object (B) 继承的,别的 object (B)可能会有这个函数,而且有时候 B 可能会重载 A 和 A 继承的函数,而你不想让那些重载的函数失去作用,那么就采用 this_object()-> 的形式。 2.3 调用别的 Object 里面的函数 这就是我们引入 object 这种数据类型的最大好处了。它能让我们调 用别的 Object 里面的函数。在上面的例子中,我们可以知道当前的 Object 能不动。下面的例子,你可以增加一个 player 身上的钱。 调用别的 object 里面的函数,可以用下面两种方法: object->function(parameters) call_other(object, "function", parameters); example: this_player()->add_money( "silver", 5 ); call_other( this_player(), "add_money", "silver", 5 ); 在某些时候( 很不精确的说法 ),mud 是一个由玩家命令触发的函数 调用的链式反应。当一个 player 触发了一个函数调用链,那么这个 player 就是 eufn this_player() 返回的那个 object。就是说,因为 this_player() 依赖那个触发事件序列那个 player,那么你应该小心的使用 this_player() 这个 efun,如果你把 this_player() 放在一些函数,这些函数别调用通 常可能是 driver 来调用的,或者不一定是 player 来触发的,那么使用 this_player() 最好不要出现在那些函数里面。比如 create(), setup()。 2.4 lfun: init() 在任何时候,一个“活的”的 object,接近一个 object (进入一个新 房间,或者另一个 object 进入同一个 room ),init() 将自动被调用。 利用这个,你可以写一些自动触发的效果,比如,你进入一家客栈,小 二和你打招呼,看看这样一个例子: void init() { ::init(); if ( this_object()->can_act() ) { this_object()->eventGreet( this_player() ); } } eventGreet() 可以是下面那样: void eventGreet( object ob ) { if ( !ob || environment( ob ) != environment( this_object() ) ) { return ; } else { write( "小二说道:这位客官,您想要点什么?\n" ); } } efun environment() 返回一个 object 所在的环境,比如一个 player 所 在的 room,一把剑所在的 player 等等。 2.5 在你的 room 里面放入一个 object 看下面的一个例子,你可以在一个 player 所在的房间放入一条蛇: void test() { object env, snake; env = environment( this_player() ); if ( objectp( env ) ) { snake = clone_object( "/clone/monster/snake" ); if ( objectp( snake ) ) { snake->move( env ); } } } 例子中用到了一个 efun objectp ,这个 efun 判断传入的参数是不是一 个真实的 object,如果是就返回真,否则就是假。efun clone_object() 则试着把一个文件调入内存,变成一个 object。最后一个函数 move, 这个显然不是一个 efun,但是总的来说,一般会调用 efun move_object 把一个 object 放到另一个 object 的内部。 小结 ( 也是 lpc 入门的小结 ) 在本章,我们了解作为数据类型的 object。同时也了解一些 efun: this_object(), this_player() environment() clone_object() objectp() 的使用。还有 init() 这个特别的函数的使用。 到了现在,你应该有足够的知识编写一些漂亮的东西了。当然,我强 调过一点,你必须了解你为之开发的 mud,了解它的 mudlib,它的风格, 多多阅读 mud 带的文档和说明。当然只是了解 lpc 入门 介绍的东西, 对 lpc 的了解是很基础的,如果你想更进一步,最好的方法是,多读 程序,多写程序,积累经验。Lpc 只是 C 的很小的一个子集,有一点点 的特殊的东西,是很容易掌握的。 maht( trill ) 11/12/97 3:53PM trill@XO (tm)