Why ECS is so underrated?
Posted by CLinkZ-s4h@reddit | programming | View on Reddit | 24 comments
why do many people in game development choose OOP if it is extremely slow? here are the advantages and disadvantages of OOP.
Disadvantages:
- lack of multithreading (systems are very difficult to isolate from each other, which leads to strong dependency and interferes with multithreading)
- cache misses (the CPU often waits for data from slow RAM, because now the CPU is always faster than RAM).
- heavy objects (inheritance in OOP is a very heavy and abstract system that eats a lot of RAM).
Advantages:
- Simple and convenient.
and what about ECS?
Disadvantages:
- difficult, sometimes inconvenient. not recommended for UI
Advantages:
- all the disadvantages of the OOP are solved here.
I know that companies cannot find good programmers who know ECS and as cheaply as possible. But I personally think if you're making a server-side game, it's a good investment. ECS is one of the most performant paradigms that exist in gamedev. Personally, I think ECS should penetrate gamedev a little bit, which will expand the possibilities for creating heavy games that require a lot of CPU resources.
programming-ModTeam@reddit
Surveys and AskReddit-style questions are not allowed on r/programming.
vips7L@reddit
OOP isn’t slow. Dynamic dispatch is “slow” when the compiler can’t inline function calls and has to jump around memory and that’s only when PGO can’t optimize to the actual implementation like what most JIT compilers will do.
However, you need to remember Amdahl’s law; you can get rid of all the dynamic dispatch you want, but it’s not going to speed up shit when you’re waiting on writing to disk or network io to the server.
Hot-Employ-3399@reddit
Neither is a bottleneck for games.
vips7L@reddit
Really? Games aren’t reading assets from disk? They’re not having the server check player locations or hit markers? They’re not saving local state to disk so you don’t lose your progress?
Anyway it’s just an example to show Amdahl’s law.
angelicosphosphoros@reddit
It can be slower due to allocating objects separately, causing frequent memory accesses outside of CPU caches.
Even if you store objects in arrays (e.g. generational arena), sometimes you need only 1-2 fields of the whole object, then accesses to them would cause cache misses again because distance between same fields of different objects would be larger than cache line. In such case, ECS wins because it stores same fields of different objects together.
vips7L@reddit
I never claimed it wasn’t slower. Like everything in programming it depends on context and implementation; for example a cache miss literally means nothing while we’re waiting for the disk or the server to respond or your N^2 loop to complete or the extra hours it takes to implement your perfect code while your competitor has already shipped their product.
As someone else said before micro benchmarks are damn lies.
angelicosphosphoros@reddit
There is also a middleground when you use generational arenas to store your objects and use ids to reference them instead of pointers.
The main problem with ECS is lack of support on language level. Classes and structs are implemented by languages directly and tools (linters, static analysis, debuggers) understand them. ECS is implemented as a library and lack any readable representation in code.
thomasfr@reddit
One or both of those are usually not too complicated to work with.
angelicosphosphoros@reddit
This is basically an additional project(that doesn't bring additional money) for several people to work on full-time. It is just economically unfeasible.
If you want to create a successful project, you need to focus development on the product itself and use existing solutions for things outside of the focus. So if you write the game, you should write the game instead of writing compilers, linters, 3D-editors, etc.
You can support such "side-projects" only if you are huge company and can dedicate a team for developing internal products.
thomasfr@reddit
Either you find the linting important enough for the quality of the code to make it worth writing, if it is not important enough then you probably did not need it.
For a lot of languages it is very easy to write linters because there are good ast parsers so it's not a huge effort most of the time. The really complicated to parse languages are often complicated because of sophisticated compile time meta programming and in that case you can write the macro version instead.
When I create a linter for a single project I typically keep the source of the tool in the same SCM repository as the code that it is linting to decrease the separate project management burden.
As recently as yesterday I wrote a one off linter to support a medium size refactoring to make sure that all newly introduced conventions were correctly followed after the change, really no big deal at all.
gordonnowak@reddit
the fuck are you on about. ECS is standard.
Fiennes@reddit
It is? Do you have a source for that - genuinely curious.
RichoDemus@reddit
I don’t think so, if you go by number of games, play time or revenue I think games that use ECSes as their primary way of handling game objects is a minority
hairfred@reddit
What? I don't think it is, most modern game engines use an ECS pattern of sorts; the pattern is certainly not mutually exclusive with OOP either. I wrote an ECS for a really basic 2D SDL2 engine I was developing years back (we sometimes called them actor component systems) and it used some OOP concepts but to write good code you don't do things strictly 'OOP' or 'functional' or 'procedural' etc. Keep hierarchies flat, avoid large vtables, prefer composition over inheritance, except sometimes you want polymorphic objects (in my case that I could hold pointers to and have some RT duck typing + scripting). At the same time I was reading a good book about data oriented design which applied more of the relational db style to traditional programming (and ECS' / games fits quite well) and it also had some general good advice in terms of cache lines, using pool allocators and I guess inherent / implicit data storage techniques.
I don't believe that the pros / cons listed here are really accurate. I think many patterns can be written in various ways but some naturally lend themselves better to a particular paradigm. ECS and OOP worked really well together for me, it probably had some minor overheads but it made it easier to have a very dynamic system whilst being able to make some base assumptions - this is what makes a good ECS. My engine had a separate system for UI, but it could have been done with the ECS, I just chose to write something more specific because the UI didn't really need the same level of freedom. You don't need to constrain yourself to using 1 single pattern or 1 single paradigm.. you'll end up writing lots of workarounds. My engine had a lot of OOP parts but something like the event system was typically very 'functional' i.e. first class functions for attaching callbacks usually 'lambda' functions, lots of 'closures', 'currying' - all very 'functional' concepts.
Sunscratch@reddit
ECS is not a silver bullet. It’s a great option when you need scale, many simple entities that should be handled efficiently. It falls short when you don’t need such scale, for example when your game has many specialized characters. That’s why engines like UE and Unity provide both ECS as an option.
heavy-minium@reddit
But ECS is quite common in game development. One could argue that it could even more prevalent, but I think the many more implementations are a sort of "precursor" of ECS or "almost" ECS, in the sense that one often has a lookup of entities with unique ids, additional primitive data structures that are compact, and a system that perform operations in bulk on those primitive data structure - compact, cache-friendly and optimal in memory access, the essence of ECS. Applying the ECS pattern on top is just going a bit further than that.
The premise of OOP vs ECS is not entirely correct anyway, it's more like OOP vs Data Oriented Design. And in that sense, Data Oriented Design is very prevalent in the industry.
baconator81@reddit
Keep in mind ECS only deals with a subset of problems OOP deal with. OOP also describes how business logic should be arranged (aka through polymorphism.. etc ) while ecs really only deals with data layout.
beephod_zabblebrox@reddit
for multithreading, bevy comes to mind, since it can differentiate between mutable and inmutable access
BubuX@reddit
It's mostly because it adds complexity and many games don't need it performance optimization (turn based, deck builders)
I had to use ECS in my web spaceship building game among other tricks to keep it performant.
Another benefit is that it keeps data organized into components and things that change data into systems.
Falcon3333@reddit
ECS is used - when it makes sense. OOP is and can be fast too. If you can't write fast/efficient OOP code you probably can't write ECS code anyway.
NeitherManner@reddit
"When there is one, there is many" is the typical slogan for ecs performance, but how often there are 1000 enemies each with same type of components for archetype? Most games I play have at max like 20 enemies all who have bit different components.
tiajuanat@reddit
Serious Sam has entered the chat
JarateKing@reddit
The big performance benefit of ECS only really comes up when you have huge amounts of similar entities. In those cases ECS has really caught on and is the popular option. For most games, the overhead of making a function call to update gameobjects is nowhere near a bottleneck. In that case you may as well stick to what's familiar and slightly easier to reason about.
afl_ext@reddit
Imagine me i did my own ECS and i was happy until i realized the biggest strength comes from storing componey jn per type flat array and updating them separately
And i have a struct “components” in entities that uh is not doing this layout…