2
\$\begingroup\$

I've got a background in C++ but completely new to game dev, Unreal, and ECS.

Recently, I learned about ECS and fell in love with the resulting project structure and theoretical reduction of spaghetti code that could arise as a game project grows. However, Unreal (or most other mainstream engines) have limited or no ECS systems ready to go. As a result, I decided to try to implement what I like to call a Pseudo-ECS on my own within an Unreal project that lets Unreal handle basics like rendering and physics, and the Pseudo-ECS will handle all gameplay logic.

It's similar to a true ECS system in terms of separation of data and logic, however it does not follow the ECS memory layout, entity id lookups, or even querying for that matter. Here's how it's set up:


All components/systems are derived from these 2 ActorComponent classes and live in their respective folders:

enter image description here

When an ECS_Component is added/removed from an actor in the world, that actor is stored in a global queue for the next frame to process.

enter image description here

Every tick, the global queue is processed against a list of registered ECS_Systems and then cleared. Essentially, ApplySystems will be called on every actor that had a change to the ECS_Components that were applied to it.

enter image description here

ApplySystems checks the required ECS_Components for each ECS_System (using a set of 4 int64 bitflags & bitmasks, supporting up to 255 components) and if the actor has those components, then that ECS_System is added/removed from it.

The function is a bit too big to post here. Basically, it loops through all the components on the actor and generates a bitflagged set of int64's. Then it loops through every system in the game and checks via bitmask to see if the actor should use the system.

enter image description here


The result; all system logic only runs on actors that have the required components. When a component is added/removed, the actor gets updated to ensure it has the right systems at all times. And this works! I successfully created basic health, hunger, and follow systems with this.

Here's the thing... obviously, I would be missing out on any performance gains from a true ECS system, however performance is not what drew me to ECS in the first place. That being said, I don't want this system to be a hindrance to the games performance either.

My question is, do you think this Pseudo-ECS system is worth using even without a true ECS memory layout or querying system? I really have no frame of reference to know this...

\$\endgroup\$
3
  • 1
    \$\begingroup\$ If it works in your testing and has adequate performance on your target devices, that is all that matters. I don't recommend basing your technology decisions on an opinion poll of Internet strangers. Some rando could log on here and say this is the best idea ever, or the worst of all time, and neither of those would change the real evidence that you have access to: your profiling results, and your personal experience of how well you enjoy developing in this system. \$\endgroup\$
    – DMGregory
    Apr 15, 2022 at 11:39
  • 3
    \$\begingroup\$ Sure, but that would require finishing my game first. The question comes down to, what are the effects/drawbacks of an ECS system without ECS-style memory layout and are they generally prohibitive? Someone with a deeper knowledge of unreal and ECS I would listen to more so than myself at this early stage of development. \$\endgroup\$
    – mrg95
    Apr 15, 2022 at 18:54
  • \$\begingroup\$ Given that this question went a year without getting an answer, I think that's pretty strong evidence that stress-testing it with synthetic content would be a faster and more accurate way to evaluate this approach. You don't need a full final game, just a few components that you can spam hundreds of copies of in a test scene to measure how well the performance scales. That would let you spot if there's a massive performance cliff at a low level of scene complexity, which could be a deal-breaker, or if you've likely got performance headroom to spare, making the approach viable. \$\endgroup\$
    – DMGregory
    Jul 26, 2023 at 17:02

2 Answers 2

0
\$\begingroup\$

The way I see it, Unreal and Unity are large codebases of licensable engines. And it large toolchain and asset pipeline. The problem is they add a ECS to it which is large refactoring effort and taking in to account how the best iterative implement ECS into it. It is example of how the refactor a finished game engine to ECS which is large undertake. To understand the concept of ECS. Best thing in my opinion would be to dive in the theory. The book Data oriented design? Richard Fabian. Also C++ specific. If your C++ are of high level OOP you would see OO solutions to every ECS problem. C++ multi-paradigm. So I would delve deeper into C++ Functional paradigm support.

Then the biggest mistake is ECS isn’t particle system it is extreme overkill to authentic Pong game. ECS shine wen you have large amount of different game objects. So the benefit arise at often much larger scope of game. From Phong to arena shooter no. A Arma large scale milsim, Homeworld , xseries. Starcitizen. My opinion only then you experience the benefit of pure data oriented entity component system. To me encapsulation in ECS DOD is at level of the systems. Where the logic and data is isolated. And is decoupled.

To me a good example to research ECS to make a 2D game using carrier fleet warfare or Mainbattle tank and armored infantry in WW II setting you have a halftrack truck which is for OOP diamond of dead game object.

A pong game even C++ is overkill I would choose web game in HTML5 Canvas game. With intermediate complex games you get benefit in OOP if you shift from inheritance to component game objects. Often that refactoring within OOP is for most game enough benefit. For asset control and data driven. Asset pipeline your asset tool would be database in it core if you gp full pure dod ECS.
Using Unreal you are bound by their implementation of a ECS. And the type of games it supports. And then it is choice if that suit you game project often it does.

\$\endgroup\$
0
\$\begingroup\$

To start off with, there's no requirement that an ECS needs to adhere to Data-Oriented Design principles. ECS has been around forever (I was working on games with them over 20 years ago, and yes we even called them entity components), just they're also a really good fit for DoD. Likewise, you can implement DoD principles without an ECS (ECS is just one aspect of a pure/full DoD implementation, and you don't need to have a pure implementation to reap many of its benefits).

However, there are a couple of glaring problems with your approach of considering components as data and systems as dependent on specific combinations of components.

Basically, it loops through all the components on the actor and generates a bitflagged set of int64's. Then it loops through every system in the game and checks via bitmask to see if the actor should use the system.

Firstly, how will you handle cases where there can be more than one instance of a data type? e.g. wheels, ammo, etc. If each data type has a specific slot (bit in your bitmask), you're going to need different data types for each wheel (front/back for a motor bike, fl/fr/rl/rr for a regular car, fl/fr/??/??/rl/rr for a 6 wheeler semi, etc.) or ammo type (9mm, 50mm, etc.). If you do have a single data type for such things, how will you know what slot they're meant to go in? This is a pretty big design limitation.

Secondly, if your systems are automagically used based on the components present, you will be further constrained to creating excessive component/slots for every specialization and redundant systems too, and that will limit the ability for game design to share resources. Take for instance a few different weapons, which for the games design you want to all draw from a single ammo type - how will that be achieved, if adding an 'energy ammo' component automatically adds all compatible weapon systems? Which system is used to process the component? Similarly for the wheel case, will you now need to have separate systems for each vehicle type, even though a wheel's a wheel? You're now polluting your ECS systems with checks that an ECS system is meant to avoid.

There are of course solutions to these issues, but I believe they're an indicator that you haven't selected the right approach to your ECS implementation.

\$\endgroup\$
3
  • \$\begingroup\$ Wouldn't the bitset mask only match the complete set of required components? So for your "energy ammo" example, I could have an C_EnergyAmmo component and a C_RifleWeapon component which would match the bitset sought by the S_PulseRifle system but not the S_LaserCannon system which looks for C_EnergyAmmo and C_BeamWeapon, For the different wheel position examples, wouldn't those be a single C_Wheel component on different child objects, updated by the S_Wheel system individually? Then the C_Car component could reference its 4 wheels for systems that need to coordinate them. \$\endgroup\$
    – DMGregory
    Jul 26, 2023 at 13:13
  • \$\begingroup\$ @DMGregory: What about RifleWeapon and SpecialRifleWeapon? Same components, just different properties. For the wheels/car case, the point of an ECS is components should live on an entity - of course it depends on your definition of an entity, but generally that'd be a single gameplay object like a character or a car, not the parts of the character or car (the wheels in this case). Like I say, there are solutions to these issues, such as calling each part of the gameplay object an entity, but those aren't necessarily the right choices. \$\endgroup\$ Jul 27, 2023 at 16:36
  • \$\begingroup\$ If they're differentiated by properties alone then you do not need distinct components or systems to handle them: their differences are encoded in their parameter values (eg. a specialEffect field on the component that's allowed to be blank/specify "none"). A wheel can be an entity that interacts in a larger cluster of entities just as easily as the rifles we've been discussing can be entities carried about by NPC or player character entities, or stored on a weapon rack entity, etc. This is a common approach even in ECS architectures. \$\endgroup\$
    – DMGregory
    Jul 27, 2023 at 17:22

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .