I'm seeing Godot mentioned a lot: one major distinction between O3DE and Godot is that O3DE is "ECS-based" while Godot is "OOP-based" [1][2].
This makes little difference for the hobbyist gamedev, but it has ramifications for large projects with many interacting systems. Proper ECS architecture better supports the latter case [3].
That link says O3DE uses EC, not ECS. These are terribly named and often cause confusion, but they are different.
In "Entity Component" systems (think Unity), entities own components that give them data and behavior.
In "Entity Component System" systems (think Unity DOTS), components are just data, and behavior is driven by systems that live outside entities.
They are similar in some aspects and both are radically different than a deep OOP hierarchy, but ECS is quite more hardcore on decoupling. It's been a few years and it's still not unanimous whether adopting Unity DOTS over regular Unity is easy or even worth it, for instance.
Still, Godot isn't very OOP either, working mostly with composition of behaviors.
It's less confusing when written "Entity−Component−System architecture". That is, it's a list of the three concepts -- Entities, Components, and Systems -- that predominate in the architecture.
Do you have an good references for implementing an ECS? I've only found very high level descriptions but they all are a bit handwavey and avoid the implementation details.
I know Entt is a highly praised library, but I'd be interesting in folding in ECS as a general design pattern in my programming.
ECS was popularised with http://enwp.org/Dark_Engine in 1998. The architectural style probably existed already earlier, but I have no evidence I can point to.
Are you sure about the Dark Engine bit? I remember comments from people who've seen the code saying that it was an OOP mess with weird macros over C++ features that looked like COM on a bad day, which sounds completely antithetical to what people call ECS nowadays.
Perhaps it was confined to some part of the engine? ECS didn't come out of thin air after all, it is a generalization of practices people already used for things like particles, etc.
Reading the source codes, I think this is due to no one yet having requested the ability to do so. To me it feels like implementing this is possible, but tedious.
The simple work-around for the problem would be to rebless the instance. Example:
class Structure {}
role Floatable {}
role Inhabitable {}
class Houseboat extends Structure with Floatable with Inhabitable {}
$hb = Houseboat new
$s = Structure new
$s apply Floatable, Inhabitable # houseboat at run-time
# stop swimming
### NYI
### $s unapply Floatable
# make a new house that cannot swim
$s1 = Structure new
$s1 apply Inhabitable
$s1 = $s rebless_into $s1
But note that the point of an ECS is being able to dynamically change roles without recreating new entities. If changing a house into a houseboat means creating a new entity, then everyone who had a reference to the house would need to be informed of the new reference.
I'm not sure I follow. In ECSs that I'm familiar with, entities are integer IDs, not class objects. So adding or removing components (roles) to an entity doesn't make use of any language-level features, it's just calls to the ECS library. E.g. in JS:
var id = ecs.createEntity() // returns an int
ecs.addComponent(id, 'house')
ecs.addComponent(id, 'boat')
So, very different from the class-based approach being floated a few comments ago. Does that answer your question?
Godot's head developer admits that if you want to do anything performance-intensive (e.g. thousands of interacting entities, AAA stuff) with Godot, you will likely end up hacking the low-level engine code or even using a separate ECS/DoD implementation. At that point, why not use a proper ECS engine?
I've played maybe one game with entities in that count range (Planetary Annihilation) and I think you'd need a lot of low level engine work for something like that anyway (since it's doing all sorts of neat stuff with interpolation, weird coordinate systems, networking, etc.)
Hardly any game needs "thousands of interacting entities" though (outside of special subsystems like particle systems). Arguably, (DOTS-style) ECS makes it harder to incrementally build a game by adding features, because you need to put more effort into designing the data layout upfront. And if there's just a few dozen instances of each thing that's definitely overkill, moving to ECS won't make a noticeable performance difference in that case.
> Hardly any game needs "thousands of interacting entities" though (outside of special subsystems like particle systems).
This is an example of survivorship bias. How many ambitious game concepts have collapsed under performance/architecture issues that lead to productivity-killing refactoring? Impossible to say, but no doubt many.
> Arguably, ECS makes it harder to incrementally build a game by adding features, because you need to put more effort into designing the data layout upfront.
OOP bakes these decisions into the inheritance hierarchy, which ends up being more thorny than adding a component, or migrating an existing component's schema. ECS will make it straightforward to determine which Systems will be affected when a particular Component's schema is altered.
Speaking from experience, the hardest part about game development isn’t figuring out how to (efficiently) build something, it’s deciding what to build in the first place. The second hardest problem is getting everyone on board with the answer to that. The third is figuring out how to build the content 1000x to support that. Way, way down the list is the runtime performance for a gameplay system.
True ECS systems - and not frameworks that just have things called “entities” which own things called “components” - are hard to work with, almost by definition (ie you have to be very explicit about data layout and dependencies). They add a lot of friction upfront to solving the important and hard problem(s) while purporting to solve something that isn’t actually an issue in most cases (guess what, your N is likely < 10, modern cpus go brrr, etc). If you are working in a domain where you already know something about the performance and input size characteristics - particle systems are the go to example - then maybe ECS makes sense as a framework. Otherwise, I’d advocate for simpler oop approaches with heavy composition.
> just have things called “entities” which own things called “components” - are hard to work with, almost by definition (ie you have to be very explicit about data layout and dependencies).
My experience has been completely the opposite to this. In fact being explicit about data layout and dependencies is a hallmark of a OOP rather than ECS.
In compiled languages the dependencies in object hierarchies are fixed at compile time and can only support tree designs, so you have to plan ahead for all possible combinations to even build relationships with OOP, even with composition (because its static).
With ECS everything is decoupled so you can write a system that does X and it affects nothing else.
This leaves you free to design by isolated processes rather than by code structure, and entities naturally do whatever processes their data supports dynamically.
Makes iterating designs incredibly rapid and offers design options that are convoluted and fragile with OOP such as completely changing what an entity does at run time.
For instance you can move the keyboard input component from a player entity to a monster or even something as random as a building and it just works - you didn't have to design for it, you don't even need to change any code. Remove the health component, now the entity is invincible, remove the gravity component and now it can fly, add a homing component and now it seeks a target. All this is trivial and can be done at run time. Want flying flaming lampposts the player can control? Just combine the appropriate components. Need to drastically pivot the design? Vastly less work than OOP - sometimes just a case of changing the data in components or their combination in entities without touching systems. Don't need this flexibility? Still gives you a more modular and less coupled design.
As a nice bonus this flexibility comes with more cache friendly performance than static hierarchies to boot.
All of what you describe in terms of data driven entity composition is possible without a true ECS framework. That is what I was referring to and more or less what Unreal or Unity (base, not dots) offer.
ECS is one of the better examples of something that sounds good on paper but in practice, and crucially in production, doesn’t provide the sort of benefits that outweigh the friction it imposes.
There seems to be a myopia online around things like ECS, data oriented programming generally, writing games in C (as opposed to that horrible high level monstrosity C++…), optimization, etc. Those are all fine things in and of themselves (though I’ve never understood the opposition to C++ as anything other than nostalgia), but they are often discussed without being ground in the considerations of building a game. If you want to build a tech demo, great! However, the needs of building a game with hundreds of people, most of whom aren’t engineers, and to a quality/production level that even “simple” things become complicated, demand other things take precedence. I lead a team that facilitates a creative project, not to satisfy my technical desire to have optimal cache or thread utilization in every piece of code. The right tool is the one that gets you closer to the creative goal, and for gameplay code most of the time it probably looks like what Epic or Unity are shipping with their entity frameworks.
It's a "where are the bullet holes on the planes that survived" kind of problem. The thing that overwhelmingly kills game projects is overscoped design, which manifests into a need for very detailed, configurable entities with rich scripting functionality. So if you pursue scalability at the level of the entity system itself, as a thing you should invest substantial engineering resources to - you are effectively saying, "yeah, I have a team of 100 people to throw at the game's implementation and they are going to add literally every feature we brainstormed and also stuff we haven't". Because if you actually don't intend to do that, then you can instead adopt a pattern of prototyping it in whatever works well for authoring, followed by profiling and hardcoding a fast path as necessary. "Fast from the beginning" is just guessing about the bottlenecks.
And that doesn't mean OOP is definitely good at the authoring task, either. It just happens to be good at kicking the can down the road and letting things work inconsistently, which may be correct in a prototype when you don't know if you're actually shipping that feature, and only poses an issue if you've tied the authoring to the runtime implementation in a deep fashion. Godot doesn't assume this; while it does have hierarchical relationships of objects, it has some boundary points with respect to reuse(scenes and scene instancing) that make the path of least resistance be to make separate authoring and runtime versions of entities, with one spawning the other.
> This is an example of survivorship bias. How many ambitious game concepts have collapsed under performance/architecture issues that lead to productivity-killing refactoring? Impossible to say, but no doubt many.
Probably less than you think. The games industry knows how to wring performance out of hardware. Data oriented design is common in most game engines where it matters. It’s just it’s not usually the gameplay code that is particularly a bottleneck.
There are also plenty of examples of games where the gameplay layer is a perf concern that not only have been released but were big sellers. For example Factorio and City Skylines. It’s just I’m those examples it makes more sense to worry about data model and access patterns for the actual problem at hand rather than try to generalise it with all the attendant problems that causes. Not least slowing down workflows when you don’t actually need it.
Most game engines are also composition based rather than using much inheritance these days.
> This is an example of survivorship bias. How many ambitious game concepts have collapsed under performance/architecture issues that lead to productivity-killing refactoring? Impossible to say, but no doubt many.
I'm reminded a bit of Minecraft, whose infinite and completely mutable voxel world was really novel at the time -- and which was (and maybe still is) the source of a lot of performance woes.
I've been wondering something, though: wouldn't it be possible to implement regular EC-style components on top of an ECS system?
You can't implement ECS on top of EC, but if it's possible the other way around, Godot's argument that most people won't need it would seem a bit weak — just let them use fat components on top of an ECS core, and if/when they need the performance there's still room to push it without side-stepping the whole engine.
You can implement ECS on top of EC. Entitas is and example of a really good ECS on top of Unity’s default EC.
I’m currently writing and designing a serialization/networking library that I’m using to build an ECS framework on top of regular Unity EC. Why not use dots? Well, I hate the restriction of using only blittables for component data, I want to have access to the already existing ecosystem of Unity packages, and the biggest is that I am designing it for networking first. It’s slow going (I’m a dad and I have a full time game dev job), but I’m making good steady progress. My serialization library currently features composition, quantization, no reflection, and no garbage collection. I plan on releasing the first version under the MIT license hopefully in the next couple months.
I have a prototype that I’ve been building to test my stuff. Check it out it’s only 30s.
https://youtu.be/p4v3ZnS2KBM
Your demo reminds me of a problem that M&B 2 Bannerlord had, they created a destructable castle, but couldn’t get performance network enough to sync the destruction (bricks and stone walls) to all players.
Thanks so much for posting these! I did get interested about physics, I recently did Space Engineers scripting and it really is cool to play with all kinds of variables.
After working too long with stateless API:s on the backend and one state container to rule them all react-redux kind of architectures on the front end the OOP code style kind of makes my skin crawl. When I try to learn Unity I find it so hard not to turn my code into spaghetti.
Unity has always been more "ECS" than "OOP" though (traditional Unity has Entities and Components for composition instead of inheritance, modern Unity moves Component data and logic into Systems for performance).
Yeah, kinda. But the term ECS definitely already existed before the "data-oriented revolution" for engines that used components attached to game entities to achieve "feature composition". Not sure what the "S" stood for at the time, probably not "Entities/Components/Systems" (because "Systems" is the new thing that actually matters), maybe simply "Entity-Component System" as in "this is an Entity-Component system".
The only major difference (in regards to code organisation) between Unity's old classes and ECS is that in Unity the logic ("Systems") is coupled with the data ("Components") in the same class.
Entities in Unity are already not concrete implementations (probably just a "handler" ID) as far as the user is concerned. This is pretty much like ECS.
Would either Godot or O3DE be a good choice for a CAD-type application? It looks like Godot deals well with a scene graph which seems like a good way to organize data for that kind of application.
Neither is designed for a CAD engine. CAD uses generally NURBS and a scene graph based around constraints. Game engines are not constraint based but rather about independent behaviour agents interacting using triangle meshes. Quite different.
For NURBS modelling there is OpenNURBS [1], made by the guys who made Rhinoceros 3D, an excellent NURBS 3D modelling program. However, although Rhino is available on Windows and macOS, it is not available on Linux and the authors seem pretty against making a Linux version. OpenNURBS is only available on Windows.
I desperately want open source CAD to be a thing. I would suppose that Freecad is probably a very good starting point. I don't think the lack of good open source CAD is due to a lack of a decent codebase so much as the fact that good CAD software is a very large project and we have just not directed enough efforts towards it. I am speculating however and may be wrong.
Rather than "just" Open source CAD I would like to see Open Source CAD-like applications. Well, at least in my mind CAD is something kind of specific and carries a lot of design assumptions with it.
I feel there is a lot of cool stuff you can build in the space of building shapes using constraints. Like visual programming languages made to visualize mathematical relationships using geometry.
Interesting. In my case I am specifically talking about mechanical design CAD for engineering. We have a huge need for that in my opinion. Freecad might be the closest thing but I suspect it needs more investment.
However what you’re talking about sounds important as well.
> I don't think the lack of good open source CAD is due to a lack of a decent codebase
I think the problem is exactly that. A good constructive solid geometry (CSG) is a difficult thing to make and there are no open source alternatives to the ones powering the mainstream CAD packages.
Closest thing would be a level editor, which is very much a CSG-based CAD program with roots going back to the Quake 1 generation. It's just not geared towards typical production applications where real objects are being machined.
It's hard to avoid the segfaults. I've tried to use it many times for simple projects. Some workflows it's every 10min or so, and often you get into corrupted states where you can tell it's about to happen, but of course if you save you risk your files completely.
It's also slow, onshape in my browser beats it at roughly everything.
Graphics-wise, the assumptions are quite different. Game scenes are a large collection of low-detail objects that are constantly moving and not all visible at once. CAD scenes are a small collection of high-detail objects that don't move except in response to input events.
If the CAD project is big and serious, I would be afraid of eventually hitting some limitation of the game engine that is hard to work around due to such different assumptions.
Both game engines and CAD applications have some type of level of detail node in their scene graph so that zoomed in items are high fidelity and items further are simplified.
I work on an application that uses the geometry kernel from PTC (GRANITE) for modeling and OpenSceneGraph for display. I'm a little worried about OpenSceneGraph because it's 100% OpenGL which feels like it's at the end of it's life and we need to find something built on Vulkan or Direct3D for the future.
This makes little difference for the hobbyist gamedev, but it has ramifications for large projects with many interacting systems. Proper ECS architecture better supports the latter case [3].
[1] - https://docs.o3de.org/docs/welcome-guide/key-concepts/#the-c...
[2] - https://godotengine.org/article/why-isnt-godot-ecs-based-gam...
[3] - https://www.youtube.com/watch?v=W3aieHjyNvw