我是Bitfighter的首席开发者,我们正在使用Lua和C++的混合,使用Lunar(Luna的一种变体,可在此处获得)将它们绑定在一起.
我知道这个环境对面向对象和继承没有很好的支持,但是我想找到一些方法来至少部分地解决这些限制.
这就是我所拥有的:
C++类结构
GameItem |---- Rock |---- Stone |---- RockyStone Robot
机器人实现了一个调用的方法getFiringSolution(GameItem项目),着眼于位置和速度项目,并返回该机器人将需要火打角项目.
-- This is in Lua angle = robot:getFiringSolution(rock) if(angle != nil) then robot:fire(angle) end
所以我的问题是,我想通过岩石,石头,或rockyStones到getFiringSolution方法,我不知道该怎么做.
这仅适用于Rocks:
// C++ code S32 Robot::getFiringSolution(lua_State *L) { Rock *target = Lunar::check(L, 1); return returnFloat(L, getFireAngle(target)); // returnFloat() is my func }
理想情况下,我想要做的是这样的事情:
// This is C++, doesn't work S32 Robot::getFiringSolution(lua_State *L) { GameItem *target = Lunar::check(L, 1); return returnFloat(L, getFireAngle(target)); }
这个潜在的解决方案不起作用,因为Lunar的检查函数希望堆栈上的对象具有与GameItem定义的className相匹配的className.(对于您使用Lunar注册的每个对象类型,您提供一个字符串形式的名称,Lunar使用该名称来确保对象的类型正确.)
我会满足于这样的东西,我必须检查每个可能的子类:
// Also C++, also doesn't work S32 Robot::getFiringSolution(lua_State *L) { GameItem *target = Lunar::check(L, 1); if(!target) target = Lunar ::check(L, 1); if(!target) target = Lunar ::check(L, 1); return returnFloat(L, getFireAngle(target)); }
这个解决方案的问题是,如果堆栈上的项目类型不正确,check函数会生成错误,并且我相信,从堆栈中删除了感兴趣的对象,所以我只有一次尝试抓取它.
我想我需要从堆栈中获取指向Rock/Stone/RockyStone对象的指针,找出它是什么类型,然后在使用之前将其转换为正确的东西.
进行类型检查的Lunar的关键位是:
// from Lunar.h // get userdata from Lua stack and return pointer to T object static T *check(lua_State *L, int narg) { userdataType *ud = static_cast(luaL_checkudata(L, narg, T::className)); if(!ud) luaL_typerror(L, narg, T::className); return ud->pT; // pointer to T object }
如果我这么称呼它:
GameItem *target = Lunar::check(L, 1);
然后luaL_checkudata()检查堆栈上的项目是否为Rock.如果是这样,一切都是桃子的,它会返回一个指向我的Rock对象的指针,该对象会被传递回getFiringSolution()方法.如果堆栈中存在非Rock项,则转换为null,并且调用luaL_typerror(),这会将应用程序发送到lala land(错误处理打印诊断并以极端偏见终止机器人).
关于如何推进这个的任何想法?
非常感谢!!
最好的解决方案我想出来......丑陋,但有效
根据以下建议,我想出了这个:
templateT *checkItem(lua_State *L) { luaL_getmetatable(L, T::className); if(lua_rawequal(L, -1, -2)) // Lua object on stack is of class { lua_pop(L, 2); // Remove both metatables return Lunar ::check(L, 1); // Return our object } else // Object on stack is something else { lua_pop(L, 1); // Remove 's metatable, leave the other in place // for further comparison return NULL; } }
然后,以后......
S32 Robot::getFiringSolution(lua_State *L) { GameItem *target; lua_getmetatable(L, 1); // Get metatable for first item on the stack target = checkItem(L); if(!target) target = checkItem (L); if(!target) target = checkItem (L); if(!target) // Ultimately failed to figure out what this object is. { lua_pop(L, 1); // Clean up luaL_typerror(L, 1, "GameItem"); // Raise an error return returnNil(L); // Return nil, but I don't think this // statement will ever get run } return returnFloat(L, getFireAngle(target)); }
我可以对此进行进一步的优化......我真的想弄清楚如何将其折叠成一个循环,因为实际上,我将有三个以上的类来处理,这个过程是有点累赘.
上述解决方案略有改进
C++:
GameItem *LuaObject::getItem(lua_State *L, S32 index, U32 type) { switch(type) { case RockType: return Lunar::check(L, index); case StoneType: return Lunar ::check(L, index); case RockyStoneType: return Lunar ::check(L, index); default: displayError(); } }
然后,以后......
S32 Robot::getFiringSolution(lua_State *L) { S32 type = getInteger(L, 1); // My fn to pop int from stack GameItem *target = getItem(L, 2, type); return returnFloat(L, getFireAngle(target)); // My fn to push float to stack }
Lua辅助函数,作为单独的文件包含在内,以避免用户需要手动将其添加到代码中:
function getFiringSolution( item ) type = item:getClassID() -- Returns an integer id unique to each class if( type == nil ) then return nil end return bot:getFiringSolution( type, item ) end
用户从Lua这样打电话:
angle = getFiringSolution( item )
Norman Ramse.. 5
我想你正试图在错误的地方调度方法.(这个问题是所有这些"自动化"方式使Lua与C或C++交互的困难的症状:对于它们中的每一个,幕后都会有一些魔力,并且如何使其工作并不总是显而易见的.我不明白为什么更多的人不只是使用Lua的C API.)
我看了一下Lunar网页,它看起来好像你需要methods
在类型上创建一个表T
然后调用该Luna
方法.网上有一个简单的例子.如果我正确地阅读了代码,那么问题中的粘合代码实际上并不是推荐使用Lunar的方法.(我还假设你可以完全像C++调用那样实现这些方法.)
这一切都非常狡猾,因为Lunar的文档很薄.一个明智的选择是自己完成所有工作,并将每个C++类型与包含其方法的Lua表相关联.然后你有Lua __index
metamethod咨询那张桌子,鲍勃是你的叔叔.Lunar正在做一些接近这些的东西,但它充分利用了C++模板,其他goo我不确定如何使它工作.
模板的东西非常聪明.您可能希望花时间深入了解其工作原理,或者重新考虑是否以及如何使用它.
简介:为每个类创建一个显式方法表,并使用Lunar Register
方法注册每个类.或者自己滚动.
我想你正试图在错误的地方调度方法.(这个问题是所有这些"自动化"方式使Lua与C或C++交互的困难的症状:对于它们中的每一个,幕后都会有一些魔力,并且如何使其工作并不总是显而易见的.我不明白为什么更多的人不只是使用Lua的C API.)
我看了一下Lunar网页,它看起来好像你需要methods
在类型上创建一个表T
然后调用该Luna
方法.网上有一个简单的例子.如果我正确地阅读了代码,那么问题中的粘合代码实际上并不是推荐使用Lunar的方法.(我还假设你可以完全像C++调用那样实现这些方法.)
这一切都非常狡猾,因为Lunar的文档很薄.一个明智的选择是自己完成所有工作,并将每个C++类型与包含其方法的Lua表相关联.然后你有Lua __index
metamethod咨询那张桌子,鲍勃是你的叔叔.Lunar正在做一些接近这些的东西,但它充分利用了C++模板,其他goo我不确定如何使它工作.
模板的东西非常聪明.您可能希望花时间深入了解其工作原理,或者重新考虑是否以及如何使用它.
简介:为每个类创建一个显式方法表,并使用Lunar Register
方法注册每个类.或者自己滚动.