使用luabind,告别lua原生C API

我在上一篇日志中提到,由于多线程的原因,弃用python而改用lua。绝大部分的游戏都会在启动的时候从外部读取某种地图文件来加载场景,而不是直接把场景写死在C++中。在不考虑加密性和文件大小的情况下,我决定直接使用lua文件作为地图文件。这样,我可以先在C++中写好函数,封好接口,再由lua来调用这些函数,来完成场景的创建工作。

整个流程大概是这样的:

创建新的场景实例(C++) -> 场景实例调用特定的lua地图文件(C++调用lua) -> lua地图文件中调用C++中的函数完成场景创建(lua调用C++) -> 场景创建完成,开始游戏(C++)

抽象起来,大概有以下几点

  1. C++中有个叫做Scene的类,class Scene。
  2. 类Scene自己有许多写好的场景创建函数,例如createBuilding(),createVehicle()等等。为方便起见我们就用一个createObject()来代指这些函数吧。这些函数都是非静态成员函数,它们要被导出为lua可使用的函数,并被lua所调用。
  3. 类Scene中有个非静态成员方法叫做loadMap(),该方法负责调用lua脚本。
  4. lua脚本中在通过调用Scene类中的成员函数来创建场景。

如果要使用lua原生的API来完成这些事情,那简直是复杂得难以想象。不过幸好,我们有luabind,它的使用方式与boost::python十分相似,十分方便。这里是luabind的使用文档,十分详细。如果不想看英文的话,这里有中文版的。

为了演示luabind的用法,我首先在C++中写一个名为Scene的类

class Scene
{
public:
	Scene()
	{}

	void createObject(int obj);

	void printObjects();

	void loadMap(std::string fileName);

private:
	std::vector<int> mObjects;
};

在这里,我用一个int型的数组来模拟场景中的物体,createObject()方法就是向数组中添加数字,printObjects()会把数组中的东西一起过打印出来。

void Scene::createObject( int obj )
{
	mObjects.push_back(obj);
}

void Scene::printObjects()
{
	for (auto iter = mObjects.begin(); iter != mObjects.end(); ++iter)
		std::cout << (*iter) << std::endl;
}

在loadMap()方法中,我们打开一个lua虚拟机,将Scene中的成员函数导出,并调用lua脚本中的createScene()函数来创建场景。

void Scene::loadMap( std::string fileName )
{
	try
	{
		using namespace luabind;

		lua_State* L = lua_open();
		luaL_openlibs(L);
		luabind::open(L);
		// 导出类Scene
		module(L)
			[
				// 导出的类名字不必与C++中的一样
				// 方法也是这样
				// 但是为了看着方便
				// 我让它们名称都一样了
				class_<Scene>("Scene")	
				.def(luabind::constructor<>())	
				.def("createObject", &Scene::createObject)	
				.def("printObject", &Scene::printObjects)	
				// 注意到我并没有导出loadMap()方法
			];
		// 加载lua文件
		luaL_dofile(L, fileName.c_str());
		// 调用lua文件中的createScene方法
		luabind::call_function<void>(L, "createScene", this);
	}
	catch (luabind::error& e)
	{
		std::cout << e.what() << std::endl;
	}
}

在lua中的脚本是这样的:

-- map.lua
function createScene( scene )
	for i=0, 10 do
		scene:createObject(i)
	end
end

现在,我在main函数中调用Scene的loadMap函数:

void main()
{
	Scene s;
	s.loadMap("test.lua");
	s.printObjects();
	system("pause");
}

大功告成!

发表评论

电子邮件地址不会被公开。 必填项已用*标注