New entity system: PILES

General discussion about LÖVE, Lua, game development, puns, and unicorns.
Post Reply
kuniqs
Prole
Posts: 4
Joined: Tue Oct 14, 2014 3:02 pm

New entity system: PILES

Post by kuniqs »

Behold, PILES!

(check out https://github.com/kuniqs/imbir8 for newest version)

Politically Incorrect Lua Entity System was inspired by <a href="http://t-machine.org/index.php/2007/09/ ... t-1/">this article</a> about database-based (durr) entity systems used in MMOs. tl;dr: You have a set of entities (bags of components) and a bunch of systems working in ordered way (functions which work on entities that have the required components). So, you can have a system named 'movement' that works on all entities with the 'position' and 'velocity' components.

I've tried others' approaches to component-based architecture, but was put off by Java-style syntax of them. I mean - come on! Lua deserves better than that.

My code is more a proof of concept than usable, and slow as hell I guess (but it wouldn't be noticeable under luajit I think). I couldn't figure out a way to remove entities from the inside of the system processing part, so the entity database gets copied before each iteration and zombie objects get buried after it. I also didn't used the observer pattern for event handling (to be fixed when I feel like it) since I'm more concerned about usability than speed at the moment.

One thing I never found an satisfying answer for is: How do you manage message passing between components? Problem is, the order of recievers of that message is undefined, so if we have situations where the order of components affects the side effects of the message (say, A tells B to 'die' but C prevents 'die' on B - with [C,A,B] order B dies but with [A,C,B] order B lives), how do I untangle this mess? The solution I have so far is to keep event flags in components and mark them as 'dead' then rethrow the message until everyone involved do their job. But that leads to bloat and unmanageable situations where you have multiple event handlers, each doing the handling in conflicting ways, meaning each one needs to know about each other to avoid errors. There MUST be a simpler way.


<a href="http://chomikuj.pl/kuniqs/PILES,4279586 ... OWNLOAD</a>
Last edited by kuniqs on Tue Nov 18, 2014 10:54 am, edited 1 time in total.
User avatar
Jasoco
Inner party member
Posts: 3726
Joined: Mon Jun 22, 2009 9:35 am
Location: Pennsylvania, USA
Contact:

Re: New entity system: PILES

Post by Jasoco »

Hi. Welcome to the forum. Some problems though.

First, use the forum URL tags. HTML does not work here. It makes this post come off as a copy and paste spam which I hope was not your intention.

Second, if you upload an example, either upload or just paste the contents of the single .lua file into the thread or if it's a full example, it should be a fully running .love file. The file you uploaded is not usable as-is at all. It has no main.lua and no documentation to help people figure out what it does.

Lastly, use the forum attachments system. Especially for something so small. And don't upload .rar files. We prefer .love files or if needed .zip. Just for compatibility. But if you must, still use the attachments feature.

Thanks.
kuniqs
Prole
Posts: 4
Joined: Tue Oct 14, 2014 3:02 pm

Re: New entity system: PILES

Post by kuniqs »

It's me again. I've tried many approaches, each with it's own drawback and said 'to hell with it'. Seeing as no single way was perfect, I've written few games in spare hours to see how my favorite ECS (clone of Artemis framework) manages. I also removed the juvenile political incorrectness after I got sober.
The biggest problems so far (apart for the performance issues of course, as I went out of my way to avoid complicating the framework) are:
1) How to efficiently remove/add a table item in Lua (either from hash or table), during iteration, without affecting the order of iteration? (I'm just making a copy for iteration, which is simple but not scalable)
2) How to query entities without making assumptions about them? The 'best' way is a SOL-esque query function that returns a collection of entities that fulfill established requirements. It's just too slow. I've had this problem with collision detection code. Other way is to send events through the whole system, but it's just a variation of the method above.

Those games have been coded in a few hours each and it shows. I think it's more honest to publish the 'unprettified' versions to show how ECS frameworks work in practice (or maybe I'm just lazy?). I'm working on improving the framework itself and when I'm done, I'll show off a mario bros clone.
PONG.love
(2.68 KiB) Downloaded 148 times
ASTEROIDS.love
(3.47 KiB) Downloaded 146 times
SPACE_INVADERS.love
(2.65 KiB) Downloaded 166 times
kuniqs
Prole
Posts: 4
Joined: Tue Oct 14, 2014 3:02 pm

Re: New entity system: PILES

Post by kuniqs »

I'm publishing an improved version here without memory-leaking bugs of the previous one. I'll post the game later since honestly it's the first time I've tried my hand on coding a platformer - I'm more a roguelike developer.

Why Imbir6? It's a mystery of the ages, or for whoever gets a hold on my bong. And it's the 6th rewrite of it.

How do I catch errors in LOVE? 'Cause whenever an error occurs in LOVE, even with the --console switch, everything just crashes to Windows without any warning or output. Even redirecting standard output via command line doesn't work.

BTW. Is there a way to manually call love.draw, so my game doesn't waste time clearscreening then redrawing everything 100 times a second? Also can someone explain to me how paths in love work, and how to add my lua directory to love's search path?
imbir6.lua
(8.21 KiB) Downloaded 138 times
kuniqs
Prole
Posts: 4
Joined: Tue Oct 14, 2014 3:02 pm

Re: New entity system: PILES

Post by kuniqs »

The final, 8hth iteration of Imbir Component System library. This one has been rewritten to solve some performance problems with imbir6. Long story short: it doesn't waste cycles any more. For more of my spergin check below.
imbir8.lua
(7.11 KiB) Downloaded 126 times
Usage (more detailed uses inside library):

Code: Select all

	w = World()
	i = Imbir{x=2,c='i'}
	s = System{
		'x','c',
		Logic = function(i)
			print(i.x,i.c)
		end}
	w = w + Imbir{x=1,c='a'} + Imbir{x=3,c='b'} + s + i -- add 3 imbirs and subscribe 1 system to world w
	w = w - i
	Iterate{s,s} -> will print
		'1	a'
		'3	b'
		'1	a'
		'3	b'






For my pc (1.6 GH intel cpu)
- imbir8, called 60 times per second for 6 systems each iteration, where each system works on about 1/5 of imbirs, handles ~25 000 different imbirs with no logic in them
- imbir6, for the same scenario, handles ~3000 imbirs and scales much worse with more systems and imbirs

- imbir8, iterating once for 6 systems, where there's only 1000 imbirs per system in a 100 000 imbirs collection, clocks under 0.01s
- imbir6 takes about 1 second

Systems now cache all their imbirs pre-iteration, which means a system with only 1 corresponding imbir from a collection of 1000 imbirs will no longer spend time type-checking the other 999 ones. The computational complexity of system iteration was (number of systems)*(number of all imbirs in the world) and is now (number of systems)*(number of corresponding imbirs for each system).
So, in the old library, having an iteration of 5 systems over 100 imbirs, where each system works on 5 different imbirs, would always take 5*100 operations. In the new library, it only takes 5*5 operations. Iteration time is no longer dependant on overall amount of imbirs in world.
Post Reply

Who is online

Users browsing this forum: Bing [Bot] and 4 guests