QuesterDesura

C++ Need some help with the Entity Component System

Recommended Posts

Hello,

I'm currently trying to make a Minecraft Clone using OpenGL and using the ECS pattern. I didn't quite understood yet why I need the "Systems" when I already have components. My current structure I'm planing to use is this:

 VBVcfIz.png

My main problem is that I don't really know how to store the Entitys. If I for example want to attack and check which Entity I did hit then I would need to iterate through all Entity stored in my vector<GameObject> in the World Class and check if it got the Health Component and then decrease the health. Which doesn't seem very clever to me as I will probably have multiple thousands Entitys alone by the Blocks in the chunks. I did read some stuff about Handlers but didn't understood how they work or should solve the problem of iterating through all Entitys who could possible need to be called to Receive Damage. Can anyone help me?

 

Thanks 

Share this post


Link to post
Share on other sites
1 hour ago, QuesterDesura said:

Which doesn't seem very clever to me

Yeah it isnt, but this has nothing to do with ECS.

In a "proper" engine you have spatial structures that have all physical entities inside it with their collision bodies (that can be as simple as a box, or a bunch of other primitives attached together). This is often handled by the physics engine, you can check out Bullet for instance (if you're doing a 3D game) or Box2D (if you're doing a 2D game) to see how they work and how they're used... Or you could go down the path of trying to implement your own spatial structures, in which case you'll never finish anything. Your call.

Anyway, these structures can do neat things like you pass it some primitive, and it tells you all the stuff that collides with it.

In this particular case, what you'd do is to issue a query into that spatial structure, our primitive being an infinite ray (which would require for us to check the distance later) or a line segment (from the player up to the bullet's range), pointing in the direction the player  is firing. The physics engine/spatial  structure will tell you what entities did you hit. 

With that information, you could check if those entities have a health component, and if any of they do, decrease it.

1 hour ago, QuesterDesura said:

I didn't quite understood yet why I need the "Systems" when I already have components. 

Because in "pure" ECS, components have no logic. You implement it in the systems. That player class with a "process input" method? That'd go into an InputSystem that processes entities with Player components (and **only** those).

I suggest you google for "ecs library" and see what it turns up. No sense in reinventing all of this when you can draw inspiration from tons of ECS libs that have been spawned.

 

Edited by TheChubu

Share this post


Link to post
Share on other sites

There are many different architectures people call "ECS", because it's very hyped and popular right now, few people know why they need it, and many implementations of it are terrible.

It's not one design pattern, but a buzzword that acts as an umbrella for one or two designs that I personally think are nice, and a dozen more designs that are just terrible. Some really intelligent developers go a step further and say all ECS architectures are terrible. =)

22 minutes ago, QuesterDesura said:

I didn't quite understood yet why I need the "Systems" when I already have components.

As TheChubu mentioned, in some ECS architectures, components *only* hold data, and Systems contain the logic that transforms that data. Other ECS systems, that I wouldn't even call "ECS", put the logic in the components and lose half the reason why ECS exists in the first place.

24 minutes ago, QuesterDesura said:

If I for example want to attack and check which Entity I did hit then I would need to iterate through all Entity stored in my vector<GameObject> in the World Class and check if it got the Health Component and then decrease the health.

Yes, that sounds terrible.

I don't even want components of different type put in an array together - it doesn't seem worth it to me without a compelling reason (here's me explaining why I dislike it). I wouldn't want actions like 'IAttack' to be components either, nor would I have 'Player' responsible for drawing the GUI (depending on what you mean by GUI - if it's a name or healthbar over his head, I would - but if it's a HUD or menu widgets, I wouldn't).

I probably wouldn't make Blocks into entities - the blocks need to be highly optimized since you'll have huge numbers of them, and it'd be better to implement something special just for them.

 

In Minecraft-like games, there's really only a few different types of objects:

  • Blocks - As mentioned, special care needs to be given to these because of how many there are.
     
  • Special "blocks":
  • Wall switches (activated manually)
  • Floor switches (activated on-touch)
  • Doors
  • Arrow trap, spike floor trap, spike floor, etc...
  • Moving platforms / elevators
     
  • Monsters
  • Players
  • Projectiles (arrows, fireballs, etc...)
  • Items in the world (separate concept from the items in your inventory).

Essentially, I'd make two different classes:

  • Block (for all regular blocks - it'd probably cover 99% of all your objects)
  • Entity

'Entity' would handle all the other cases: special blocks, in-world items, projectiles (unless there are alot of projectiles - inwhich case, handle it specially), and monsters and players. They all share more in common than they don't:

  • Solid: Monsters, players, most special blocks (any that aren't solid, just have a "bool solid = false" or a empty bounding box)
  • Does stuff on touch: Monsters, projectiles, floor switches, items in world.
  • Does stuff on hit: Monsters, projectiles, wall switches, special blocks, etc...
  • Visible: All (any that aren't, just have a "bool invisible" or an empty 3D model)
  • Has health: All? (indestructible entities, if any could just be given a bajillion health).

I don't think components are needed here. Instead I'd change their behavior mostly by passing in parameters, including functors. Or if really needed, derive from a base class - or just implement specific behavior as abstract classes, contained by Entity.

Sure, this will all work perfectly fine in a component system (Solid, Visible, Touchable, Hitable), but component systems cost alot more code complexity, so if I was to pay for that complexity, I'd want to be sure it is actually worth the cost of a full ECS architecture.

Share this post


Link to post
Share on other sites

So if you don't want to make all Systems derive from a base class how should they be called then? Writing them all out manually or loop through them when having them all in a vector doesn't seem to be much difference for me.

When I make 2 Classes Block and Entity would you put them in 2 vectors where are Blocks/Entitys are stored? I was thinking bout making vectors for the 4 Areas in a Cartesian coordinate system and then I can access blocks with their position as a index and when I want to check for Raycasts then I can just take the player position and directly access all blocks in a radius of x and check if they are hit.

Share this post


Link to post
Share on other sites

Please oblige me and forgett about "GameObject". This is an approach I hate Unity for bringing it into the game because you do not never ever need something as a GameObject in a specialized game. What you should have is some set of Subsystems like Rendering, Logic, and Physics each has a list of specialized classes (no! GameObjects) like a combination of Matrix, Mesh and Texture (Rendering), a combination of Position, Bounds, Gravity, Force (Physics) and a combination of Healt, logical Inventory (Logic). Evrything may be connected due to a connector class holding 3 pointers to each of its connections to keep a maintainable structure of an entity for the game but thats it.

Rendering does not need to work on the logic, moving players does the Input System, moving NPCs does the AI Systemoperating on coresponding classes. Use some kind of polling or event based update routine to keep your game running.

In Minecraft, the Voxel Engine has no information about a single block until it was created as part of a querry into the terrain system. You never have single blocks stored as objects but a data managing unit that maps chunk data into visual and logicall data. A querry is given into the system to check for possible actions performing when a player hits the input button and on the case of mining or placing a block, some data is written into that chunk and rendering is updating the mesh to remove the texture/vertices from that position and have the underlying block "become visible".

I have already worked on some games that made use of modifying there environment by building, or growing

Share this post


Link to post
Share on other sites
1 hour ago, Shaarigan said:

Please oblige me and forgett about "GameObject". This is an approach I hate Unity for bringing it into the game because you do not never ever need something as a GameObject in a specialized game.

Many, many games had some concept of a GameObject long before Unity came out. It's often called different names, of which Actor or Entity are perhaps the 2 most common.

This doesn't stop you having specialised objects which subsystems can access. For example, your Rendering system can render Meshes (like you said), but the GameObject/Entity/Actor can be responsible for registering its mesh with the Rendering system.

 

To the original poster - for a combat system you might normally need 2 components for things that can get hit - a Collision component to mark the bounds of the object, and a Damage component to track damage done to the object. You can slice and dice this process however you like, depending on which component-based approach is most appealing to you: get the damage component from the collision component via an entity, have a system that returns only matching pairs of collision/damage components, etc.

Ultimately though, you're not going to want your blocks to be component-based entities anyway, as you will have far too many blocks for this to be a efficient way to work. So you'll probably want to handle mining and digging as a special case. So you'll need to ask yourself how much benefit you're going to get from these components.

Share this post


Link to post
Share on other sites
On 9/10/2017 at 3:25 AM, QuesterDesura said:

So if you don't want to make all Systems derive from a base class how should they be called then? Writing them all out manually or loop through them when having them all in a vector doesn't seem to be much difference for me.

The end-generated code isn't different, but the code itself is significantly different.

As you know, in programming there are many different ways to get the same result. But different ways of coding can have different pros and cons they tradeoff (and it's not zero-sum either - some are genuinely better, others genuinely worse) - the code design affects their execution speed, memory usage, development time, compile time, convenience vs amount of boilerplate required, ease of debugging, ease of expanding, ease of learning/understanding, ease of reasoning about after having learned it, and so on, even when the final output is the same.

 

<opinion>

My issue isn't that the end-result is different (it's not), but rather that one method actually has more cons than I can justify to myself, without any real gains, and makes it a little harder to expand the architecture in certain ways, as development continues.

In the thread I linked, someone asked a similar question and I gave some concrete examples, but to summarize a two key points:

  • Forcing a consistent interface on unrelated classes puts unnecessary constraints on how the individual interfaces are designed and used.
    Hodgeman gave one example, and I gave the Uncharted 2 example. For me personally, when I am putting constraints on an interface via inheritance, I find it hard to notice when the class isn't a suitable fit, because I've already made the assumption that it should be inherited - so it's hard to catch myself at it, hence my pro-active defense against it - i.e. I better justify it to myself in advance, because if I assume it is justifiable without cause, I have trouble remembering to question the justifications afterward.
     
  • Manually calling the systems makes their execution order clear and explicit.
    It's slightly easier to debug and optimize (including easier to parallelize). And being more straightforward, it's much easier to comprehend and reason about, helping other coders - or yourself in the future - understand what's going on. It's also less code. You don't gain anything of real substance from making them inherit, but you do lose some real benefits.

Others absolutely disagree with me. I had a link to a thread somewhere giving an alternative view, though I can't place my hand on the link.

I should also clarify that there are absolutely use-cases for components and component systems where it *does* make sense for the components to inherit from a base class. But at the level of abstraction we are talking about here, where the ECS is containing things as unrelated as Graphics and Physics, I've never been convinced that the actual benefits sacrificed on that particular altar of abstraction gain any benefit worth the cost.  =)

</opinion>

Quote

When I make 2 Classes Block and Entity would you put them in 2 vectors where are Blocks/Entitys are stored?

Yeah, I'd put them in separate containers. Entities would likely be in a vector, possibly with an unordered_map to redirect EntityID's to the vector's elements, if required.

For blocks, I'd start off with a 3D array of chunks with each chunk being a 3D array of blocks, and only do something cleverer if needed.

For example, subdividing the world into 16x16x16 chunks of blocks, to cull or stream them quicker.

By "3D array", I actually mean a regular 1D array (std::vector or std::array) to you index into as if it were 3D:

arraySize = (width * height * depth);

arrayIndex = (x) + (y * width) + (z * height * width); //Usually tossed into a convience function.

 

 

Share this post


Link to post
Share on other sites
On 9/9/2017 at 7:33 PM, TheChubu said:

That player class with a "process input" method? That'd go into an InputSystem that processes entities with Player components (and **only** those).

Just wanted to point out you may want the InputSystem to operate on the entities which contains an InputComponent.  This way you can control things other than just the player (like a homing missile, or a remote control car, etc.).

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now