NLua - 如何通过Lua向用户数据添加新功能?

时间:2018-03-10 16:58:57

标签: c# lua luainterface nlua

我试图为我的Player类定义一个新函数,该函数是在C#中定义的。 Lua在我的项目(游戏引擎)中的目的是为玩家等实体定义自定义行为。

但是,当我在Lua文件上执行DoFile(fileName)时,它会因此异常而崩溃:

"字段或属性'闲置'不存在"

它特别指向此代码块的第一行:

function Player:Idle()
    self:Turn()
    self.StateType = StateType.Stand
    self.MoveType = MoveType.Idle
    self.Vel = Vector2.Zero
    if self.Anim.Number ~= 0 and (self.Anim.Number ~= 5 or self:GetAnimTime() == 0) then
        self:ChangeAnim(0)
    end
end

Player:Idle似乎有问题。但是,我也尝试将其写为Player.Idle,我也遇到了同样的问题。以下是我如何处理在C#中加载播放器的脚本:

        state["Player"] = this;

        // Load the states
        for (int j = 0; j < stateFiles.Length; j++)
        {
            string fp = filePath + @"\" + stateFiles[j];

            // If it's common, then if it doesn't exist, use the default.
            if (stateFiles[j] == "common.lua" && !File.Exists(fp))
                fp = Path.Combine("Content", "common.lua");

            // Now load it
            var f = state.DoFile(fp);
        }

我将Player全局设置为this,因为这是播放器类,因此需要在Player的上下文中声明任何新函数。我做错了什么?

修改

我已经解决了之前的错误,但我仍然没有得到我想要的结果。似乎不可能直接这样做;但是我已经阅读了,在Lua 5.2中,似乎可以通过debug.setuservalue将表与userdata对象相关联来做这样的事情。但是,当我尝试使用它时,表仍然是空的(即使用户数据不是)。

这就是我尝试过的(C#):

        state.NewTable("Player");
        state["tmp"] = this;
        state.DoString("a = debug.setuservalue(tmp, Player)");
        var t = state["Player"]; // Shows that Player is an empty table
        var a = state["a"]; // Shows that a was indeed set.

换句话说,我希望能够在脚本中使用self来引用用户数据以及自定义函数,例如Idle()Turn()

我如何实现我想要的行为?

1 个答案:

答案 0 :(得分:2)

来自Lua参考手册:https://www.lua.org/manual/5.3/manual.html#2.1

  

无法在Lua中创建或修改用户数据值,只能通过   C API。这保证了主机拥有的数据的完整性   程序

所以你不能向userdata添加函数,但你可以通过将userdata包装在你自己的Lua表中来编写自己的扩展接口。

简单示例,假设您可以通过调用Player()来创建Player userdata值。

WrappedPlayer = {}
WrappedPlayer.usrdata = Player()
function WrappedPlayer:Idle()
  self.usrdata:Turn()
  self.usrdata.MoveType = MoveType.Idle
end

然后您只需拨打WrappedPlayer:Idle()

即可

当然你可以进一步改进这一点,在用自己的表覆盖Player表并添加一些metatable魔法后,你可以简单地创建你自己的Player对象:

local myPlayer = Player()
myPlayer:Idle()

阅读一些Lua OOP教程,了解具体方法。

不要忘记一个非常简单的解决方案:

function SetPlayerIdle(player)
  player:Turn()
  -- and so forth
end