Class structure in Lua/Corona

781 views Asked by At

So I'm working on a game in Lua and I'm trying to use metatables and classing but I think I'm importing my PHP knowledge and doing things slightly sideways.

-- Basic Monster
Monster = {}

function Monster:new(newX, newY)
    local newMonster = {x = newX, y = newY}
    setmetatable(newMonster, {__index = Monster})
    return newMonster
end

function Monster:moveTo(newX, newY)
    self.x = newX
    self.y = newY
end

function Monster:takeDamage()
    self.hitPoints = self.hitPoints - playerWeapon.damage
    if self.hitPoints <= 0 then
        self.die()
    end
end

function Monster:tap()
    self.takeDamage()
end

function Monster:die()
    self.removeSelf()
end

--Groblin
Groblin = {}
setmetatable(Groblin, {__index = Monster})

function Groblin:new(newX, newY)
    local groblin = display.newImage('assets/images/goblin.png');
    groblin.hitPoints = 4
    physics.addBody(groblin, 'static')
    gameGroup.insert(groblin)
    return groblin
end

I'm basically looking to be able to spawn several different types of monsters, and retain some base class functionality for them, but I'm uncertain in the above example how I tie in the base class to the Groblin class I made as I feel like I blew out that subclass altogether by what I'm doing inside of Groblin:new.

3

There are 3 answers

0
six8 On

If you want classes that you can subclass, try using middleclass. It's not very trivial to do subclasses in standard lua and middleclass has taken care of the boilerplate.

Also, make use of local -- use it anywhere it can be used.

0
robinkc On

Check out http://www.lua.org/pil/16.2.html for inheritance. Pay a little attention on the explanation of how the use of self in Account:new works out best while SpecialAccount extends Account.

I generally follow a little different approach than the mentioned in above link. In the above approach -

SpecialAccount = Account:new()
s = SpecialAccount:new{limit=1000.00}

You are calling Account:new() twice, and more problem arises when Acoount:new() does some validaiton on constructor parameters and throws exceptions. For ex: ensuring that the limit passed in non-nil.

So I follow this

SpecialAccount = setmetatable({__index = Account})

Does the trick of allowing superclass constructor to be used in subclasses.

PS: I prefer to treat new function as a constructor. It essentially does the same job.

0
dmattp On

A simple way to do this with your example would be:

function Groblin:new(newX, newY)
  local groblin = Monster:new( newX, newY )
  setmetatable(groblin, {__index = Groblin})
  groblin.image = display.newImage('assets/images/goblin.png');
  -- ...
  return groblin
end

Use the base class ":new()" method to construct the object and then add the unique fields for the subclass. This insures the base class is properly constructed. Re-setting the metatable to "Groblin" in the subclass constructor insures that any methods defined for the Groblin subclass are called if available, and where the Groblin table does not re-define a method the superclass method will be called.

It probably is better to use a library that provides a consistent approach for object creation and subclassing, but hopefully that gives you a better idea of how to do things manually.