I found MiddleClass's mixin functionality, and made a quick attempt, but I've messed up somewhere.
I've attached the same code in a .love and below. Basically my "Pushable" mixin should make some entity subclasses pushable, but not others.
However when I try to call :pushed on Tree, the method isn't there (obviously).
Is there a better way to do this?
require("middleclass")
Pushable = {}
function Pushable:pushed(by)
print("I (" .. self.name .. ") am being pushed by " .. by.name)
end
Entity = class("Entity")
function Entity:initialize(name) self.name = name end
Block = class("Block", Entity)
Block:include(Pushable)
function Block:initialize(name) Entity.initialize(self, name) end
Tree = class("Tree", Entity)
function Tree:initialize(name) Entity.initialize(self, name) end
function love.load()
b = Block:new('blocky')
t = Tree:new('tree')
p = Entity:new('the player')
end
function love.draw()
b:pushed(p)
t:pushed(p)
end
A good way to do this is to have one big Sprite class that has all of the features you want. And then you derive that class into concrete classes that specifies the flags that you want for each item. For instance, the pushable this would go like this:
Sprite = class()
Sprite.pushable = false
function Sprite:pushed( dx, dy )
if self.pushable then
self.x, self.y = self.x + dx, self.y + dy
end
end
Crate = Sprite:subclass()
Crate.pushable = true
I hadn't thought of that... but then wouldn't your Sprite definition be thousands of lines long?
You could split up Some of the functionality into external files that are then included, but the core parts would get messy.
For instance every time the player touches a Sprite, you'd have to go through a big if-then statement to decide what to do.
I guess it would work, it just seems a little messy.
Also how would it work for performance and memory? (I have no idea how Lua deals with this)
Every single sprite from decorative clumps of grass to climbable walls would have all this code and behaviour associated with it that was irrelevant.
I don't mean to sound too negative, thanks for the idea. I often over-engineer stuff, and your way sounds like it would work.
Memory usage depends on how the class code is arranged. Some class implementations copy all members to the instantiations. These would eat a bit of memory, though they would be faster. Most implementations use metatables and the __index metamethod. This makes it so instatiations have no members in them but what's uniquely theirs, so less memory used, but every function is polymorphic, which could be slower in deep class hierarchies. Mixins combine the two, so that you copy in what's relevant to the lowest class possible before instantiation.
As for how big the code will get, it depends on the complexity, obviously. Not everything needs to go in the main sprite class if it's only going to be relevant in a single child class, so you could move it down. But that code will need to get written anyway, and where is just how you keep organized. Without suggesting something more complex like a Entity/Component system, I can recommend that you try to keep the sprite hierarchy as flat as possible. Deep hierarchies have the tendency to become fragile, where you make the assumption that only crates will get pushed, and then realize that wheels get pushed also, and try to create a common class Pushable, but then realize that both can be picked up, and make a parent class Holdable, and then realize that heavy bounders can't be picked up but can be pushed.
Thanks for the excellent reply I had no idea about what Lua does under the hood.
I totally agree about the fragility of inheritance. I thought I heard about an alternative that was more suited for games. I think it's the Entity/Component system that you mentioned. That sounds perfect for what I want to do. Some objects have a Animation component, some have Pickupable, etc.
I searched the net briefly but couldn't see anything for Löve/Lua. Maybe I'll have to write my own. At least I know what it's called now
Just an alternate thought, Lua's type behavior is best described by Duck Typing. The simplest way to do mixins/entity component/etc is to just build up the objects that you want by attaching the functions necessary. Let me demonstrate this with code:
juno wrote:I use 32log. It makes creation of objects so much easier and allows inheritance/overloading/overridding
That looks simple but I think I already have what I need from middleclass.
Inny wrote:Just an alternate thought, Lua's type behavior is best described by Duck Typing. The simplest way to do mixins/entity component/etc is to just build up the objects that you want by attaching the functions necessary.
The only problem with that is as soon as you add new functionality, say "meltable", you have to add "unmeltable" to every single other object.
I'm wondering now if a lot of this functionality won't end up in the player class.