【问题标题】:Lua OOP function is not being called?Lua OOP 函数没有被调用?
【发布时间】:2012-11-11 18:46:40
【问题描述】:

我在 Allegro 5 中使用 Lua 和 LuaBridge。我决定将所有图形对象移植到 Lua,但遇到了一些问题:

被调用一次的字符类

Character = {sprite; AI}

function Character:new()
  o = o or {} -- works!
  setmetatable(o, self) -- works!
  self.__index = self  -- works!
  return o -- works!
end

function Character:LoadSprite(filename)
  self.sprite = self.sprite or Bitmap() -- works!
  self.sprite:LoadFile(filename) -- works!
  self.sprite.x = 0 -- works!
  self.sprite.y = 0 --works!
end

function Character:SetX(xx)
  self.sprite.x = xx -- maybe? cannot tell if it works or not.
end

function Character:AddBehavior(fname, cname)
    self.AI = self.AI or Pattern()
    self.AI:AddBehavior(fname, cname)
end

function Character:Draw()
  self.sprite:Draw() -- works!
 end

Foo = Character:new()

从主程序调用函数的Lua脚本:

function CoreInit() --called at initialization
  Foo:LoadSprite("Image.png") -- works!
end

function CoreLogic() --called during logic cycle
  Foo:SetX(50)  -- does NOT work!
end

function CoreDraw() --called during drawing/rendering cycle
  Foo:Draw()  --works perfectly!
end

所以基本上,脚本用适当的坐标和图像初始化角色,并绘制它,但要么没有调用逻辑(它在逻辑循环中),要么改变 X 的函数有问题坐标。

此外,任务管理器建议每个周期存在约 30 KB 的内存泄漏,当我在 C++ 中使用图像对象时没有发生这种情况。

这是通过 LuaBridge 导出到 Lua 的 Bitmap 结构的 sn-p,以备不时之需:

void Bitmap::Register(lua_State*lua) {
  luabridge::getGlobalNamespace(lua)
    .beginClass<Bitmap>("Bitmap")
    .addConstructor <void (*) (void)> ()
    .addStaticData("scale", &Bitmap::scale)
    .addFunction("LoadFile", &Bitmap::LoadFile)
    .addFunction("Draw", &Bitmap::Draw)
    .addData("x", &Bitmap::x)
    .addData("y", &Bitmap::y)
    .addData("w", &Bitmap::w)
    .addData("h", &Bitmap::h)
  .endClass();
}


void Bitmap::LoadFile(string file) {
  name = file;
  bitmap = al_load_bitmap(file.c_str());
  w = al_get_bitmap_width(bitmap);
  h = al_get_bitmap_height(bitmap);
}

void Bitmap::Draw() {
  if (scale > 1)
    al_draw_scaled_bitmap(bitmap, 0, 0, w, h, x * scale , y * scale, w * scale, h * scale, 0);
  else
    al_draw_bitmap(bitmap, x, y, 0);
}

Bitmap::Bitmap() :  velocity(1) {
   bitmap = NULL; 

}
Bitmap::~Bitmap() {
  name = "";
  if (!bitmap) 
    al_destroy_bitmap(bitmap);
}

UPDATE:我能够弄清楚的一件事是内存泄漏来自 CoreLogic;我在 C++ 中注释掉了对它的调用,内存泄漏消失了,但是当我保持调用不变,但注释掉 CoreLogic 的内容时,泄漏仍然存在。嗯……

第二次更新:内存泄漏已被缩小到与人工智能有关的问题,我没有发布:

Pattern = {complete; timer; command; Files; Commands; itr; num}

function Pattern:new()
  o = o or {}
  o.Files = {}
  o.Commands = {}
  o.complete = false
  o.timer = 0
  o.itr = 1
  o.num = 1
  setmetatable(o, self)
  self.__index = self
  return o
end

function Pattern:AddBehavior(filename, commandname)
  self.Files[self.num] = filename
  self.Commands[self.num] = commandname
  self.num = self.num + 1
end

function Pattern:DoBehavior()
  self.command = self.Commands[self.itr]
  dofile(self.Files[self.itr])
end

function Pattern:CheckBehavior()
  if self.complete == true then
    self.itr = self.itr + 1
self.timer = 0
self.complete = false
  end
  if itr >= num then
    self.itr   = 1
self.timer = 0
self.complete = false
  end
end

function Pattern:Initialize()
  self.itr = 1; self.timer = 0
  self.complete = false
  self.command = self.Commands[self.itr]
end

CoreLogic 函数中,它会调用 Foo.AI:DoBehavior(),这完全没有做任何事情并导致内存泄漏。

【问题讨论】:

  • 内存泄漏和循环是什么意思? Lua 是垃圾回收的。在您的情况下,每次调用Bitmap() 时,都会创建“对象”,而不必销毁。如果将对象放入闭包中,则引用将被保留,因此 C++ 绑定对象的释放将进一步延迟。
  • 基本上每次调用CoreLogic函数(当前FPS为30),程序的内存占用增加30KB。我设法解决了 AI 表的问题。我会立即发布该代码。

标签: c++ lua allegro5 metatable luabridge


【解决方案1】:

Foo.AI:DoBehavior() 从文件中读取一个块,为其内容、字节码转换形式、函数环境和在该文件顶层创建的任何可能的临时值保留内存。预计这里会丢失内存,这不是泄漏。 Lua 不会立即释放内存。实际上它甚至根本没有将其返回给系统。

垃圾收集器偶尔会运行并找到不再使用的字符串/表/函数/其他任何内容。 Lua 在自己的内部索引中将这块内存标记为空闲,下次需要空闲内存时会使用它,但从系统上看 Lua 内存消耗永远不会减少。

如果您怀疑程序的某些部分可能会在自动 GC 调用之间产生过多不必要的垃圾,您可能希望通过 collectgarbage 或 C API 强制执行 GC。

【讨论】:

    【解决方案2】:

    经过更多的努力,我能够解决问题;本质上,它回到了 Pattern 表的构造函数以及 AI 对象是如何在 Character 中初始化的。我不得不改变构造函数:

    Pattern = {complete; timer; command; Files; Commands; itr; num}
    
    function Pattern:new()
      o = o or {}
      o.Files = {}
      o.Commands = {}
      o.complete = false
      o.timer = 0
      o.itr = 1
      o.num = 1
      setmetatable(o, self)
      self.__index = self
      return o
    end
    

    到:

    Pattern = {}
    
    function Pattern:new()
      local o = {complete = false; timer = 0; command = ""; Files = {}; Commands = {}; itr = 1; num = 1}
      setmetatable(o, self)
      self.__index = self
      return o
    end
    

    还有这个:

    Character = {sprite; AI}
    
    function Character:new()
      o = o or {} 
      setmetatable(o, self) 
      self.__index = self 
      return o 
    end
    

    到:

    Character = {}
    
    function Character:new()
      local o = {sprite; AI = Pattern:new()}
      setmetatable(o, self)
      self.__index = self
      return o
    end
    

    现在对 Foo.AI:DoBehavior() 的调用按预期进行,没有使用额外的内存。这段代码是我第一次尝试在 Lua 中实现 OOP,这可能是我从现在开始的方式。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-10-17
      • 2017-04-18
      • 2011-12-30
      • 2018-02-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多