Ezelia

Entity Systems : have you used them in HTML5 game dev ?

Recommended Posts

Hello everyone,

 

I started playing with the so called Entity Systems or Entity Component Systems.
(If you don't know what's an ES read this article http://alecmce.com/library/why-use-entity-systems-for-game-engineering witch explain in a clever approach what should be an Entity System and what makes it so different from OOP)

for those who used them, do you think they can be suitable for HTML5 games ?

I made a quick and simple code and from a first viewpoint the system is incredibelly flexible and easy to maintain/add features .

but I don't know if the performance will follow if I use this on a real game ...

 

Share this post


Link to post
Share on other sites

In our game, we're currently using the OOP for entities. So far, we're doing well with it, from a design perspective, though I start to see the point of entity component systems.

 

Concerning performance, I could actually imagine, that an ECS might be more efficient then OOP, at least for V8.

Google had a very interesting video about optimizing JavaScript for V8: http://www.youtube.com/watch?v=XAqIpGU8ZZk

One important statement: in order for objects to be optimized, they must not excess a certain number of properties.

When using OOP, you tend to have objects with a large number of properties per object, so certain optimizations of V8 simply might not trigger.

 

This is all guessing, but I had one experience that was quite interesting and might be related to this optimization:

 

Originally, the rendering of our game was based directly on our entities. However, since this resulted into cluttered code, I decided to introduce "sprite" objects, that are created from entities, and perform the rendering code exclusively on sprites. This was obviously connected with some overhead, since each entity had to create sprites (at least on construction) and copy over some properties that are relevant for rendering.

 

However, to my surprise, the resulting code was actually slightly faster than the previous.

This might be, because the sprite objects were simpler compared to entities, so the code working on sprites could be optimized more efficiently by V8.

 

I don't really have any concrete proof here or anything, but I think going for small objects (which is something that ECS does), might in fact improve performance on some JavaScript engines. 

Share this post


Link to post
Share on other sites

sound interesting :)

my own aproach to ECS is that an entity is actually not a class so I have no constructor there .

all what an entity should be aware of is what components it has.

my components are where data is defined (for example Position component is {x:number, y:number} )

and my systems (I called them Modules) are where all the code resides .


presently, for each game loop I iterate throught all my systems and update them, some systems update entities data others don't ...

for example my renderer iterate throught all entities having Sprite component and update them.

the problem with my present code is that I do many loops (one for each system) ... and I think I can have a performance issue here in the future.

I'm thinking about another approach witch consist in iterating throught all entities each frame, and update it from systems it's bound to....
but then I have to deal with cases where one system has to do defferent operations (for exemple my Renderer should sort my entities THEN render them) ....

from what I'm experimenting, I think that the power (and weakness) of an ES can com from datastructures it can use to organize entities and access theme quickly.

Share this post


Link to post
Share on other sites

Hi again,

 

I see the problem with the iteration.

I think iterating over all entities for every module/system can have serious performance implications since there are probably an increasing number of modules. 

 

In our game engine we have a fixes number of update phases.

1. regular update

2. deferred update

3. rendering

 

So we iterate only three times over all entities (well almost, for rendering we iterate now over sprites created from entities).

So far this worked out well. We need the deferred update phase so that certain entities can react upon the update of other entities immediately and separating update from rendering is essential anyway. So far, there wasn't the need for any additional update phase.

 

So what I suggest in your case: Have a fixes number of update phases and allow each modules to perform an action for each update phase. That way, you can avoid iterating over entities too much and still handle inter module dependencies.

Share this post


Link to post
Share on other sites

I think I found a - hopefully - good approach to handle modules dependencies and iterations optimisation efficiently.
I'm using some ideas from OS's kernels.
actually, the "kernel" will handle inter-modules communication, this way, all modules can communicate throught a "standard" API.
another idea taken from OS's is a scheduler, the scheduler is where I handle modules execution order, priorities ...etc

I made a dumb scheduler that just iterate throught each existing module and apply the logic to it's entities.
then I made another GameScheduler witch run modules in a given order , then run the rendering module at the end (to make sure everything is updated).

this way I keep modules behaviour totally independent from the way they are executed, and I can handle many custom cases by just writing a new scheduler for each case if needed.

Share this post


Link to post
Share on other sites

I made an ECS game engine, you can see it here: https://github.com/whirlibulf?tab=repositories

 

`engine` is the repository for the main ECS management code.

`pong` is a demo pong game using the engine.

And the rest of the repositories are systems and components built for the engine/demo.

And some basic documentation on the website: http://whirlibulf.com/

 

The nice thing about ECS is that it is very modular and data-oriented. All the systems and components are in separate repos, and for a game I can just pick and choose which ones I need/want. Once I've done that, all I need to do is define all the entities in data files, and write any systems for game-specific logic that are missing.

 

I haven't used it in any actual games yet, but I do intend on doing that soon and trying out some more complex systems.

 

It's not really an engine though, it's more like a tiny library, with some other supporting (optional) files.

 

Right now I'm trying to figure out how to do scene management, entity grouping or parenting, and UI stuff.

 

 

the problem with my present code is that I do many loops (one for each system) ... and I think I can have a performance issue here in the future.

 

This isn't a huge problem really, because systems only loop over entities that have the necessary components. For example, the rendering system does not process entities that don't have a renderable component, and the movement system doesn't process entities that don't have both a position and velocity component.

Share this post


Link to post
Share on other sites

 

This isn't a huge problem really, because systems only loop over entities that have the necessary components. For example, the rendering system does not process entities that don't have a renderable component, and the movement system doesn't process entities that don't have both a position and velocity component.

 

 

but how do you determin what entities have, let's say, Render and Position component, whithout looping and checking ? :)

Share this post


Link to post
Share on other sites

There are a few ways you can do it.

 

You can use bit masks, where each component type corresponds to a single bit position.

You would still need to loop through each entity's bitmask to check for the presence of components but it is a very fast check.

But bitmasks don't work very well in javascript so I had to try something else.

 

In my engine, systems can make the engine index certain combinations of components.

When components are added, it loops through each index to see if the entity matches any, and adds the entity's ID to the index if it does.

Then the system can request all the entities for a specific index, which is done in constant time.

There's no need to check which entities match because the check was already performed when the component was added.

This adds a tiny bit of overhead when adding or removing components but ideally this would be done during a loading screen.

 

You can see my indexing code in my entity manager: https://github.com/whirlibulf/engine/blob/master/lib/managers/entity.js

And some instructions for using it in a system (see "Working with entities and components"): http://whirlibulf.com/docs/systems.html

 

index is the function called by systems to let the engine know which component set is required by the system.

updateIndex is called when a new component is added to an entity.

match is called to compare an entity's set of components with an index's requirements.

Share this post


Link to post
Share on other sites

I use ECS in my little engine. I find it very flexible, because you can use components and still mix it with "OOP" way.

For example - you can define a class that is inheriting from entity and all what constructor does is adding few component to itself, after that you can inherit from that class and add one more component, and so on.

This way "OOP" style can still be there.

Share this post


Link to post
Share on other sites

@whirlibulf what you described is actually what I did as a first approach, but I'm trying to figure out faster solutions :) I want to be able to deal with thousands of entities, my current tests are made with 128x128 (16384) entities ...



@narushevich I'm also thinking to use ECS as a low level Framework and still use OOP on top, but the OOP will only provide an API so the developers will not hav to deal with the components ...etc (but they can if they want) ... I don't think that inheriting from Entity is a good idea as Entity is NOT a class in the ECS approach, well actually we model it as a class because we have no choice, but it's just a structure of data. I think it's better to create a separate classe (GameObject?) and just put an entity on it as a variable.

Share this post


Link to post
Share on other sites

Okay, entering the discussion, too.

 

That whole approach seems to me as if it doesn't really fit into how JavaScript works...

Also, it seems to be very slow (or needs additional features to be implemented *hint hint*).

 

What exactly is bad about just extending objects? Its the easiest and quickest way in Javascript to modularize object capabilities.

Somewhere above was the statement that V8 is only optimizing objects with about ~30 props at max. If thats really the only reason to jump through such hoops to implement a ECS, its a bit silly reason, except when:

you only build for chrome.

 

Even then, I dare to say that the little performance gain there doesn't really matter.

Share this post


Link to post
Share on other sites

@Chris, the real gain in ECS is not about performance, but it's flexibility !

I started reading about ECS last year, and wans not convinced of it's value ... but the more I read the more I understood the real ECS approach.

basically :

OOP split the code around inheritance (roles of objects)

where ECS separate the roles themselves.

instead of having a parend object that live, and two children a walker and a flyer .

in ECS you have the live role, the walk role and the fly role witch you can combine in any way you need.

I started making a PoC with this and I'm really impressed of how the code becomes maintainable. really!

also, ECS really separate between data and game logic. Components hold data, systems hold game logic and this also make the code more readable than classic OOP.

now about JavaScript, actually it's more suited to ECS than other languages mainly because JS is prototyped so it's ways easier to implement ECS using JS than other languages (I'd say it's more natural to write ECS in JavaScript than OOP).

that being said, I'm not claiming that OOP is bad or have to be abandonned, but from what I learned, ECS is really more suited to games than OOP.

the performance issue comes when the number of entities become really big, but this is not due to ECS itself, it's more related to the way you handle your update loops.

you can have an OOP code and ECS code that produce the same in-memory datastructure and the same game-logic code, the only difference is how you split concerns .

Share this post


Link to post
Share on other sites

to give a concrete example.

when I create an entity with my code I have that in memory :
 

var myEntity = engine.createEntity();//myEntity = {id:'someUID' }



I decide to add a position component witch define x and y
 

myEntity.addComponent(CPosition)//myEntity = {id:'someUID', pos:{x:0, y:0}}



then I decide to add input component
 

myEntity.addComponent(CInput)//myEntity = {id:'someUID', pos:{x:0, y:0}, input:{lastkey:-1, mouseX:-1, mouseY:-1, mouseDown:false}}

...etc


when I run my engine it does nothing, until I start a module (a subsystem).

now I start my Input system (MInput), it'll register all entities having CInput component and update them each time a mouse/key event is fired (we can also apply filter to only update some entities).

I click somewhere on the screen and I get
 

//myEntity = {id:'someUID', pos:{x:0, y:0}, input:{lastkey:-1, mouseX:150, mouseY:200, mouseDown:true}}




I want to render things, I need sprite component for this
 

myEntity.addComponent(CCprite)//myEntity = {id:'someUID', pos:{x:0, y:0}, input:{lastkey:-1, mouseX:150, mouseY:200, mouseDown:true}, sprite:{img:'path/to/img.png', index:0, width:64, height:64}}


(supposing that MRender module is allways running)



I have to handle movements : I add a system that register entities having position and input component, and move each entity to the last clicked position.




now some entities no more need rendering :
 

someEntity.removeComponent(CSprite).







with this approach, you can handle object pools more efficiently since everything in your game is an entity :)

Share this post


Link to post
Share on other sites

So you are registering all the entities that some system wants as they are added? Traditional ES have much more functional approach where each update they query all the entities for the right ones. I didn't like this approach and used something similar to what you do... it has its problems but works quite well as long as I take care to keep it clean.

Share this post


Link to post
Share on other sites

So you are registering all the entities that some system wants as they are added? Traditional ES have much more functional approach where each update they query all the entities for the right ones. I didn't like this approach and used something similar to what you do... it has its problems but works quite well as long as I take care to keep it clean.

actually, "querying" entities to get right ones or having the right ones up to date on a list of references, is functionnally the same  :)

when I say "registering entity", I mean adding a reference to that entity in the subsystem index .

it's exactly the same idea as SQL indexes.

instead of iterating all entities to determine witch ones have a given set of components, I make an index that is mutch faster.

 

Share this post


Link to post
Share on other sites

Here's another nice introduction article series on entity systems: http://t-machine.org/index.php/2007/09/03/entity-systems-are-the-future-of-mmog-development-part-1/

 

@Chris - Entity systems are about composition over inheritance, not performance.

 

For example, if you have a player entity and a monster entity, both need position because they need to be able to move and be rendered somewhere.

 

For an example OOP approach, you might have two classes, Player and Monster, both inheriting from a simple BaseEntity class.

What if one type of monster needs to go underwater, and one kind needs to fly? You add some new classes, UnderwaterMonster and FlyingMonster extending Monster.

What if another type of monster can both go underwater and can fly? What do you do then?

What if monsters have different kinds of attacks - melee, range and magic? Do you now have MeleeMonster, RangedMonster, MagicMonster? What about UnderwaterMeleeMonster, FlyingMeleeMonster, UnderwaterRangedMonster, etc.?

Now what if the Player class also needs to go underwater, fly, and have different kinds of attacks?

 

Quite simply, inheritance is not a model that works for most games. There are far too many kinds of entities with different shared properties and behaviour.

If you were to do this in OOP, you would have a huge mess of classes.

 

Wouldn't it make more sense if Underwater, Flying, Melee, Range, and Magic were separate components that you could easily add to any entity, where the logic is separate from entities?

A flying system shouldn't care if the entity is a player or a monster, or a brick, and if the entity can go underwater or not. As long as the entity can fly, then the flying system will handle all the logic for making it fly.

 

 

That whole approach seems to me as if it doesn't really fit into how JavaScript works...

Also, it seems to be very slow (or needs additional features to be implemented *hint hint*).

 

Can you explain what you mean?

 

The design has very little to do with language and can be implemented anywhere.

From my own experience, javascript hasn't hindered writing an entity system in any way.

 

As for performance, there aren't any known benchmarks for entity systems in javascript. As I said, entity systems are not necessarily done for performance, but they can perform just as well or even outperform simpler approaches.

 

 

What exactly is bad about just extending objects? Its the easiest and quickest way in Javascript to modularize object capabilities.

 

There's nothing bad about it, it's just a simpler approach, and is already the first steps towards an entity system. A proper entity system is easier to maintain and more flexible.

Share this post


Link to post
Share on other sites

This looks a bit like a bit more advanced and modular _.extend() approach.

Are there any libs to provide this functionality?

 

@ezelia: I still don't see a reason why you would want to iterate over a objects properties :)

Share this post


Link to post
Share on other sites
Are there any libs to provide this functionality?

 

Well, whirlibulf does this :P

CraftyJS is slightly similar to an entity system but it's not quite the same.

I'm not sure of any others in javascript, although I'm sure many people are working on them right now.

 

 

I still don't see a reason why you would want to iterate over a objects properties

 

The idea is that properties (components) are stored separately from entities, even though it conceptually belongs to an entity.

 

This allows you to process components independently from each other. A rendering system doesn't care about the AI state, input state, etc. of an entity.

All it needs to know is what to draw, and where to draw it, so that is the only data that the rendering system needs to iterate through.

Share this post


Link to post
Share on other sites

This looks a bit like a bit more advanced and modular _.extend() approach.

Are there any libs to provide this functionality?

 

@ezelia: I still don't see a reason why you would want to iterate over a objects properties :)

 

yeah it's sort of _.extend() ... and .extend() is not a POO feature, in a pure POO aproach .extend is evil ;) and here comes ECS.

about iteration, I think I didn't explained my aproach good.

actually I'm not iterating over objects properties, I'm iterating over my objects (or entitites) !

when the "cursor" is pointer to an object, then each subsystem will update a set of that object properties if the object is referencing a component handled by the given subsystem.

the only problem I had with my initial approach was with the renderer subsystem witch need to iterate over all renderable entities where most of other subsystems only need to update a small set of entities ... my initial implementation was iterating over all entities and checking each one against all available subsystems.

not I changed that with a "scheduler" aproach, the role of scheduler is to handle those loops in a more efficient way.

for example, loop over entities tagged as "modified" and apply modification.

then loop over all renderable entities within the current viewport to render them.

now I have no more performance issue :)

there are some implementations out there, but all of them mix between OOP and ECS and I didn't like their aproaches.

I'm not abandonning POO, ECS will be the low level of my game engine, and OOP will handle the top level.

for exemple, when I'll create a player : var p = new player(x, y, 'alias', 'mapId', {/*shape*/} ....)

this will create an entity and extend it with corresponding components.

the POO layer will be there only to provide a more commone way to create composite game objects/components.

the base game logic will be handeled by the ECS

 

Share this post


Link to post
Share on other sites

When using a ECS, I would create object constructors where the prototype is made of entity components.

This way, you can always say new XY() and have a completely fresh object, based on the components. That sounds nice to work with :)

Share this post


Link to post
Share on other sites

For many years I've been using ECS to build my games. ECS is perfectly suitable for browsers but may really hit performance if your engine isn't well designed. The game I'll present to the JS13KGame contest will use a small ECS engine. The main benefit is modularity: you can assign components to an entity to give it new behaviors without editing your entity class or setting flags (in traditional OOP). 

 

When JS13KGame will be over, I'll release the engine and provide benchmarks.

Share this post


Link to post
Share on other sites

interesting :) I'd like to see your implementation, I'm still experimenting different approaches, to make something simple and powerful.
I looked inside ash engine code and its ported version, it's approach is almost what I want to implement but I dont like the nodes thing, I think it adds some complexity to the engine that can be avoided.

Share this post


Link to post
Share on other sites

Very interesting thread, i have been looking for a simple and lightweight yet performant (yes yes, i know, i want it all ;) ) Javascript ECS framework, but have yet to find it.

Even though it is very interesting to read the articles about different aproaches and ways to optimize the code, i prefer not to try to reinvent the wheel myself as i have done so often in the past, so i am looking for a good and active project that i can use in my games. (i also lack the in-depth knowledge of the inner workings of JS to optimize such a library to the necessary extend)

 

Unfortunately i have not found a valid candidate yet. It seems to me that although the ECS idea has been around for a while, it has not culminated in a widespread JS engine.

I have looked into

AshJS : https://github.com/nckpark/AshJS

esEngine: https://github.com/jlgrall/esEngine

Bindlestiff: https://github.com/hughsk/bindlestiff

and the code of a few game engines which did include an ECS, but these projects were either not working (esEngine), not really complete or optimized (bindlestiff) or inactive (AshJS).

 

After reading this thread i will happily give whirlibuff a try. It would be awesome if a few people could agree on the same way of implementing an ECS in JS and would work together to create a solid and JS optimized base system that could be used in other projects.

 

So far it seems that everybody is using his own little ECS, which is perfectly valid as the implementation itself is not overly complicated, but the optimization of the code is another story.

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...

  • Recently Browsing   0 members

    No registered users viewing this page.