论文导读:自定义插件的设计、实现及使用流程如图1所示。游戏引擎,基于CrystalSpace的自定义插件的设计与实现。
关键词:插件,软件复用,游戏引擎,CrystalSpace
1.Crystal Space及其核心SCF
1.1 Crystal Space
在介绍Crystal Space之前,首先介绍一下游戏引擎和3D游戏引擎,游戏引擎是用于控制所有游戏功能的主程序,从计算碰撞、物理系统和物体的相对位置,到接受玩家的输入,以及按照正确的音量输出声音等等,它是一个处理事务的系统,同时它也是一个控制模块,向所有的子系统发出命令[1]。而3D游戏引擎,除了包含游戏引擎的所有功能外,它还负责处理3D世界的数据结构(包括所有的光源、行动)以及从玩家或相机所在的视点渲染3D世界[1]。
Crystal Space(以下简称CS)是一个开源的3D游戏引擎。除了具备3D游戏引擎应有的功能外,其自身还包含许多独有的特点。首先,CS的框架是一个高度模块化的框架,该框架能更好的为用户提供服务,并且使用户使用CS更方便。其次,CS是一个由构件和库组成的包,虽然它很多的功能都偏向于3D游戏的处理,但是它同样也适用于其他方面的应用,这主要是得益于CS中的大部分插件和库的相互独立性,这使得用户在CS中,可以只使用自己需要的插件以及自定义插件,而不会与其他插件相关联或受到其他插件的影响。科技论文,游戏引擎。最后,CS广泛的支持各种不同类型的硬件和软件平台,具有很好的跨平台性[2]。科技论文,游戏引擎。
1.2 SCF
由于CS高度模块化的框架,而作为其框架核心的SCF(Share Class Facility,共享类工具)为用户设计与开发基于CS的自定义插件提供了便利。科技论文,游戏引擎。SCF与COM(Component Object Model,组件对象模型)[4]类似,但只是一个轻量级的COM。SCF与COM相比,其使用更加简单、方便,并且SCF屏蔽了COM中很多繁琐的部分,却同时具备COM的大部分优势[3]。
在Crystal Space中SCF用来管理引用计数、系统插件、自定义插件和抽象接口。在插件的开发中,SCF技术实现了类接口与类实现的分离,这一方面,使插件使用者只用关心类接口的功能及接口的使用方法,而不用关心它的具体实现;另一方面,它对类实现进行了很好的封装,不会将类实现的任何细节暴露给用户,并且插件开发者对类实现的修改不会对插件的使用造成影响[2]。另外,SCF还提供了插件对象注册器和插件管理器使CS能自动的完成对插件的管理,用户只需要书写少量的代码就能实现对插件的加载、使用及卸载。
2.设计和使用自定义插件
自定义插件的设计、实现及使用流程如图1所示,用户自定义插件设计时,必须在SCF中的对象注册器中注册,并由插件管理器统一管理,而应用程序对插件的调用及加载也必须通过对象注册器和插件管理器来完成。

图1 自定义插件的设计、实现及使用流程
2.1 设计自定义插件
用户自定义插件的实现包括定义插件的API,自定义插件的具体实现,自定义插件的编译及自定义插件的注册四个部分。
1)定义用户自定义插件的API
在Crystal Space中,使用SCF定义插件的API,其优势在于,将接口的定义和实现进行明确的分离。操作步骤包括:
Ⅰ. 定义插件API所在文件“Myapi.h”
Ⅱ. 定义API的版本号;
Ⅲ. 定义抽象类“iMyApi”,类名以“i”开头,用于标识该类是一个SCF接口。
Ⅳ. 定义两个纯虚函数DoSomthing( )和GetSomething()用于设置/获得一个3D坐标。下面是API定义的具体代码:
struct iMyApi : publicvirtual iBase
{ SCF_INTERFACE(iMyApi, 1, 0, 0);
virtual void DoSomething (intparam, const csVector3&) = 0;
virtual int GetSomething ()const = 0; };
2)创建自定义插件的实现(头文件)
下面是用户自定义插件具体实现的头文件“myplug.h”的定义。其操作步骤包括:
Ⅰ. 实现类必须同时继承iMyApi和iComponent接口,以保证能使用插件管理器来管理插件。
Ⅱ. 定义初始化函数,用于完成插件的初始化工作。具体代码如下:
class MyPlugin : publicscfImplementation2 <MyPlugin, iMyApi,iComponent>
{ …………
virtual boolInitialize (iObjectRegistry*);
virtual voidDoSomething (int param, const csVector3&);
virtual intGetSomething () const; };
3)创建自定义插件的实现(源文件)
下面为用户自定义插件具体实现的源文件“myplugin.cpp”,操作步骤包括:
Ⅰ. 使用CS_IMPLEMENT_PLUGIN通知CS本模块是一个插件
Ⅱ. 申明在CS中,允许使用SCF初始化MyPlugin类的对象,部分代码如下:
…………
CS_IMPLEMENT_PLUGIN
SCF_IMPLEMENT_FACTORY(MyPlugin)
…………
bool MyPlugin::Initialize(iObjectRegistry* r)
{ object_reg= r; returntrue; }
…………
4)在SCF中注册自定义插件
SCF能够自动且动态的查找已定义的插件,并通过查询每个插件的meta-Information来判定插件实现的细节。科技论文,游戏引擎。Meta-information是结构化的XML文档,其中包含插件在SCF中的注册信息,及本插件与其他插件的关联等。科技论文,游戏引擎。插件的meta-Information文档在插件被编译时,将被嵌入插件模块中,方便对插件的查询。科技论文,游戏引擎。下面是自定义插件的meta-Information的设置,内容包括:
Ⅰ. 设置插件的名称
Ⅱ. 指明实现该自定义插件的类的名称
Ⅲ. 对插件的一般描述及设置与该插件相关联的其他插件的名称。具体代码如下:
<plugin> <scf><classes> <class>
<name>crystalspace.mygame.myplugin</name>
<implementation>MyPlugin</implementation>
<description>My Special Game Plugin</description>
<requires> <class>crystalspace.graphics3d.</class></requires>
</class></classes></scf></plugin>
5)编译自定义插件
插件模块的编译取决开发时所使用的开发工具,这里使用Microsoft visual studio 2005进行编译。
2.2 自定义插件在应用程序中的使用
完成自定义插件的设计与实现后,就可以使用了,自定义插件的使用包括加载及调用。
1)在应用程序中加载自定义插件
在应用程序中加载自定义插件的操作步骤包括:
Ⅰ. 导入自定义插件API的头文件,插件使用者通过调用插件API实现对插件的使用。
Ⅱ. 调用对象注册器。对象注册器查询已注册的插件中是否包含应用程序指定的插件。
Ⅲ. 使用csQueryRegistry调用插件管理器,利用插件管理器实现自定义插件的加载(或从应用程序中卸载)。具体代码如下所示:
#include <myapi.h>
csRef<iPluginManager>plugin_mgr = csQueryRegistry <iPluginManager> (object_reg);
csRef<iMyApi> myapi =csLoadPlugin<iMyApi> (plugin_mgr,'crystalspace.mygame.myplugin');
if (myapi.IsValid()){ ... }
2)在应用程序中使用自定义插件
最后一个步骤就是使用用户自定义插件,在应用程序中,通过调用自定义插件的API来实现对插件提供的功能的使用,具体代码如下:
myapi->DoSomething (1,csVector3 (2, 3, 4));
printf ('%d ',myapi->GetSomething ());
3.小结
本文设计和实现了一个基于Crystal Space的自定义插件的实例,从中发现,基于Crystal Space技术设计和实现的自定义插件与使用其他方法实现的插件相比具有很多优势,首先,基于CS的插件具有很好的跨平台性;其次,插件的开发实现了类接口与类实现的分离,从而使插件的开发和插件的使用相分离;再次,用户自定义插件的功能不会受到任何限制,能最大限度发挥插件开发者的能动性;最后,SCF提供了插件对象注册器和插件管理器,使CS能自动完成对插件的管理,减轻了插件开发者和插件使用者的开发负担。因此,在实际开发过程中,开发者可以设计及使用符合自己需要的自定义插件,从而使基于CS的游戏开发或软件开发更加便利、快捷。
[参考文献]
[1][美]Andre Lamothe著. 李祥瑞,陈武译.3D编程大师技巧[M].人民邮电出版社,2005.
[2][美]Box.D 著. 潘爱民译.COM本质论[M]. 中国电力出版社,2001.
|