简体   繁体   English

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

[英]NLua - How to add new functions to a userdata through Lua?

I'm trying to define a new function for my Player class which was defined in C#. 我正在尝试为在C#中定义的Player类定义一个新函数。 The purpose of Lua in my project (a game engine) is to define custom behavior for entities such as players. Lua在我的项目(游戏引擎)中的目的是为玩家等实体定义自定义行为。

However, when I do DoFile(fileName) on the Lua file, it crashes with this exception: 但是,当我在Lua文件上执行DoFile(fileName)时,它因以下异常而崩溃:

"field or property 'Idle' does not exist" “字段或属性“空闲”不存在”

It specifically points to the first line in this chunk of code: 它专门指向此代码块的第一行:

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

It seems to have a problem with writing Player:Idle . 编写Player:Idle似乎有问题。 However, I also tried writing it as Player.Idle and I get the same issue. 但是,我也尝试将其编写为Player.Idle并遇到相同的问题。 Here's how I handle loading the scripts for the player in C#: 这是我在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);
        }

I'm setting the Player global to this because this is the player class, so any new functions need to be declared in the context of Player . 我将Player全局设置this因为这是Player类,因此任何新函数都需要在Player的上下文中声明。 What am I doing wrong? 我究竟做错了什么?


Edit 编辑

I've solved the error from earlier, but I'm still not getting the results I want. 我已经解决了较早的错误,但是仍然没有得到想要的结果。 It seems it's not possible to directly do this; 似乎不可能直接执行此操作; however I've read up and it seems in Lua 5.2, there's a way to do something like this by associating a table with the userdata object through debug.setuservalue . 但是我已经阅读了,在Lua 5.2中,似乎有一种方法可以通过debug.setuservalue将表与userdata对象相关联。 However, when I tried using it, the table was still empty (even though the userdata was not). 但是,当我尝试使用它时,表仍然是空的(即使userdata不是)。

This is what I tried (C#): 这是我尝试过的(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.

In other words, I want to be able to use self in the script to be able to refer to the userdata, as well as custom functions, such as Idle() and Turn() . 换句话说,我希望能够在脚本中使用self来引用用户数据以及自定义函数,例如Idle()Turn()

How can I achieve the behavior I desire? 我如何实现自己想要的行为?

From the Lua reference manual: https://www.lua.org/manual/5.3/manual.html#2.1 从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. 只能通过C API无法在Lua中创建或修改Userdata值。 This guarantees the integrity of data owned by the host program. 这保证了主机程序拥有的数据的完整性。

So you cannot add functions to userdata but you write your own, extended interface by wrapping the userdata in your own Lua table. 因此,您无法向用户数据添加功能,而是通过将用户数据包装在自己的Lua表中来编写自己的扩展接口。

Simple example, assuming you can create a Player userdata value by calling Player(). 一个简单的示例,假设您可以通过调用Player()创建Player用户数据值。

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

Then you can simply call WrappedPlayer:Idle() 然后,您可以简单地调用WrappedPlayer:Idle()

Of course you can further improve this and after overwriting the Player table with your own and adding some metatable magic you could simply create your very own Player object: 当然,您可以进一步改善这一点,并用自己的Player表覆盖并添加一些可继承的魔术之后,您可以简单地创建自己的Player对象:

local myPlayer = Player()
myPlayer:Idle()

Just read some Lua OOP tutorials to find out how. 只需阅读一些Lua OOP教程以了解操作方法。

Not to forget a very simple solution: 不要忘记一个非常简单的解决方案:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM