Функция Lua OOP не вызывается?

Я использую Lua и LuaBridge с Allegro 5. Я решил портировать все графические объекты на 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 КБ, чего не было, когда у меня были объекты изображения на C ++.

Вот фрагмент структуры Bitmap, которая была экспортирована в Lua через LuaBridge на случай, если это понадобится:

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);
}

ОБНОВЛЕНИЕ. Одна вещь, которую я смог выяснить, это то, что утечка памяти происходит из 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(), что абсолютно ничего не делало и вызывало утечку памяти.


person M89    schedule 23.11.2012    source источник
comment
Что вы подразумеваете под утечкой памяти и циклом? Lua собирает мусор. В вашем случае каждый раз, когда вы вызываете Bitmap(), объект будет создан и не обязательно уничтожен. Если вы поместите свой объект в закрытие, ссылка будет сохранена, поэтому освобождение объекта, связанного с C++, будет отложено.   -  person Dmitry Ledentsov    schedule 23.11.2012
comment
По сути, каждый раз, когда вызывалась функция CoreLogic (текущий FPS равен 30), объем памяти программы увеличивался на 30 КБ. Мне удалось прибить это к проблеме с таблицей AI. Я опубликую этот код на мгновение.   -  person M89    schedule 23.11.2012


Ответы (2)


Foo.AI:DoBehavior() читает фрагмент из файла, резервируя память для его содержимого, формы, преобразованной в байт-код, среды функций и любых возможных временных значений, созданных на верхнем уровне этого файла. Здесь ожидается потеря памяти, и это не утечка. Lua не сразу освобождает память. На самом деле он даже вообще не возвращает его в систему.

Время от времени сборщик мусора запускается и находит строки/таблицы/функции/что-то еще, что больше не используется. Lua помечает эту память как свободную в своем собственном внутреннем индексе и будет использовать ее в следующий раз, когда ему понадобится свободная память, но потребление памяти Lua, как видно из системы, никогда не уменьшится.

Если вы подозреваете, что какая-то часть вашей программы может генерировать слишком много ненужного мусора между автоматическими вызовами GC, вы можете принудительно выполнить шаг GC либо через collectgarbage, либо через C API.

person Oleg V. Volkov    schedule 23.11.2012

Еще немного поработав над локтями, я смог решить проблему; по сути, он вернулся к конструктору таблицы 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

to:

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

to:

Character = {}

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

Теперь вызов Foo.AI:DoBehavior() выполняется так, как предполагалось, без использования дополнительной памяти. Этот код был моей первой попыткой реализовать ООП на Lua, и, вероятно, теперь я буду делать это именно так.

person M89    schedule 24.11.2012