OO Game Architecture

Questions about the LÖVE API, installing LÖVE and other support related questions go here.
Forum rules
Before you make a thread asking for help, read this.
User avatar
kexisse
Citizen
Posts: 56
Joined: Wed Jun 13, 2012 2:52 pm

OO Game Architecture

Post by kexisse »

I'm trying to make a large-ish game, with objects that have different attributes. How is it best to do this in Löve/Lua?

For example, I imagine objects would have a mix of attributes like:
  • Pushable/Pullable
  • Carryable
  • Climbable
  • Interact-able (hit X next to them for something)
  • Solid (impassable for the player)
  • One-way solid (imagine platforms you can jump up to from below, but that you can stand on)
  • Animated
Is there a good way to do this with Lua/Löve?
Using mixins or something? I'm not sure what the right term is.
User avatar
kexisse
Citizen
Posts: 56
Joined: Wed Jun 13, 2012 2:52 pm

Re: OO Game Architecture

Post by kexisse »

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?

Code: Select all

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
Attachments
mixin_broken.love
Attempt at using optional mixins. Trying to push the tree should do nothing.
(2.43 KiB) Downloaded 202 times
User avatar
Inny
Party member
Posts: 652
Joined: Fri Jan 30, 2009 3:41 am
Location: New York

Re: OO Game Architecture

Post by Inny »

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:

Code: Select all

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
User avatar
kexisse
Citizen
Posts: 56
Joined: Wed Jun 13, 2012 2:52 pm

Re: OO Game Architecture

Post by kexisse »

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.
User avatar
Inny
Party member
Posts: 652
Joined: Fri Jan 30, 2009 3:41 am
Location: New York

Re: OO Game Architecture

Post by Inny »

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.
User avatar
kexisse
Citizen
Posts: 56
Joined: Wed Jun 13, 2012 2:52 pm

Re: OO Game Architecture

Post by kexisse »

Thanks for the excellent reply :D 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 :)
Santos
Party member
Posts: 384
Joined: Sat Oct 22, 2011 7:37 am

Re: OO Game Architecture

Post by Santos »

FEZ may be what you want!
User avatar
juno
Citizen
Posts: 85
Joined: Thu May 10, 2012 4:32 pm
Location: London

Re: OO Game Architecture

Post by juno »

I use 32log. It makes creation of objects so much easier and allows inheritance/overloading/overridding
wat ya mean she's in another castle!?
User avatar
Inny
Party member
Posts: 652
Joined: Fri Jan 30, 2009 3:41 am
Location: New York

Re: OO Game Architecture

Post by Inny »

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:

Code: Select all

Handler = {}
function Handler.pushable(self, dx, dy)
  self.x, self.y = self.x + dx, self.y + dy
end
function Handler.unpushable(self, dx, dy)
  return
end

Crate = Sprite:subclass()
Crate.pushed = Handler.pushable

Boulder = Sprite:subclass()
Boulder.pushed = Handler.unpushable
User avatar
kexisse
Citizen
Posts: 56
Joined: Wed Jun 13, 2012 2:52 pm

Re: OO Game Architecture

Post by kexisse »

Santos wrote:FEZ may be what you want!
Oh cool that looks really good. Thanks!
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.

Code: Select all

function onCollision(target)
  if target.pushable then  -- pushable is undef by default
    player:push(target)
  end
end
This architecture stuff is trickier than I thought.
Post Reply

Who is online

Users browsing this forum: No registered users and 2 guests