Remix.run Logo
cloogshicer 6 days ago

Can someone point to a real life example or tutorial/guide of the ECS architecture he proposes?

I'd like to learn more about how to implement this.

jayd16 6 days ago | parent | next [-]

The two biggest for-sale engines have their implementations as well as what others have posted.

Unity ECS (has a pretty good general introduction to ECS) https://docs.unity3d.com/Packages/com.unity.entities@1.3/man...

Unreal https://dev.epicgames.com/documentation/en-us/unreal-engine/...

masfoobar 5 days ago | parent | prev | next [-]

While people are likely to hand useful links or videos, I will attempt another method of understanding.

When it comes to organising your code in an ECS-esque fashion, it is much closer to normalising a database except you are organising your structs instead of tables.

With databases, you create tables. You would have an Entity table that stores a unique Id, and tables that represent each Component.. which there would be a EntityId key, etc.

Also, each table is representative of a basic array. It is also about knowing a good design for memory allocation, rather than 'new' or 'delete' in typical OOP fashion. Maybe you can reason the memory needed on startup. Of course, this depends on the type of game.. or business application.

An 'Entity' is useless on its own. It can have many different behaviours or traits. Maybe, if referring to games, you can have an entity that:- has physics, is collidable, is visible, etc.

Each of these can be treated as a 'Component' holding data relevant to it.

Then you have a 'System' which can be a collection of functions to initialise the system, shutdown the system, update the system, or fetch the component record for that entity, etc.. all of which manipulates the data inside the Component.

Some Components may even require data from other Components, which you would communicate calling the system methods.

You can create high level functions for creating each Entity. Of course, this is a very simplified take :-

  var entity1 = create_player(1)
  var boss1 = create_boss1()

  function create_player(int player_no) {
    var eid = create_entity();
    physics_add(eid);             // add to physics system
    collision_add(eid);           // add to collision system
    health_add(eid, 1.0);         // add health/damage set to 1.0
    input_add(eid, player_no);    // input setup - more than 1 player?
    camera_set(eid, player_no);   // camera setup - support split screen?

    return eid;
  }

  function create_boss1() {
    var eid = create_entity();
    physics_add(eid);
    health_add(eid, 4.0)          // 4x more than player
    collision_add(eid);
    ai_add(eid, speed: 0.6, intelligence: 0.6);  // generic AI for all

    return eid;
  }
igouy 4 days ago | parent [-]

So global functions to configure functionality defaults and the functionality may be reconfigured later.

Jtsummers 6 days ago | parent | prev | next [-]

1. You have entities, which may just be identifiers (maybe a u64 used as an index elsewhere) or some more complex object.

2. You have components, which are the real "meat and potatoes" of things. These are the properties or traits of an entity, the specifics depend on your application. For a video game or physics simulator it might be velocity and position vectors.

3. Each entity is associated with 0 or more components.

4. These associations are dynamic.

5. You have systems which operate on some subset of entities based on some constraints. A simple constraint might be "all entities with position and velocity components". Objects lacking those would not be important to a physics system.

In effect, with ECS you create in-memory, hopefully efficient, relational databases of system state. The association with different components allows for dynamically giving entities properties. The systems determine the evolution of the state by changing components, associating entities with components, and disassociating entities from components.

The technical details on how to do this efficiently can get interesting.

Compared to more typical OO (exaggerated for effect), instead of constructing a class which has a bunch of properties (say implements some combination of interfaces) and manually mixing and matching like:

  Wizard: Player
  FlyingWizard: Wizard, Flying
  FlameproofWizard: Wizard, Flameproof
  FlyingFlameproofWizard: Wizard, Flameproof, Flying
Or creating a bunch of traits inside a god object version of the Wizard or Player class to account for all conceivable traits (most of which are unused at any given time), you use the dynamic association of an entity with Wizard, Flying, and Flameproof components.

So your party enters the third floor of a wooden structure and your Wizard (a component associated with an entity) casts "Fly" and "Protection from Elements" on himself. These associate the entity with the Flying and Flameproof components (and potentially others). Now when fireball is cast and the wizard is in the affected area, he'll be ignored (by virtue of being Flameproof) while everything around him catches fire, and when the wooden floor burns away the physics engine will leave him floating rather than falling like his poor non-flying, currently on fire Fighter compatriot.

dkbrk 6 days ago | parent | prev | next [-]

It's a bit of a long read, but I think the best introduction is still this [0] and the comments were here [1]. Yes, it's presented in the context of rust and gamedev, but ECS isn't actually specific to a particular programming language or problem domain.

[0]: https://kyren.github.io/2018/09/14/rustconf-talk.html

[1]: https://news.ycombinator.com/item?id=17994464

joeblubaugh 6 days ago | parent | prev | next [-]

They’re very common in video game programming and visual effects and uncommon elsewhere. I enjoyed this article, though it’s still about using ECS in a simulation / computer graphics context.

https://adventures.michaelfbryan.com/posts/ecs-outside-of-ga...

pjmlp 5 days ago | parent | prev | next [-]

Basically is programming against composable interfaces like COM, Objective-C protocols, and anything else like that, but sold in a way that anti-OOP folks kind of find acceptable, while feeling they aren't using that all mumbo jumbo bad OOP stuff some bad Java teachers gave them on high school.

Most of them tend to even ignore books on the matter, like "Component Software: Beyond Object-Oriented Programming." [0], rather using some game studios approach to ECS as the genesis of it all.

[0] - https://openlibrary.org/books/OL3564280M/Component_software

sirwhinesalot 5 days ago | parent [-]

None of that is what people mean by ECS. ECS is a poor man's relational database. Do you think SQL is OOP too?

pjmlp 5 days ago | parent [-]

People without CS background say a lot, like confusing ECS with data oriented design.

sirwhinesalot 4 days ago | parent [-]

I have a PhD in computer science and I'm also able to stop for two seconds and understand what ECS as used by game devs means. It is pointed out in the talk that the design pattern was used in sketchpad of all things and reinvented in 1998. They call that pattern ECS. It is unfortunate the name is overloaded but that doesn't mean that when they say ECS they're referring to the ECS you are and it is somehow a gotcha since that other ECS is still very much OOP.

They are not talking about that ECS.

pjmlp 4 days ago | parent [-]

Then lets sort this out, point an github repo of your choice for a game engine using ECS and lets discuss the implementation from CS point of view regardling programming language features used for the implementation.

Given that both of us have the required CS background should be kind of entertaining.

sirwhinesalot 4 days ago | parent [-]

Sure, the Bevy engine is the one I'm most familiar with:

- An entity is a 64 bit integer wrapped in a struct for typesafety (newtype pattern). This is a primary key.

- A component is a struct that implements the "component" trait. This trait is an implementation detail to support the infrastructure and is not meant to be implemented by the programmer (there is a derive macro). It turns the struct into a SoA variant, registers it into the world object (the "database") plus a bunch of other things. It is a table.

- A query is exactly what it sounds like. You do joins on the components and can filter them and such.

- A system is just code that does a query and does something with the result. It's basically a stored procedure.

It is a relational database.

EDIT: forgot to link the relevant docs: https://docs.rs/bevy/latest/bevy/ecs/component/trait.Compone.... It is really critical to note a programmer is not expected to implement the methods in this trait. Programmers are only supposed to mark their structs with the derive macro that fills in the implementation. The trait is used purely at compile time (like a c++ template).

There's also flecs which doesn't rely on OOP-ish traits in its implementation: https://www.flecs.dev/flecs/

Either way, it doesn't matter if OOP is used in the implementation of an ECS, just as it doesn't matter if MySQL uses classes and objects to implement SQL.

4 days ago | parent [-]
[deleted]
crabmusket 6 days ago | parent | prev | next [-]

Here's something that I think is in the direction Casey advocates for without being full-blown ECS:

https://gamedev.net/blogs/entry/2265481-oop-is-dead-long-liv...

As I posted on the video itself: https://news.ycombinator.com/item?id=44611240

adastra22 6 days ago | parent | prev | next [-]

Like this? https://devlog.hexops.com/2022/lets-build-ecs-part-1/

cloogshicer 5 days ago | parent | prev | next [-]

Thank you all for your recommendations!

halfcat 6 days ago | parent | prev [-]

Look for data-oriented design [0] (not to be confused with domain-driven design) in addition to ECS.

[0] https://www.dataorienteddesign.com/dodbook/