This series is a response to the request of many people and is thought on the
one hand to explain the design and ideas behind many choices in
EnTT, on the
other to show how this library can be used to develop something from
In no case is the aim to teach programming a game (since I’m not the right person to do it) but I’ll try to show how the various
EnTT modules can be
combined to achieve something that works in this sense. I’ll probably focus on
something simple because I’m not that skilled overall and the goal is to explore
the various features of the library, not to make the game of the year one step
at a time. Afterwards, nothing excludes that the series takes a turn towards
more complex applications, just for the sake of continuing to write it. :)
A library of libraries
Let’s start with the basics: what
and how I recommend using it.
Unfortunately, I’ve read or been told several times that
EnTT is very big.
I’d like to debunk a myth: it is not.
EnTT is a library of libraries, mainly
completely unrelated to each other and usable independently.
So, why didn’t you create many different projects instead? Good question.
My goal has never been to have one or many high-rated projects on GitHub. My aim was and is to have something that I can clone and that offers me all together those tools that I’ve developed and continue to develop over the years.
The alternative was to make
EnTT a project full of submodules. However, I’m
not a supporter of submodules. Honestly, it had to be comfortable for me first
of all and I find this form much much easier to use and to work with.
This doesn’t prevent users from cloning the repository and using only a small
part of it.
I’ve seen many projects that rely only on the ECS part or only on its runtime reflection system, even someone who clones it and then uses only the delegate and little else.
This is… just… fine? Using a class from
EnTT won’t tie a project to all
the other parts of the library.
So there are no dependencies between modules?
It depends on the definition of dependencies actually.
Literally all files refer to the
core directory for definitions such as
ENTT_NOEXCEPT. That is to say, a single configuration file
(or kind of) to rule them all.
If this type of dependencies is a problem and not acceptable, then yes, this library is not for you. If this is fine instead, the other dependencies are likely irrelevant to you anyway. They are most of the times things that are convenient but configurable and can be by-passed.
For example, the default pool in the registry offers signal for when a component
is created or destroyed. To do that, it uses the signal class from the
Is this an inevitable dependency? Definitely no. The default pool type is fully customizable. Signal support can be removed or replaced with your own class, thus removing the dependency on the built-in signal class.
Then there are modules that are completely unrelated to the rest of the library.
An example of this are many of the classes in the
On the other hand, some types make use of features offered by other modules and therefore depend on them. For example, the
registry class makes use of the
internal RTTI system (
core/type_info) and would not work without it. In these
cases, although the dependencies are minimal, these are things that would have
been replicated had I chosen to create separate repositories.
So, at the end of the day, the answer is that yes, there are some dependencies. A very few ones though, mainly due to things closely related to the module in use and such that you would have wanted to have anyway.
If there are few dependencies, why do I import everything every time anyway?
Most likely because you’ve decided to use the single include file or to include
entt.hpp from inside
src. Well, don’t and life will smile at you.
These files are intended for small tests or for online use. For example, the single include file was a convenience for testing and reproducing errors on godbolt. And I say was because thankfully godbolt now includes EnTT as a library and it’s possible to use the files inside
src directly, making it much easier to work with.
The only reason I personally see for using the single include file or
directly is to increase parsing and compile times, without any real
EnTT is designed as a library of libraries and I constantly try to insert in
each file the minimum necessary for the functionality that belongs to it.
Even including only registry.hpp in my headers doesn’t help either
Likely, in fact you shouldn’t most of the time.
A long time ago now, a very smart guy suggested filling
EnTT with what I would
call forward files and I’ve been keeping them up-to-date ever since.
For example, if your header only refers to a generic reference to a registry
const entt::registry &), why include
registry.hpp at all, risking
that every change will propagate to who knows how many cpp files?
entt/entity/fwd.hpp instead next time. Do it for all your
headers, do it wherever you need it, do it for every
EnTT class you find
EnTT is a header-only library and I personally have no problem using a super
optimized, tested and well known
std::vector rather than reinventing the wheel
by offering something worse and with a dubious interface, just because the
gamedev world often wants it.
Of course, this doesn’t mean that we should be crazy or deny one of the most critical aspects of C++, that is, compilation time. However, we can do a lot to mitigate the problem as long as we know the right means.
Believe me, I don’t like to heat my room with my laptop and that’s why I’m in a constant process to reduce inclusions, instantiations and so on. Though, the first step is to start using the right tools that already exist!
Oh, and anyway EnTT is too modern C++, it doesn’t work on consoles
Really? I thought Bedrock ran on consoles. :)
Why do we keep talking about this point all the time? It works, that’s it, C++17 is widely accepted nowadays, you don’t have to worry about it anymore.
Okay, you convinced me, where do I start?
From the next posts (which I’ll try to keep short for the whole series, trying
to publish frequently).
Next time I’ll try to give you an idea of what’s really in this library. Module by module, just a quick look. Then we’ll delve into one module at a time, one class at a time, one design choice at a time and one example at a time, with some explanations on lesser known C++ techniques used here and there.
This is just the beginning of this journey. I’ve waited a long time, many have asked me about this, finally it’s time to start it.
Let me know that it helped
I hope you enjoyed what you’ve read so far.
If you liked this post and want to say thanks, consider to star the GitHub project that hosts this blog. It’s the only way you have to let me know that you appreciate my work.