Reputation: 5717
Is it possible to use inheritance with Codea? While I am fairly new to Lua, but from some quick Googling, it looks like the methods to do inheritance and polymorphism are a bit "involved". Is there any technique that can be used safely with Codea's Lua-hosting engine?
Here is a simple runnable test I am trying to get working. My superclass:
Superklass = class()
function Superklass:init(x,y)
self.x = x
self.y = y
end
function Superklass:debug()
print(string.format("(%d, %d)", self.x, self.y))
end
A subclass:
Ship = class()
function Ship:init(x, y)
-- you can accept and set parameters here
print('ship:init() called')
self = Superklass(x,y) -- ???
print('attempting to call self:debug()')
self:debug() -- works! prints
print('ok!')
end
function Ship:draw()
print('ship:draw() called')
print('attempting to call self:debug()')
self:debug()
print('ok')
end
And the program entrypoint:
-- initial setup
function setup()
ship = Ship(HEIGHT/2, WIDTH/2)
end
-- called once every frame
function draw()
ship:draw()
end
Here's the output from running that:
ship:init() called
attempting to call self:debug()
(384, 375)
ok!
ship:draw() called
attempting to call self:debug()
error: [string "Ship = class()..."]:16: attempt to call method 'debug' (a nil value)
Pausing playback
I am sure this is incredibly naive -- but I would love a tip in the direction of something that might work in the context of Codea.
Upvotes: 0
Views: 556
Reputation: 5717
Just to give a working solution (class inheritance in Codea) and point out a few of the pitfalls. First, I should note that Codea loads classes in tab order, so the tabs for the superclasses have to be prior to the tabs for the subclasses. I would recommend looking through this thread on the Codea forums. It discusses the technique below, and also gives some insight into the underlying mechanics.
First, we define a superclass AbstractSprite whose constructor takes an (x,y) coordinate. It provides a method debug to echo this coordinate to the console.
AbstractSprite = class()
function AbstractSprite:init(x,y)
self.position = vec2(x,y)
print("new AbstractSprite created")
end
function AbstractSprite:debug()
print(string.format("(%d,%d)", self.position.x, self.position.y))
end
Next, we define an implementing class Ship, which implements a custom debug that calls super, demonstrating how to move up the class hierarchy.
Ship = class(AbstractSprite)
function Ship:init()
AbstractSprite.init(self)
print("new Ship created")
end
function Ship:debug()
print("I am a ship, calling my superclasses' methods!")
AbstractSprite.debug(self)
end
The program entrypoint. We create both a Ship and a 'raw' AbstractSprite, calling debug on each:
function setup()
ship = Ship()
ship:debug()
asteroid = AbstractSprite(150, 200)
asteroid:debug()
end
And console output:
new AbstractSprite created
new Ship created
I am a ship, calling my superclasses' methods!
(0,0)
new AbstractSprite created
(150,200)
Upvotes: 3
Reputation: 52641
Disclaimer: I'm the author of middleclass, an OO-lib for Lua.
The closure-based you pointed out on the first example is a nice intellectual exercise, but it has little practical value. In Lua, object orientation is better achieved with tables (as the example pointed out by your second example suggests) - it gives equivalent functionality at a faster rate. The only differences are syntactical.
There are lots of libraries that use the standard table-based approach to do OO in Lua. You may find a list here:
http://lua-users.org/wiki/ObjectOrientedProgramming
Using middleclass, your code would become like this:
require 'middleclass'
-- middleclass needs the class name as a parameter
SuperClass = class('SuperClass') -- I don't see the point of using a K here, BTW
function SuperClass:initialize(x,y) -- initialize instead of init
self.x = x
self.y = y
end
function SuperClass:debug()
print(string.format("(%d, %d)", self.x, self.y))
end
--
Ship = class('Ship', SuperClass) -- notice that we put the superclass here
function Ship:initialize(x, y) -- initialize instead of init again
-- you can accept and set parameters here
print('ship:initialize() called')
self = SuperClass.initialize(self,x,y) -- notice the extra self and initialize here
print('attempting to call self:debug()')
self:debug() -- works! prints
print('ok!')
end
function Ship:draw()
print('ship:draw() called')
print('attempting to call self:debug()')
self:debug()
print('ok')
end
Upvotes: 2