用Boost.python构建游戏脚本系统的尝试

来源:互联网 发布:unity3d可以不用vs2015 编辑:程序博客网 时间:2024/06/05 10:38

最近在用HGE写自己的小游戏,UI接近完成之后要进一步完善却感到用C++去写剧情(比如人物对白)之类的琐碎事务不太理想,于是就想到了用脚本去扩展C++。

这是第一次用游戏引擎,也是第一次写比较复杂的游戏,之前没有过带脚本游戏的开发经验。网上找了一些资料,发现很少有这方面的介绍(也许是搜索的不够),失望之余只好自己再摸索一下,毕竟已知的是有许多游戏都是以脚本扩展游戏系统的。

先想到了AngelScript,下过来试了两把,一来觉得作为脚本来说使用起来有点繁琐,二来AngelScript并不像Lua和Python在国内这么流行,所以能找到的现成资料不多。放弃了AngelScript之后,又去对Lua和Python作了下简单的了解,Python我之前学过一点,本身也比Lua更易上手,所以选了Python。


Python提供了C接口,网上关于C和Python如何互调资料有很多,我也试着写了几个Demo,这个过程没有遇到什么阻力。由于我是打算以Python扩展C++,所以主要侧重关注C++如何调用Python的问题。我想了想一项游戏事件(比如对话),如何交给脚本去完成。最容易想到的有两个方式:


1、让Python获得用户输入、玩家数据和UI管理能力,然后C++调用py之后一切交给py去完成(py里来设置条件、次序等)。


2、C++设一个状态量,传给py,然后py根据状态量返回不同的字符串给C++,引擎再根据这个对画面进行更新。这种方式可以免去py对系统资源的直接管理,只处理逻辑。


后者问题也很明显,这样的话C++就得循环调用这个文件(期间修改状态量),让调用脚本变得啰嗦了,另外脚本也会写的很别扭。总而言之就是失去了作为脚本清晰易于管理的好处。

前者的问题是Python给的C接口只能通过动态链接库的方式访问C++变量,而且没办法传递C++对象。这样的话可行性就很低了,一来会破坏原有的封装,二来没办法进行正常通信。以此为前提,后者的解决方案是,把引擎实体的创建也扔给DLL,dll设置数据共享区段,然后py和c++都调用这个dll。只是这种方案仍非常不理想(比如python要调用需要把dll后缀改成pyd等等)。


后来找了资料发现boost.python实现了C++对象传递给python,而且不需要通过动态链接库。这样一来把第二个方案的问题解决了脚本就真正可以用起来了。

先是用了一个简化版的boost(一开始不知道是简化版的,第一次用boost),结果少了一堆文件,没过多久就怀疑是不是机器上的boost被简化过了,然后下了最新的,发现果然少了。但下来了之后还是不能直接用,看了会儿boost.python的官方攻略,说是要编译出python库,得用bjam。好吧又得多学个东西...官方的说法是可以不用bjam,但没说用其他工具怎么编,网上的资料乱的可以,于是还是用bjam为好。


然后我从sourceforge上下了bjam的源码包编译出exe来,再按照官方教程向下走。问题又来了,教程就那么三言两语,好像十分简单的样子,我每步都按要求做结果出了好多我看不懂的错误...太可怕了= =。 然后网上求解决,但没一个资料比较适用的(并且资料不多)。这样弄来弄去几个小时一下子就过去,一点进展也没有,环境变量、文件路径、编译器之类的全都检查了,快崩溃的时候发现boost文件包里本身就带了bjam源码包,于是我把原来的bjam删了,重新编译这个,再运行的时候就没问题了,重重舒口气。。。


sourceforge上的bjam貌似有路径问题,所以在本地表现不佳,而bjam又是个挺复杂的东西,一下子要我修正过来我还真没想法,而且也没那耐心。


用msvc9.0编译完boost.python之后,得到python的静态库和动态库各一个。然后我就可以开始写了,从这里复制了demo:

http://www.chineselinuxuniversity.net/articles/24491.shtml

然后运行的时候发现运行总有异常,异常的很莫名其妙。(顺便吐槽下,用了boost的东西编译起来果然够慢...素问模板元方式写的东西把部分运算提前到编译器,但没想到这么慢...)


就这样又浪费很多时间。


最后无计可施之下,决定换一个python版本试试(原本用的是3.2),事先知道python2和3变动比较大,并不兼容,但我以为boost的话,应该已经写好了对3的支持才对,但结果发现不行。然后重新编译boost.python,修改项目配置,再运行的时候终于成功了。


总结下来,发现基本都是些比较隐蔽的问题,网上又没什么资料,什么时候解决一半取决于运气,一半取决于耐心。


至此C++和Python算是牵手成功了。


此前也考虑过自己写一个脚本解释器,但想来想去觉得没能解决关键问题,又重复造轮子,而且要写个靠谱的解释器也挺费事儿的。接下来的重心就转到如何对脚本进行管理了。