如何使用setmetatable围绕C#对象创建Lua包装器类

时间:2019-04-20 19:38:29

标签: c# lua moonsharp

我正在为当前正在使用C#开发的游戏创建一些UI,并希望将所有内容公开给Lua,以便我的美术师可以进行细微调整而无需执行任何代码。我正在使用MoonSharp将Lua脚本集成到我的项目中。

这是我的UIElement包装类当前拥有的内容:

UIElement = {};
UIElement.__index = UIElement;

setmetatable( UIElement, {
 __index = function( self, key )
  local codeElement = rawget( self, "__codeElement" );
  local field = codeElement and codeElement[key];
  if type( field ) == "function" then
   return function( obj, ... )
    if obj == self then
     return field( codeElement, ... );
    else
     return field( obj, ... )
    end
   end;
  else
   return field;
  end
 end,
 __call = function( cls, ... )
  return cls.new( ... );
 end,
} );

function UIElement.new()
 local self = setmetatable( {}, UIElement );
 self.__codeElement = BLU_UIElement.__new();
 return self;
end

BLU_UIElement 是我的C#类,该类通过MoonSharp API向Lua公开。直接与对象一起使用时,它可以正常工作,并具有SetPos,SetColor等功能。

UIElement 旨在成为Lua中包装和扩展C#对象的“类”。

当我在脚本的其他地方实例化UIElement并尝试调用一个函数(例如SetPos)时,它确实正确地进入了__index函数。但是,rawget调用始终返回nil。它似乎也不特定于BLU_UIElement。我已经尝试了一些非常简单的方法,例如在构造函数中添加字符串ID值,并尝试在__index函数中将其原始获取,但是它也会返回nil。

我假设我只是在做一些错误的事情,在类或对象本身上设置了元稳定器,但是我不确定问题出在哪里。我一直在这里寻找:http://lua-users.org/wiki/ObjectOrientationTutorial,以获取关于我做错了什么的想法,但我没有发现任何事情。

我很高兴对此有任何指导,我已经花了几天的时间来研究它,但仍未弄清楚,而在线搜索通常只会显示与我已经在做的类似的代码。

2 个答案:

答案 0 :(得分:0)

我必须承认,我不确定是否要通过在LUA(而不是C#)中编写包装类,然后公开该类型来实现的目标,但是我注意到了这一点:

对我来说 NativeClass .__ new()从未在MoonSharp中解决,就像您尝试在

self.__codeElement = BLU_UIElement.__new();

由于这个原因,我为本机类创建了自定义构造函数,并将它们作为委托传递给全局命名空间(尽管必须注册其类型)。看起来很像您通常会构造一个对象。只是没有新的关键字:

在C#中

public NativeClass{

   public static NativeClass construct()
   {
      return new NativeClass();
   }

}

将静态方法作为委托传递给脚本:

script["NativeClass"] = (Func<NativeClass>)NativeClass.construct;

然后您可以在MoonSharp中创建一个新的实例,

x = NativeClass()

编辑:所以没有读到您尝试使用字符串执行此操作。也许您应该考虑不在LUA中编写包装类,而在C#中编写,还是有理由禁止这样做?

答案 1 :(得分:0)

我有一个朋友,对Lua的元数据的了解远比对我的了解多。如果答案对其他人有帮助,请在此处发布答案。

问题是我试图将UIElement表既用作“类”表又用作“对象”元表。在__index函数中调用rawget时,它试图在UIElement表中查找内容,而不是在UIElement.new()中创建的self表中查找内容。将这两个拆分成不同的表(一个用于类,一个用于对象元表)可以解决问题。

这是我更新后的有效代码:

UIElement = {};
setmetatable( UIElement, {
    __call = function( cls, ... )
        return cls.new( ... );
    end,
} );

UIElement.objectMetaTable = {
    __index = function( self, key )
        local objectValue = rawget(self, key);
        if objectValue ~= nil then
            return objectValue;
        end

        local classValue = UIElement[key];
        if classValue ~= nil then
            return classValue;
        end

        local codeElement = rawget(self, "__codeElement");
        if codeElement then
            return codeElement[key];
        end
    end,
};

function UIElement.new()
    local newInstance = setmetatable( { id = "blah" }, UIElement.objectMetaTable );
    newInstance.__codeElement = BLU_UIElement.__new();
    return newInstance;
end