So when I was trying to make my LD48, I wanted to use an Entity-Component system. I didn't really plan it out all that well and ended up have to hold some variables inside the Entity to share across multiple components. Not really what you want for Entity-Component.
Doing a bit more reading, I saw that one of the ways to decouple the components from the entity is through a messaging system. Each component has a publish method that is then received up by the entity and distributed to all the other attached components, which can either accept or refuse the message
One thing that is confusing me, is how to implement the receive portion for the entity. For LOVE, you could probably just toss it in a method that gets called during the update phase, but observer patterns aren't supposed to require a game loop
The other option I can think of is to reference the entity inside the component, but again, that makes the entity and component tightly coupled.
Anyone have any thoughts/insights into implementing the Observer pattern in Lua, without either referencing the observer in the messengers or forcing periodic polling?
Observer Pattern in Lua
Forum rules
Before you make a thread asking for help, read this.
Before you make a thread asking for help, read this.
Re: Observer Pattern in Lua
Design Patterns exist as a way to address deficiencies in a language. Things like the Entity-Component pattern exist to allow you to build up objects for your game via the idea that you should "Prefer Composition over Inheritance", rather than having deeply complexy and convoluted taxonomies and hierarchies of object classes. Luckily, you can get away without needing an Entity-Component system in Lua. The reason is Lua is a language with Duck Typing. Meaning that you can bypass the need to build up your entity classes with component classes, and just copy those components into the entity classes directly.
Of course, code always says more that words, so lets see some code:
As for the observer pattern, that's a useful piece of code to be had, and kikito made a nice one: https://github.com/kikito/beholder.lua
Of course, code always says more that words, so lets see some code:
Code: Select all
function player_input_control(self, dt)
if love.keyboard.isDown("space") then self:shoot() end
end
function demo_input_control(self, dt)
self.demo_time = (self.demo_time or 0) + dt
if self.demo_time >= 5 then
self.demo_time = self.demo_time - 5
self:shoot()
end
end
-- Change the player Entity's "Update" component
if current_level == "demo" then
player.update = demo_input_control
else
player.update = player_input_control
end
Re: Observer Pattern in Lua
Your example seems to conflate Entity-Component with Strategy. Components handle more information than merely an algorithm. I completely understand why Strategy is unimportant in Lua, but Entity-Component is a bit different.
For example, Entity-Component wouldn't allow self:shoot(), like you have in your methods, since you would have to assume the entity implements the shoot mechanic.
For example, Entity-Component wouldn't allow self:shoot(), like you have in your methods, since you would have to assume the entity implements the shoot mechanic.
- kikito
- Inner party member
- Posts: 3153
- Joined: Sat Oct 03, 2009 5:22 pm
- Location: Madrid, Spain
- Contact:
Re: Observer Pattern in Lua
I don't think it's possible in pure Lua. You might be able to do something like that if you basically modify Lua itself (from C). But I don't think it's worth it.Anyone have any thoughts/insights into implementing the Observer pattern in Lua, without either referencing the observer in the messengers or forcing periodic polling?
If maintaining a reference to the "interesting object" feels "wrong" to you, maybe using a function which references it from its closure might feel less bad.
When I write def I mean function.
Re: Observer Pattern in Lua
I actually think I found something that would work:
http://lua-users.org/wiki/AlternativeObserverPattern
I'd have to force all the components to have a publish method...but I was going to do that anyways. Here is what I have so far:
I haven't tested it yet; the one thing I am concerned with is the scope of self in addComponent()
Would I need a local this = self to be able to get this to actually work?
http://lua-users.org/wiki/AlternativeObserverPattern
I'd have to force all the components to have a publish method...but I was going to do that anyways. Here is what I have so far:
Code: Select all
function Entity:addComponent(c)
self.components[#self.components + 1] = c
c.publish:register(self, self.receive)
end
function Entity:removeComponent(c)
for k,v in pairs(self.components) do
if c.id == v.id then
c.publish:deregister(self)
table.remove(self.components, k)
end
end
end
function Entity:receive(id, msg)
self:deliver(id, msg)
end
function Entity:deliver(id, msg)
local id_tbl = type(id) == 'table' and id or {id}
for _,v1 in ipairs(self.components) do
for _,v2 in pairs(id_tbl) do
if v2 == v1.id then
v1:handle(msg)
end
end
end
end
Code: Select all
c.publish:register(self, self.receive)
-- without the syntatic sugar
c.publish.register(self --[[ the object publish ]], self --[[the object entity ]], self.receive --[[ the receive method for entity ]])
Re: Observer Pattern in Lua
The code example would have been a bit more complicated to demonstrate duck typing, but the point I was trying to make is that your objects, or their metatables, can be compilations of functionality that's duck-typed, i.e., functionality is assumed to be there in some form. For instance, the self:shoot() call doesn't imply that the entity implements shoot, only that the entity has shoot, meaning that shoot can be one of those things that you mixed in before hand.MarekkPie wrote:Your example seems to conflate Entity-Component with Strategy. Components handle more information than merely an algorithm. I completely understand why Strategy is unimportant in Lua, but Entity-Component is a bit different.
For example, Entity-Component wouldn't allow self:shoot(), like you have in your methods, since you would have to assume the entity implements the shoot mechanic.
A better implementation of my idea would be a "Mixin" function, which I think middleclass has that. The idea being is that Components would be a plain lua table, and the mixin function just copies everything from the component into the entity. There would be a few details that I'm hand waving right now, that would need to be dealt with, like if two mixins both defined an update function, one would overwrite the other.
Yeah, you can use that too. When I wrote it, I was a working as a Qt software engineer and I basically mimicked the Signals and Slots system. If I tried to write the same code today, I probably would allow for generic parameter binding, rather than forcing the self.MarekkPie wrote:I actually think I found something that would work:
http://lua-users.org/wiki/AlternativeObserverPattern
If you continue to use that code, here's the correct way without using the table colon operator. The first parameter needed to be changed.
Code: Select all
c.publish.register(c.publish --[[ the object publish ]], self --[[the object entity ]], self.receive --[[ the receive method for entity ]])
Re: Observer Pattern in Lua
I understand what duck-typing is. Rather than having to create some sort of IQuackable interface, implement that interface into both a Duck class and a Turkey class, and then be confident that I can call both Duck.Quack() and Turkey.Quack(), I just have to go MaybeDuck.Quack(), and during runtime, it'll just check to see if Quack is a function of MaybeDuck.
I also understand that Strategy is trivial when you have first class functions.
But there are some issues with just using duck-typing; mainly holding a state within the component. Again, Entity-Component is not Strategy: components can have states. From Game Programming Patterns:
I also understand that Strategy is trivial when you have first class functions.
But there are some issues with just using duck-typing; mainly holding a state within the component. Again, Entity-Component is not Strategy: components can have states. From Game Programming Patterns:
This pattern bears resemblance to the Gang of Four’s Strategy pattern. Both patterns are about taking part of an object’s behavior and delegating it to a separate subordinate object. The difference is that with the strategy pattern, the separate “strategy” object is usually stateless— it encapsulates an algorithm but no data. It defines how an object behaves but not what it is.
Components are a bit more self-important. They often hold state that describes the object and help define its actual identity. However, the line may blur. You may have some components that don’t need any local state. In that case, you’re free to use the same component instance across multiple container objects. At that point, it really is behaving more akin to a strategy.
- Robin
- The Omniscient
- Posts: 6506
- Joined: Fri Feb 20, 2009 4:29 pm
- Location: The Netherlands
- Contact:
Re: Observer Pattern in Lua
Not necessarily.MarekkPie wrote:I just have to go MaybeDuck.Quack(), and during runtime, it'll just check to see if Quack is a function of MaybeDuck.
In dynamic languages like Lua and Python, yes, always, but if you're using Go you can use static duck typing (which does require you to write an interface, but not declare for each type "yeah this implements the Quacker interface").
Help us help you: attach a .love.
Re: Observer Pattern in Lua
I know this...
...but I guess I wasn't clear enough.
...but I guess I wasn't clear enough.
Re: Observer Pattern in Lua
I had a similar problem. I rolled my own Entity/Component model.
At first Entity had a few lists that components could add themselves to: drawComponents, updateComponents, collisionComponents.
Entity would call draw, update or onCollide on each of the components that had registered themselves.
However it felt kind of messy. So I swapped to using Beholder.lua. Components can observe or trigger at will, and I prefix the triggers with self to make sure they're only observed by the same entity.
I don't know what the performance is like but it seems quite decoupled and clean
At first Entity had a few lists that components could add themselves to: drawComponents, updateComponents, collisionComponents.
Entity would call draw, update or onCollide on each of the components that had registered themselves.
However it felt kind of messy. So I swapped to using Beholder.lua. Components can observe or trigger at will, and I prefix the triggers with self to make sure they're only observed by the same entity.
Code: Select all
Beholder.trigger(self, "selected")
...
Beholder.observe(self, "selected", function() [do something] end)
Who is online
Users browsing this forum: No registered users and 3 guests