NLua - 如何通过Lua向用户数据添加新功能?
NLua - How to add new functions to a userdata through Lua?
我正在尝试为我的 Player
class 定义一个在 C# 中定义的新函数。 Lua 在我的项目(游戏引擎)中的目的是为玩家等实体定义自定义行为。
但是,当我在 Lua 文件上执行 DoFile(fileName)
时,它崩溃并出现以下异常:
"field or property 'Idle' does not exist"
它专门指向这段代码的第一行:
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
因为这是播放器 class,所以任何新函数都需要在 Player
的上下文中声明。我做错了什么?
编辑
我已经解决了之前的错误,但我仍然没有得到我想要的结果。似乎不可能直接这样做;但是我已经阅读过,似乎在 Lua 5.2 中,有一种方法可以通过 debug.setuservalue
将 table 与用户数据对象相关联来做这样的事情。但是,当我尝试使用它时,table 仍然是空的(即使用户数据不是)。
这是我试过的 (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()
.
我怎样才能达到我想要的行为?
来自 Lua 参考手册:https://www.lua.org/manual/5.3/manual.html#2.1
Userdata values cannot be created or modified in Lua, only through the
C API. This guarantees the integrity of data owned by the host
program.
因此您不能向用户数据添加功能,而是通过将用户数据包装在您自己的 Lua table.
中来编写自己的扩展接口
简单示例,假设您可以通过调用 Player() 创建一个 Player userdata 值。
WrappedPlayer = {}
WrappedPlayer.usrdata = Player()
function WrappedPlayer:Idle()
self.usrdata:Turn()
self.usrdata.MoveType = MoveType.Idle
end
然后你可以直接调用WrappedPlayer:Idle()
当然你可以进一步改进这一点,在用你自己的 Player table 覆盖并添加一些 metatable 魔法后你可以简单地创建你自己的 Player 对象:
local myPlayer = Player()
myPlayer:Idle()
只需阅读一些 Lua OOP 教程即可了解具体方法。
不要忘记一个非常简单的解决方案:
function SetPlayerIdle(player)
player:Turn()
-- and so forth
end
我正在尝试为我的 Player
class 定义一个在 C# 中定义的新函数。 Lua 在我的项目(游戏引擎)中的目的是为玩家等实体定义自定义行为。
但是,当我在 Lua 文件上执行 DoFile(fileName)
时,它崩溃并出现以下异常:
"field or property 'Idle' does not exist"
它专门指向这段代码的第一行:
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
因为这是播放器 class,所以任何新函数都需要在 Player
的上下文中声明。我做错了什么?
编辑
我已经解决了之前的错误,但我仍然没有得到我想要的结果。似乎不可能直接这样做;但是我已经阅读过,似乎在 Lua 5.2 中,有一种方法可以通过 debug.setuservalue
将 table 与用户数据对象相关联来做这样的事情。但是,当我尝试使用它时,table 仍然是空的(即使用户数据不是)。
这是我试过的 (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()
.
我怎样才能达到我想要的行为?
来自 Lua 参考手册:https://www.lua.org/manual/5.3/manual.html#2.1
Userdata values cannot be created or modified in Lua, only through the C API. This guarantees the integrity of data owned by the host program.
因此您不能向用户数据添加功能,而是通过将用户数据包装在您自己的 Lua table.
中来编写自己的扩展接口简单示例,假设您可以通过调用 Player() 创建一个 Player userdata 值。
WrappedPlayer = {}
WrappedPlayer.usrdata = Player()
function WrappedPlayer:Idle()
self.usrdata:Turn()
self.usrdata.MoveType = MoveType.Idle
end
然后你可以直接调用WrappedPlayer:Idle()
当然你可以进一步改进这一点,在用你自己的 Player table 覆盖并添加一些 metatable 魔法后你可以简单地创建你自己的 Player 对象:
local myPlayer = Player()
myPlayer:Idle()
只需阅读一些 Lua OOP 教程即可了解具体方法。
不要忘记一个非常简单的解决方案:
function SetPlayerIdle(player)
player:Turn()
-- and so forth
end