1
votes

Trying to get my feet wet with LUA and Love2D, and I am having an issue with object instantiation / access in Lua.

Source with the bug can be found here: https://bitbucket.org/dannsee/love_scrollingshooter

I am In my main, I create an object, Enemies

enemies = Enemies:new()

and inside of the enemies object, i create an object to hold peristant values, which I am calling Timers.

timers = Timers:new()

So the enemies 'constructor' method looks (basically) like this

Enemies = {} -- so that Enemies will not be nil when new() is called
timers = {} -- so that timers will be accessible in the class scope

function Enemies:new(enemies)
  enemies = enemies or {}
  timers = Timers:new()
  setmetatable(enemies, self)
  self.__index = self
  return enemies
end

while the Timers being created are looking as such

Timers = {} -- so that Timers will not be nil when new() is called

function Timers:new(timers)
    timers = timers or {
      miniBombTimerMax = 0.2,
      miniBombTimer = minibombTimerMax
    } 
    setmetatable(timers, self)
    self.__index = self
    return timers
end

But when I try to refrence one of the timers ( from inside the enemies object) , I am getting a nil value exception.

timers.miniBombTimer -- Produces nil exception

It seems to me that this should both 1. be in scope, since it is an object created inside this class, and is instantiated locally as timers = {} before it is assigned a value, and 2. not nil becuase it is being given a value in the 'constructor'. But it seems there is more going on here that I am not grasping.

I am new to Lua, which may be obvious at this point, but from what I have read about variable scope it seems that this should be valid. I don't understand why the timers are not being created with values.

1
Read through lua-users.org/wiki/ObjectOrientationTutorial? You didn't show the part of the code with the problem, but presumably you're not using self?user94559
Your constructors are also not using self. I'm assuming you want timers to be a member of the Enemies class, but maybe not? Perhaps you can share a minimal example of how you intend to use this class.user94559

1 Answers

1
votes

Careful with your globals! In Lua, it's very easy to accidentally set a global variable when you don't mean to, and it looks like that's exactly what's happening.

function Enemies:new(enemies)
  enemies = enemies or {}
  timers = Timers:new()
  setmetatable(enemies, self)
  self.__index = self
  return enemies
end

On the third line here, since timers doesn't exist as a local variable here, this value ends up getting put into a global variable called timers instead. If you want to set a property of enemies, you need to mention enemies explicitly:

function Enemies:new(enemies)
  enemies = enemies or {}
  enemies.timers = Timers:new()
  setmetatable(enemies, self)
  self.__index = self
  return enemies
end

Now, you write:

But when I try to refrence one of the timers ( from inside the enemies object) , I am getting a nil value exception.

Lua doesn't really have any concept of being "inside an object" or "inside a class". In some languages, when you're writing code inside of a class, all of the class's members are in scope and you can refer to them "bare". Lua is not one of those languages; in Lua, if you want to refer to a "class member", you need to use the dot notation, explicitly stating which object you're accessing. (Or you can do the "advanced method", using _ENV.)

By the way...

timers = {} -- so that timers will be accessible in the class scope

From what I see in the question, this line doesn't do much; it just creates a global variable which is never used.

Also, this line in Enemies:new:

self.__index = self

This just sets Enemies.__index every time Enemies:new is called. This is fine, but you may as well just set it once:

function Enemies:new(enemies)
  enemies = enemies or {}
  enemies.timers = Timers:new()
  setmetatable(enemies, self)
  return enemies
end

Enemies.__index = Enemies