检测陈旧的C++;Lua中的引用 我是一个主要用C++编写的游戏,但是使用LUA来编写机器人的脚本。我们正在使用(Luna的一种变体)将碎片粘在一起 我现在正在苦苦思索我们的Lua脚本如何知道他们引用的对象已经被C++代码删除了。
以下是一些机器人示例代码(在Lua中): 请注意,仅当needTarget为true时才设置ship,否则将使用来自上一次迭代的值。自上次设置变量以来,很有可能(甚至,如果bot一直在做它的工作:-),飞船已经被杀死(并且它的对象被C++删除)。如果是这样,C++将在调用St:GeLoCo()时有一个合适的值,并且通常会崩溃。 因此,问题是如何最优雅地处理这种情况,并在程序员出错时限制损害 我有一些想法。首先,我们可以创建某种类型的Lua函数,C++代码在船或其他项死亡时调用它:检测陈旧的C++;Lua中的引用 我是一个主要用C++编写的游戏,但是使用LUA来编写机器人的脚本。我们正在使用(Luna的一种变体)将碎片粘在一起 我现在正在苦苦思索我们的Lua脚本如何知道他们引用的对象已经被C++代码删除了。,c++,lua,C++,Lua,以下是一些机器人示例代码(在Lua中): 请注意,仅当needTarget为true时才设置ship,否则将使用来自上一次迭代的值。自上次设置变量以来,很有可能(甚至,如果bot一直在做它的工作:-),飞船已经被杀死(并且它的对象被C++删除)。如果是这样,C++将在调用St:GeLoCo()时有一个合适的值,并且通常会崩溃。 因此,问题是如何最优雅地处理这种情况,并在程序员出错时限制损害 我有一些想法。首先,我们可以创建某种类型的Lua函数,C++代码在船或其他项死亡时调用它: functio
function itemDied(deaditem)
if deaditem == ship then
ship = nil
needTarget = true
end
end
其次,我们可以实现某种引用计数智能指针来“神奇地”解决问题。但我不知道从哪里开始
第三,我们可以有某种死区检测器(不确定如何工作),机器人可以这样调用:
if !isAlive(ship) then
needTarget = true
ship = nil -- superfluous, but here for clarity in this example
end
if needTarget then -- needTarget => global(?) boolean
ship = findClosest(findItems(ShipType)) -- ship => global lightUserData obj
end
<...as before...>
if!我住在船上
needTarget=true
ship=nil——多余,但为了在本例中更清楚起见
结束
如果需要目标,则--needTarget=>global(?)boolean
ship=findClosest(findItems(ShipType))--ship=>global lightUserData obj
结束
第四,我只能保留船的ID,而不是引用,并使用该ID在每个周期获取船对象,如下所示:
local ship = getShip(shipID) -- shipID => global ID
if ship == nil then
needTarget = true
end
if needTarget then -- needTarget => global(?) boolean
ship = findClosest(findItems(ShipType)) -- ship => global lightUserData obj
shipID = ship:getID()
end
<...as before...>
localship=getShip(shipID)——shipID=>global ID
如果ship==nil,则
needTarget=true
结束
如果需要目标,则--needTarget=>global(?)boolean
ship=findClosest(findItems(ShipType))--ship=>global lightUserData obj
shipID=ship:getID()
结束
我的理想情况也是明智地抛出错误。如果我在一艘死船上运行getLoc()方法,我希望触发错误处理代码,让机器人有机会恢复,或者至少让系统杀死机器人并记录问题,希望提醒我在编写机器人代码时要更加小心
这些是我的想法。我倾向于#1,但它感觉很笨重(可能会涉及很多来回,因为我们有很多像子弹这样的短生命周期对象要处理,其中大部分我们不会跟踪)。可能很容易忘记实现itemdired()函数#2很吸引人,因为我喜欢魔术,但不知道它是如何工作的#3非常容易理解,我可以将我的死区检测限制在几个游戏周期(最有可能是一艘飞船)内感兴趣的少数对象上
这一定是一个常见的问题。你觉得这些想法怎么样?还有更好的吗
谢谢
以下是我目前的最佳解决方案: 在C++中,我的船对象被称为Stand,其生命周期由C++控制。对于每个Ship,我创建一个称为LuaShip的代理对象,它包含一个指向Ship的指针,Ship包含一个指向LuaShip的指针。在飞船的析构函数中,我将LuaShip的飞船指针设置为NULL,我将其用作飞船已被摧毁的指示器 我的Lua代码只有一个对LuaShip的引用,因此(至少在理论上,由于这部分仍然不能正常工作),Lua将在相应的Ship对象消失后控制LuaShip的生命周期。所以Lua总是有一个有效的句柄,即使在Ship对象消失之后,我也可以为Ship方法编写代理方法来检查Ship是否为NULL 因此,现在我的任务是更好地理解Luna/Lunar如何管理指针的生命周期,并确保我的Luaship不会在其合作伙伴飞船被删除时被删除,如果仍然有一些Lua代码指向它们。这应该是非常可行的
事实上,这是行不通的(至少我是行不通的)。似乎起作用的是将飞船和卢阿希普物体稍微分离。现在,当Lua脚本请求一个LuaShip对象时,我创建一个新对象并将其交给Lua,然后让Lua在处理完它后删除它。LuaShip使用一个智能指针来引用飞船,因此当飞船死亡时,该指针被设置为NULL,LuaShip对象可以检测到该值 使用前,由Lua编码器检查船舶是否仍然有效。如果他们不这样做,我就可以抓住这个位置,抛出一条严厉的错误信息,而不是让整个游戏崩溃(就像以前发生的那样) 现在,Lua已经完全控制了Luasip的生命周期,C++可以删除船只而不会造成问题,而且一切都看起来很顺利。唯一的缺点是我可能会创建很多LuaShip对象,但实际上并没有那么糟糕
如果您对这个主题感兴趣,请参阅我发布的关于一个相关概念的邮件列表线程,该线程以完善上述内容的一些建议结尾:
我们公司采用了第四种解决方案,对我们来说效果很好。我推荐它。但是,为了完整性: 1号是实心的。让飞船的析构函数调用一些月球代码(或者标记它无论如何都应该被调用),然后如果你找不到它就抱怨。这样做意味着您必须非常小心,如果您想在单独的线程中运行游戏引擎和机器人,可能需要稍微修改Lua运行时
第2号并不像你想象的那么难:在C++侧写或借用一个引用计数指针,如果你的Lua /C++胶习惯于处理C++指针,它可能会不需要进一步的干预而工作,除非你正在生成。
local ship = getShip(shipID) -- shipID => global ID
if ship == nil then
needTarget = true
end
if needTarget then -- needTarget => global(?) boolean
ship = findClosest(findItems(ShipType)) -- ship => global lightUserData obj
shipID = ship:getID()
end
<...as before...>
if ship==nil or ship.destroyed then
ship = findClosest(findItems(ShipType))
end