top | item 35434374

Flecs – A fast entity component system for C and C++

200 points| apitman | 3 years ago |flecs.dev | reply

86 comments

order
[+] grenoire|3 years ago|reply
To any budding game developers, my advice would be to not rush into ECS and try to accomplish your goals with structs and loops first and understand the fundamentals of how a video game 'works' under the hood.

Your game will get done if you work on it, not necessarily if you pick ECS!

[+] stephc_int13|3 years ago|reply
I've spent a few months working with ECS/DOTS with the Unity Game Engine, their implementation of this style of architecture end up being very complex in comparison to the old fashion GameObject workflow that made Unity popular in the first place.

Everything is MUCH more difficult to implement, I won't go into details but from my experience the time spent to achieve a similar result is about 5x-10x what it should be.

Weird APIs, poor documentation, limited collective experience, tons of restrictions and limits of the C# language are making the global experience quite nightmarish.

And I have had experience with ECS-like system in different engines in the past, and I am mostly experienced with low-level engine stuff, but the induced complexity there is something I did not expect.

[+] davedx|3 years ago|reply
Yeah fully agree, ECS is the microservices of gamedev these days.

I've worked on AAA games that used it, and shipped games as a solo dev without it. If you don't know why you need it, then chances are you don't need it. Just keep it in mind as one possible architecture pattern for when your code base starts to experience growing pains is my advice.

[+] pjmlp|3 years ago|reply
Indeed, golden rules of game development, finish the game, game design matters more than tech, either make an engine or a game.
[+] illiarian|3 years ago|reply
I've also seen a few game devs saying ECS are useless in quite a few situations (or, at least, a very zealous adherence to ECS).

I guess it's one of those things that you don't know until you try (and hit the limits of using or not-using one).

I'm also reminded of Robert Nystrom's "Is There More to Game Architecture Than ECS": https://youtu.be/JxI3Eu5DPwE

(Yes, Robert Nystrom of Game Programming Patterns and Crafting Interpreters)

[+] brigadier132|3 years ago|reply
I completely disagree.

How games work is simple. It's a simulation run at some frequency and the simulation can be affected by player input. Sometimes there is a synchronization step with a server and that is more complicated.

ECS is a pattern that results in better performance and more maintainable code. There is no reason not to use it.

[+] midland_trucker|3 years ago|reply
As a programmer not part of this world: what's the go-to alternative in this situation?

Does ECS not naturally arise from using OOP? Trying to think if you are creating instances of players/physics objects/items how that wouldn't turn into a kind of entity system.

[+] whateveracct|3 years ago|reply
In imperative langs, maybe.

But I _would_ recommend ECS to Haskell devs interested in making games because apecs is just that good.

[+] strictfp|3 years ago|reply
I'm working with an ECS at $dayjob. But I'm starting to question one aspect of them. Composition of functionality makes sense. And systems acting independently and only on objects with related components makes sense.

But dynamically updating the set of components for an entity in order to "send it" to some other system, and relying on the ECS as a query database to coordinate all this, seems like questionable practice to me. I'm seeing more and more of that in our systems.

I think ECSes are becoming too dynamic, and will start to eat perf, and hide relations. Like some message bus.

Anyone else with the same gut feeling?

[+] tokumei|3 years ago|reply
I really love ECS. I’ve shipped games with my own spaghetti mess of classes and poorly thought out inheritance (at least it feels that way) but ECS and composition just is much nicer for incrementally adding functionality without thinking about the big picture too much. I love that I can think about just one small feature I want to add instead of the overall grand design.

This might be bad design (no idea) but I’m working on an item system for a game right now. I have Item and ItemHolder components. If it’s a player, they’ll have an InputController component, which lets them use the Item in the ItemHolder, otherwise there is an AIController component that let’s an NPC use the item.

I have a system for handling every piece of functionality that can be defined in its smallest form, which makes it incredibly easy to add or remove functionality to any entity.

Also, performance is great. I have the mindset to not prematurely worry about performance until profiling now.

[+] meheleventyone|3 years ago|reply
There's a few things really:

Inter-entity/system communication without a bunch of tooling to support it is always going to be a bit cludgy and hard to follow as it's by necessity dynamic at runtime. It is really useful though so writing tooling for it is a good idea.

Perf impact could be pretty big if your ECS uses archetypes and needs to do a lot of copying data around as components are added and removed. But in my experience these sort of events tend to be low frequency so probably not terrible. Always good to measure though!

Don't feel hide bound to stick within the confines of the ECS setup. It's a tool not a way of life! Straight forward message passing might be much cleaner and clearer or there might be a better data sharing strategy that can live outside the ECS itself. All frameworks provide fun puzzles of how to fit functionality into them when going round them is sometimes simpler and clearer!

[+] Carbonhell|3 years ago|reply
If I understood correctly, you are referring to applying some sort of tag component to a set of entity to be able to query it in a separate system. Am I correct? For cross system data flow, I think a mechanism similar to what Bevy does is the way to go. A specific event bus where the developer can send any type of struct, which can also allow passing a set of entity ids. I have briefly used it for my project and I think it's clear to reason about. The only catch is that you need to be careful about timing (the time between sending and receiving an event might take one frame to propagate).

https://bevy-cheatbook.github.io/programming/events.html

[+] stephc_int13|3 years ago|reply
When working on game, the control flow must be as easy as possible to follow and modify.

With the ECS implementation in Unity DOTS, this is absolutely not the case, the control flow is mostly managed behind the scene, and multi-threaded, the simplest things are transformed into a puzzle of cascading interactions.

[+] vouwfietsman|3 years ago|reply
> But dynamically updating the set of components for an entity in order to "send it" to some other system, and relying on the ECS as a query database to coordinate all this, seems like questionable practice to me.

Indeed it is. The idea of components is to decouple systems. Where systems generally operate on few components, and own a disjoint set of components. It is not a communication channel, just like any other database should not (primarily) be used as a communication channel.

You can combine an ECS with any number of different patterns to make your communication work: events, agents, messagebus, you name it.

[+] CapsAdmin|3 years ago|reply
Apart from memory layout benefits, I always felt ECS is a bit like giving dynamic language capabilities to a statically typed language.
[+] worldsayshi|3 years ago|reply
Interesting. Do you have any alternative approach in mind?
[+] indigoabstract|3 years ago|reply
This looks pretty well polished and maintained, I wasn't aware of it.

So far, I've used an alternative ECS called entt:

https://github.com/skypjack/entt

https://www.libhunt.com/compare-flecs-vs-entt?ref=compare

[+] pphysch|3 years ago|reply
EnTT is quite nice because it's more than just a ECS (if you want), it also includes libraries for a variety of other features like resource management. It's more of a "game engine" library, which is fantastic for projects that don't need to muck about in a "game studio" like Unity/Unreal (e.g. for games or simulations that don't require traditional level design).
[+] HelloNurse|3 years ago|reply
Flecs and EnTT clearly position themselves as each other's rather friendly competitor, with significantly different design choices.
[+] sowbug|3 years ago|reply
I read the front page of this site, and I still have a general question about ECSes. For what it's worth, I'm developing a DAW (digital audio workstation) in Rust.

It seems that ECS helps compose "things" (an entity) out of groups of data (each a component), and then operates upon combinations of those components (using systems). My domain is organized around behavior (many musical instruments implementing a Rust trait or interface, such as MIDI), but the data constituting each instrument is totally different. So the behaviors are the same, but the data is different. It seems that ECS isn't a fit, which is a shame because the implementations I've seen offer cool features like easy parallel processing, querying, and so on.

Is there a design pattern like ECS but for common behaviors instead of common data? Or am I being dense and not seeing how ECS actually is a good fit for this situation?

[+] ajmmertens|3 years ago|reply
The way you frame the question already suggests a solution, and one that indeed doesn't fit ECS that well. That doesn't mean you couldn't design a DAW using ECS, but you'd have to redesign how it works.

For example:

- create custom components for different instruments

- create systems for specific instruments that match the necessary components

- write the result to a common component (e.g. "ChannelOutput")

You could then add components for EQ, effects, routing, ... and introduce systems that match those. The advantage of this approach would be that you end up with a bunch of loosely coupled systems (for instruments, effects, mixing, ...) and an in-memory representation that's cache & parallelization friendly.

One other datapoint would be that Unreal's animation sequencer uses an ECS design, which has a lot of things in common with a DAW.

Glossing over lots of details here, you can't of course design a DAW in one paragraph.

[+] deterministic|3 years ago|reply
Experienced game developer here: if you are just starting out wanting to learn how to make games then 1000000% focus on gameplay and not technology. Almost all developers I know who starts working on games end up basically just working on engine technology and never get an actual game done. I used to be one of them so I talk from experience! :) Nowadays I just use Unity and focus on the actual hardest part of making games: coming up with fun enjoyable gameplay that isn’t just a clone of somebody else’s game.
[+] stkni|3 years ago|reply
I have a sort of off-topic question. The marketing for this claims not using STL containers as a selling point. Does anyone know what makes STL containers unsuitable for this use case? Clearly they're not a one size fits all but I'm intrigued to know why you market an unknown container based API over a tried and tested one?
[+] ajmmertens|3 years ago|reply
The biggest reason for me was to reduce compile times, which got cut into approximately half when I replaced STL containers with simpler custom ones. This starts adding up in large projects, where lots of files end up including the ECS.
[+] korijn|3 years ago|reply
Any idea what a game loop would look like for an ECS engine that only renders a new frame when some animation is running or when the user is manipulating the camera, but not otherwise?

Let's not argue "why". Most obvious would be saving battery.

[+] crabmusket|3 years ago|reply
I've implemented exactly this at $WORK. We literally just set a global variable, "should render next frame", from input handlers and other important events. It's not pretty but it gets the job done. There are occasional bugs where someone forgets to set the render flag after some significant event. But the bug goes away as soon as the mouse is moved, so it's usually not a big deal. If we wanted we could also schedule a "render once per second" to bound the amount of time that visual issues would persist for.

I'm not sure how this translates to ECS architecture - probably depends on your library, but if you're in charge of the main loop it shouldn't be a problem.

[+] ww520|3 years ago|reply
For energy efficient game loop, it still runs in a fixed frequency, e.g. in 60fps or 30fps. For each frame, the time is spent on event processing, state update, rendering, and sleep. Some of the steps can be skipped. The goal is to lower the times spent in the non-sleeping steps, and sleeps more for each frame.

Event queues are used to track things in long duration across multiple frames, like user input, animation sequences, sound sequences, pending state update, pending physics update, pending AI update, etc.

In each frame, check the event queues. If they are empty, sleep. Otherwise, process the events in the queues. For user input, do the state update corresponding to the input, like updating the camera position.

For ongoing animations, advance the steps in the sequences (the drawing is done in the rendering step). When an animation sequence completes, remove it from the queue. Same for sound.

For pending state update, run the update. E.g. the ship is moving, do the state update on its velocity and position. For ECS, you might end up calling or not calling the systems for the item type for batch update. E.g. when the bullet queue is not empty, you might just run the bullet related systems over all bullets for simplicity. When all the bullets end and the queue is empty, the bullet related systems can be skipped.

The physics queue has the items being simulated. Run those. Physics could run at a slower rate like 5fps, so the queued items would be skipped most of the times. Same with the AI items in the AI queue.

Whenever there's a state update, mark the screen as outdated. At the rendering step, run rendering if the screen is outdated. It's simpler to just run the whole rendering for any change. Ideally, when there's no event in the queues or the state updates are not triggered, there's no need for rendering.

This applies to using ECS or not. ECS is for tracking states of entities and do batch update with systems.

[+] pengaru|3 years ago|reply
ECS isn't really relevant to the question

game loops usually call into simulate() and render() entrypoints.

There's state potentially mutated by simulate().. render() looks at that state and potentially produces a new output to present on-screen.

Typically the render() entrypoint returns a status indicating whether a new output was produced or not to put on-screen. If no output was produced you don't flip pages. So in a quiescent situation with nothing changing, render() returns "don't flip" and you just leave the existing page displayed til the next iteration.

How you track the internal game state / dirty vs. clean state is implementation detail behind those simulate() and render() entrypoints and depends greatly on the type of game.

[+] jiggawatts|3 years ago|reply
I wrote a game engine that did that, because it was for a very simple, largely static scene.

You would implement it almost the same as a standard Windows GUI -- using an event handler loop that marks the screen as "dirty" and needing a refresh if it has changed.

Where it would immediately break down is ongoing animations. If you stopped moving your mouse, then animations would stop. Of course, you can set up the event loop to continue triggering if there are animations going on, but then you basically have a standard game engine loop running most of the time.

Personally, I'd be happy if games simply paused rendering when minimised. Some games do this, some don't.

[+] ajmmertens|3 years ago|reply
Definitely possible. I know of a project that used an event-based architecture to decide when to run ECS systems.
[+] Cthulhu_|3 years ago|reply
I'd say this is something that can be done on a driver / GPU level; if the inputs to render the next frame are the same, it can just reuse the previous one.

That's probably oversimplifying it, I don't know anything about graphics programming.

[+] holografix|3 years ago|reply
Could this be used to implement an efficient backend server for an Unreal Engine game?
[+] chii|3 years ago|reply
i dont think it's tied to any particular engine or renderer, because an ECS is merely a mechanism to organize data so that it can be accessed fast.
[+] ajmmertens|3 years ago|reply
It could be yep. One of the things that makes it a good fit for this use case is that Flecs has a query language that supports things like graph traversal and joins. Combined with either the builtin REST API or some custom protocol you could use it as a realtime in-memory database (which is what I use it for).
[+] Cthulhu_|3 years ago|reply
Doesn't Unreal have its own entity system yet?