Question

I'm using Lua and LuaBridge with Allegro 5. I decided to port all graphic objects to Lua, but I'm encountering some problems:

Character class that is called once

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 script whose functions are called from the main program:

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

So basically, the script initializes the character with appropriate coordinates and image, and draws it, but either the logic isn't being called (which it is in the logic loop) or something is wrong with the function to change the X coordinate.

Also, the task manager suggests that there is a memory leak of ~30 KB every cycle, which didn't happen when I had the image objects in C++.

Here's a snippet of the Bitmap struct that was exported to Lua via LuaBridge in case it was needed:

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 : One thing I have been able to figure out is that the memory leak is coming from CoreLogic; I commented out the call to it in C++, the memory leak was gone, but when I left the call intact, but commented out the content of CoreLogic, the leak persisted. Hmmm...

SECOND UPDATE : The memory leak has been narrowed down to something with the AI, which I had not posted:

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

And in the CoreLogic function, it would call Foo.AI:DoBehavior(), which did absolutely nothing and caused a memory leak.

Était-ce utile?

La solution 2

After some more elbow grease, I was able to resolve the issue; essentially, it went back to the Pattern table's constructor and how the AI object was initialized in Character. I had to change the constructor from:

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

And this:

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

Now the call to Foo.AI:DoBehavior() does as it's supposed to with no extra memory being used. This code was my first time trying to implement OOP in Lua, and this is probably the way I'm going to go about it from now on.

Autres conseils

Foo.AI:DoBehavior() reads a chunk from file, reserving memory for its content, its bytecode translated form, function environments and any possible temporary values created at this file's top level. It is expected to lose memory here and it is not a leak. Lua does not frees memory immediately. Actually it even doesn't return it to system at all.

Once in a while garbage collector runs and finds strings/tables/functions/whatever else that is no longer in use. Lua marks this memory as free in its own internal index and will use it next time it needs free memory, but the Lua memory consumption as seen from system will never shrink.

If you suspect that some part of you program might generate too much unnecessary garbage between automatic GC calls, you may want to force GC step either through collectgarbage or C API.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top