🎉 Celebrating 25 Years of GameDev.net! 🎉

Not many can claim 25 years on the Internet! Join us in celebrating this milestone. Learn more about our history, and thank you for being a part of our community!

Is my understanding of ECS correct?

Started by
28 comments, last by Acosix 4 years, 11 months ago
2 minutes ago, Acosix said:

No, convention isn't a matter of a programming style, but best practices made by the inventor of the C++ programming language, Bjarne Stroustroup and the ISO C++ standard committee, which adds a new standard every 3 years that adds new functionality, deprecates bad functionality and 3 years after deprecation deletes the deprecated; and in which Stroustroup has participated many times.

To summarize ISO C++ standards(example years of every-3-year publication are 1998/2001/2004/2007/2011/2014/2017 and the next one is 2020),  are not about the random common programming practices, but adding functionality and correlated best practices.

I appreciate your willingness to discuss this, but I think we might be talking past each other :) I'm not sure what you're trying to convey with the above post, or what it is exactly (if anything) that you're objecting to.

What drew me into this conversation was this quote of yours from earlier:

"A struct can not be an object."

Assuming a colloquial interpretation of this statement, it's false with respect to C++, and I felt it was worth correcting. If you now understand that the above statement is incorrect and are just arguing for conventional usage practices, then I think the question is resolved because convention was never the issue.

Advertisement

Well last try...if you'll want to stop the discussion after this post, be my guest :P

I tried to say a struct can't be as useful as a class, when making an object.

Why? Well...the C++ was for objects so a struct can not be a real object.

Take a look at it like this: A struct can be an object.

But struct is deprecated. It makes it easier to miss the point of data encapsulation.

Was I clear this time?

 

 

You use structs to connect data, but no functions. struct is for data structures, class is for making objects.

On another note, it confuses the hell out of me when someone uses classes and structures in the same project.

By the way in Visual Studio 2019 when making a new class from the Class Explorer can be done, while there is no "Struct Explorer".

On 6/26/2019 at 9:11 PM, Hashbrown said:

I'm currently playing around with ECS but was wondering if my understanding of ECS was correct. Based on what I've understood so far:

  • Entities: Are structs and only hold an id that identifies it.
  • Components: Also are structs, but holds properties that describe said component. Example: position (vec3), hp (float), etc. ***Also stores a reference to the entity it represents?
  • Systems: Functions that act upon components. If I need to update my Position Component, a system would do that.

My questions so far:

  1. Should components also store a reference or id to the entity it represents? I'm asking this after reading an article where the author stored an array of components within the component struct. I was under the understanding that entities and components should be treated independently.
  2. Should I keep an array for each component and loop through them in my main loop. I'm very confused about this part. In oop I would just put all gameobjects in an array and loop through them.

I also wrote some pseudo code showing what I think the whole thing should look like. It's very Rust...but the code is straight forward. Thanks for reading btw:



MainLoop

    UpdateTime()

    FixedUpdate
        UpdateSystems
            UpdatePositions() // System: Loops through all position components and updates them
    EndFixedUpdate

    RenderUpdate
        UpdateSystems
            UpdateRenderables() // System: Loops through all Render Components and draws
            UpdatePostprocessingSystems()
    EndRenderUpdate   

Loop MainLoop


// Components
struct Entity {
    id: u16, // unsigned integer 
}

struct TransformComponent {
    entityID:   u16,  // Reference to entity
    position:   Vector3,
}

struct RenderComponent {
    entityID: u16,  // Reference to entity
    meshID: GLuint, // Reference to mesh
}

// Should I keep arrays of each kind of component seperatly? 

// Systems
fn update_tranforms () {
    // Loop array of TransformComponents
    // Apply physics to position property 
    // Input logic: aka if (Input.rightArrow) blah.blah.blah
}

fn update_render_components () {
    // Loop array of render components 
    // Draw using meshID in RenderComponent
}

 

Two things to notice here: @Zakwayda See how the OP uses the word for struct for making a data structure?

Well personally the word struct reminds me making a data structure... not an actual object(hence: OOP).

And this post + quote goes to @Hashbrown too.

Quote

I tried to say a struct can't be as useful as a class, when making an object.

But it can be, because it has all the same functionality. It seems like what you're trying to say is that it's unconventional to use 'struct' in certain circumstances (which is true).

Quote

Why? Well...the C++ was for objects so a struct can not be a real object.

A struct can 'be a real object' by definition, because struct has all the same functionality as class. Again, what you're talking about seems to be convention.

Also, I'm not sure that C++ is 'for objects'. It supports OOP of course, but it's a multi-paradigm language (the very topic of this thread, ECS, could arguably serve as an example of that).

Part of the confusion may be that you seem to be using 'can/cannot' when you really mean 'should/should not'. For example, the statement 'structs cannot be used to create objects with encapsulation' is false, but the statement 'structs should not be used to create objects with encapsulation' is a matter of opinion and convention that you could make a plausible case for.

Quote

But struct is deprecated.

I'm...gonna have to see a source on that one :) Why do you think struct is deprecated?

Quote

Two things to notice here: @Zakwayda See how the OP uses the word for struct for making a data structure?

Hashbrown said that was pseudocode (you'll notice it's not valid C++), so I'm not sure what relevance the use of 'struct' has there. Even if it were C++ though, that usage would be consistent with common convention, which no one in this thread has disputed.

As for the video, the presenter basically says what I and others have been saying, which is that the only functional difference is default visibility and any other differences are a matter of convention.

Again, I do appreciate the engagement! We still seem to be going around in circles though, because what you're saying either seems to be incorrect (like struct being deprecated) or in agreement with what I and others are saying (which is that aside from default visibility the differences between class and struct are matters of convention). So aside from the (I think) incorrect statements...we agree I guess? :)

10 minutes ago, Zakwayda said:

But it can be, because it has all the same functionality. It seems like what you're trying to say is that it's unconventional to use 'struct' in certain circumstances (which is true).

A struct can 'be a real object' by definition, because struct has all the same functionality as class. Again, what you're talking about seems to be convention.

Also, I'm not sure that C++ is 'for objects'. It supports OOP of course, but it's a multi-paradigm language (the very topic of this thread, ECS, could arguably serve as an example of that).

Part of the confusion may be that you seem to be using 'can/cannot' when you really mean 'should/should not'. For example, the statement 'structs cannot be used to create objects with encapsulation' is false, but the statement 'structs should not be used to create objects with encapsulation' is a matter of opinion and convention that you could make a plausible case for.

I'm...gonna have to see a source on that one :) Why do you think struct is deprecated?

Hashbrown said that was pseudocode (you'll notice it's not valid C++), so I'm not sure what relevance the use of 'struct' has there. Even if it were C++ though, that usage would be consistent with common convention, which no one in this thread has disputed.

As for the video, the presenter basically says what I and others have been saying, which is that the only functional difference is default visibility and any other differences are a matter of convention.

Again, I do appreciate the engagement! We still seem to be going around in circles though, because what you're saying either seems to be incorrect (like struct being deprecated) or in agreement with what I and others are saying (which is that aside from default visibility the differences between class and struct are matters of convention). So aside from the (I think) incorrect statements...we agree I guess? :)

Should is a better word. But what should be done is equally important. It is not must in your case but can and that is not a grammatical relation.

It is a multi-paradigm language but should be combined. Which is why it is very important.

Quote

The C++ language features most directly support four programming styles: • Procedural programming • Data abstraction • Object-oriented programming • Generic programming However, the emphasis is on the support of effective combinations of those. The best (most maintainable, most readable, smallest, fastest, etc.) solution to most nontrivial problems tends to be one that combines aspects of these styles. 

Bjarne Stroustrup, C++ Programming Language, 4th Edition, page 11

inventor of the C++ language and part of the ISO C++ standard committee for C++11(2011) standard

I think we're still talking past each other, and I'm still not sure what your objection is or what you're trying to convey. You've cited Stroustrup several times - seemingly in a way that suggests you feel his quotes support whatever case you're trying to make - but everything you've quoted from him seems perfectly consistent with what I and others have said, so I'm not sure what the quotes are intended to communicate. Also, you haven't responded to questions about dubious factual claims (such as that struct is deprecated), and the dubious factual claims were really why I joined the conversation in the first place.

Anyway, I feel bad for letting the thread drift off topic, so I'll bow out at this point, at least in this thread. I'd be happy to continue the discussion elsewhere though (e.g. in a new thread dedicated to this particular topic) if the opportunity arises.

On 6/28/2019 at 4:39 AM, Hodgman said:

OOP Inheritance view of ECS -- (n.b. don't ever do this :( )



class IComponent {};
class Entity { vector<IComponent> components; }

class HitpointComponent : public IComponent { int hp; }

Entity e;
e.components.push_back(new HitpointComponent());

 

Just to be awkward, I'm gonna enter a counterpoint to this, aimed more at the original poster than at Hodgman who doesn't need my advice. :)

There are some good reasons to say "don't ever do this" regarding code like the above, but both the Unreal Engine and the Unity Engine both work pretty much this exact way. They don't meet the more rigorous definition of what people mean by an 'ECS' - they're definitely component based systems but in a looser way. However, architectures like these have successfully supported shipping thousands of games. They work.

Short story - until recently, the 'pure' form of ECS was mostly the domain of idealistic bloggers and tinkering hobbyists, much-discussed on forums but rarely used in real world game code. The first big example of this changing was when the Overwatch team started discussing their technology and said it was based on an ECS system. You can (and should) watch the video on this (see bottom of this post). But what's this, at 4 minutes in?

image.png.a7567ace64b16ee2e15f48a08b967991.png

Looks like each entity has a list of pointers to subclasses of a base component! Exactly what everyone says you shouldn't do!

Okay, fine. But what does the actual game logic look like?

image.png.d6deae0e04a7c159d96fa15c3767704b.png

So we iterate through one component, and use a Sibling function to get related components. In other words, their game logic explicitly relies on these connections between components as handled by the aggregation under an Entity. (Also, that's a member function on a Component, in addition to the Create member in the diagram above. So much for the idea that these are plain data objects.)

We don't know how they implemented the Sibling function but it doesn't matter that much - both the implementation and the gameplay code that uses it isn't going to end up looking much different from:

  • Unity - where you use GetComponent<ThatComponent>()
  • Unreal - where you might use GetOwner()->FindComponentByClass<ThatComponent>()

This approach is ugly but it works. That's why people keep coming back to it. :) You can't get away from the need to operate on multiple components at the same time to handle game functionality, and all the different approaches are really just different facades over this fact.

So what you need to consider is this:

  • What is my gameplay code going to look like, once I move past the toy examples where systems only operate on 1 or 2 components? What do I want it to look like?
  • How can I have safe, efficient, and convenient access to components, especially when entities and components may be getting deleted at runtime? Am I perhaps going to lose more performance on array-shuffling/complex indexing/tuple-building than I gain from any other aspect of the architecture? Do I know enough about my game to understand the tradeoffs?
  • Do I have enough knowledge and motivation to solve this problem properly, or should I maybe just focus on whatever is easiest to make a game?

 

 

 

To get back on topic I don't think I know everything about ECS but to answer the poster of the topic the "most important" question he needed(I believe) I say "thumbs up" for a job well done on learning ECS. You might know more about the topic, but it was a good effort, any way...to answer the question "I think" you got it right.

This topic is closed to new replies.

Advertisement