Я использую 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 (), который абсолютно ничего не сделал и вызвал утечку памяти.
Foo.AI:DoBehavior()
читает фрагмент из файла, резервируя память для его содержимого, его переведенной формы байт-кода, функциональных сред и любых возможных временных значений, созданных на верхнем уровне этого файла. Здесь ожидается потеря памяти, и это не утечка. Lua не освобождает память сразу. На самом деле он даже не возвращает его системе.
Время от времени сборщик мусора запускается и находит строки / таблицы / функции / все остальное, что больше не используется. Lua помечает эту память как свободную в своем собственном внутреннем индексе и будет использовать ее в следующий раз, когда ей потребуется свободная память, но потребление памяти Lua, как видно из системы, никогда не сократится.
Если вы подозреваете, что какая-то часть вашей программы может генерировать слишком много ненужного мусора между автоматическими вызовами GC, вы можете принудительно выполнить шаг GC либо через collectgarbage
или C API.
После еще немного локтевой смазки, я смог решить проблему; по сути, он вернулся к Шаблон конструктор таблицы и как искусственный интеллект объект был инициализирован в символ. Мне пришлось изменить конструктор из:
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, и, возможно, именно так я и собираюсь сейчас делать.