4 ms·
The weirdest thing is that the ECS as a way of building a game is inherently object oriented. You take a set of components and compose an object called an entit
by meheleventyone 5y ago
The weirdest thing is that the ECS as a way of building a game is inherently object oriented. You take a set of components and compose an object called an entity. The components on the entity define not only it's data but also it's behavior by the set of systems that act on the corresponding components. And you can take these object definitions and inherit them to add additional behavior or change the existing behavior by adding more components to the new definition.
Then if you solve the entity communication conundrum with message passing and don't allow entities to directly access one another's data you basically have all the elements.
- professoretc 5y agoECS is really just OOP with dynamic multiple inheritance: an object can inherit from multiple base "classes" (with "components" providing the data and "systems" providing the code) and this inheritance structure can be changed at runtime, by adding/removing components. Everything else (struct-of-arrays vs. array-of-structs) is just low-level implementation details. When I implemented a variation on ECS for a game I'm building, I did exactly as you suggest, re, message passing: components receive and respond to messages but their implementation is hidden.
- klodolph 5y agoInheritance is one way of describing it but I don't think the term really fits. An object is composed of multiple components, and the composition can be changed at runtime. Saying that the object inherits from multiple base "classes" seems like it just makes the concept less clear. Some languages have class-based systems with inheritance: one class inherits from another, and methods implemented in the superclass can be used in the subclass. Some languages have prototype-based systems with inheritance: one object inherits from another, and methods implemented in the prototype can be used in the object. Component-based systems don't really fit my mental model of inheritance here.
- ratww 5y ago> ECS is really just OOP with dynamic multiple inheritance It's composition, not inheritance.
- professoretc 5y agoTechnically, it's neither. Unless your programming language directly supports ECS, you're not going to be implementing the relationship between entities and components as either proper inheritance or a collection of data members, because neither of those can be changed dynamically.
- ratww 5y agoNo, "technically" and in all other regards, it's composition, plain and simple. There's nothing special about composition that it requires language support, or that it has to be static for it to be considered composition. You can implement dynamic composition in OOP simply by having a List of components, and that's how many games that don't use ECS did and still do. Composition has absolutely nothing to do with inheritance or with requiring static data members. Unlike you're claiming, the relationship between entities and components definitely does exist in ECS, just not in an OOP way, because ECS is not OOP (even though ECS can be implemented in any language).
- Bekwnn 5y ago> The components on the entity define not only it's data but also it's behavior by the set of systems that act on the corresponding components. And you can take these object definitions and inherit them to add additional behavior or change the existing behavior by adding more components to the new definition. This seems to miss what ECS actually is, unless you're just referring to the old-school way of doing entity components and not the data-oriented way. Data-oriented ECS way of doing things is to separate state and behaviour. Entity components essentially become structs where their only behaviour is potentially some getter/setter utilities. Behaviours are then state-less systems (just functions, essentially) which act on a set of components. For example, a PhysicsUpdateBehaviour might take in a RigidBodyComponent and a HealthComponent to perform a physics update and apply physics/fall based damage. The main benefit of ECS (imo) isn't even really performance. It makes code in complicated game projects much easier to manage by clarifying the game loop and by making it much more obvious how and when entity state is being modified. It's the kind of thing that potentially complicates a smaller project, but makes larger more complex projects easier to manage. This Overwatch GDC talk is the best breakdown/example of data-oriented ECS in a AAA game that I know of: https://www.youtube.com/watch?v=W3aieHjyNvw https://www.youtube.com/watch?v=W3aieHjyNvw
- meheleventyone 5y agoI know what an ECS is. Components are decoupled from systems (not not visa versa) but the actual behavior of an entity is defined by the set of systems that run on the set of components so in that sense the set of components defined what the Entity is including it's behavior. An Entity is defined in terms of it's data and it's data brings along behavior.
- dkersten 5y ago> You take a set of components and compose an object called an entity. That’s an overly broad definition of “object”, since under that same definition a record type (C struct) or any other blob of memory is an object. In the common type of “components only store data” ECS, the entity is an ID (think a foreign key) that connects multiple records together and systems are independent functions (they are not tied to nor live in an entity) that operate on collections of subsets of these components. That sounds a lot more like old school C-like procedural programming to me than it does like OOP. There’s more to OOP than the data attributes a class contains (eg the associated methods) I suppose it depends on your game engine and your ECS, but since entities don’t contain logic, it’s the systems that communicate between each other (either by sending messages or by accessing the other entities components or by just calling functions of other systems). This isn’t all that different from different parts of a procedural program communicating. Although I do personally think that making a system be an OOP object does makes sense, but it doesn’t have to be. With that said, it seems pretty common in games to use a component system that isn’t “pure ECS” (like the default Unity components prior to their new ECS), which definitely seems like typical OOP to me, just decomposed a bit more.
- meheleventyone 5y ago> That’s an overly broad definition of “object”, since under that same definition a record type (C struct) or any other blob of memory is an object. I think that's because you seem to have stopped at the second sentence the rest is important as well. I'm also talking about a level above the ECS implementation. What is the running thing actually doing. > With that said, it seems pretty common in games to use a component system that isn’t “pure ECS” (like the default Unity components prior to their new ECS), which definitely seems like typical OOP to me, just decomposed a bit more. Yes this also models much the same thing at runtime.
- dkersten 5y agoHow is the running thing operating on components any different from functions in a purely procedural language like C operating on records/structs? > Yes this also models much the same thing at runtime. In a different way, though. It also generally misses out on the data-oriented benefits of an ECS.
- adamdusty 5y agoSure ECS is object oriented in the same way C99 is. Yeah, technically you are building up some OOP functionality, the same way you emulate constructors and instance methods in C by making functions to init data structures and functions that take references to a struct to modify it's data. That doesn't make C object oriented. In ECS you are decoupling data from behavior, which is basically the entire paradigm of languages like rust and go. You could argue that by defining systems in a way that they run on certain components you are defining behavior and data in one, but I think that's a stretch. It clearly differs from OOP when I have 2 entities with components that have overlapping and non-overlapping systems. If e1 has components c1 and c2, and e2 has components c2 and c3, and c1 and c2 are used in system s1 while c2 and c3 are used in system s2, I don't see how you would model that with OOP without adding data to classes that don't need it. In OOP both e1 and e2 would need all the logic from s1 and s2, or needlessly specialized versions of s1 and s2. Which would be solved via inheritance (either class based or interface based). In ECS your data exists in an array of components and any part of your program can operate on any component however it wants. I've never needed message passing for anything I've worked on. That's not to mention that the main benefits of ECS have nothing to do with language paradigm. ECS main advantage is cache coherency and easier parallelism.
- meheleventyone 5y agoYou're too worried about the underlying implementation. Think a bit more about the runtime expression in terms of the resulting Entities and how the set of components linked to them defines data and behavior and what you could do conceptually to extend that. > That's not to mention that the main benefits of ECS have nothing to do with language paradigm. ECS main advantage is cache coherency and easier parallelism. ECS is not data-oriented by default. :) I have a long post explaining things in this thread here: https://news.ycombinator.com/item?id=27663218 https://news.ycombinator.com/item?id=27663218
- adamdusty 5y agoMy comment has nothing to do with implementation. We're talking about ECS in the context of DoD so I'm not sure what relevance being data-oriented by default has. It seems like you're just confusing the concepts of ECS, DoD, and composition. Your entire post on ECS is, "If you don't use DoD with ECS than you're not using DoD". Well yeah.. obviously? If you implement an ECS and then use it without data-oriented structures, then yes obviously you don't have data-oriented design. You're creating a strawman. You're saying if you take ECS, remove the idea of storing components independently of entities, and pass them in an inefficient manner to systems, then you don't have DoD. ECS isn't inherently DoD, literally nothing is. Arrays aren't inherently cache friendly. There's nothing stopping you from making a language that allocates data randomly throughout reserved memory and every array element points to each location. No one is arguing ECS is inherently DoD, but it is a good design to facilitate DoD. > For example we might want to do damage to another entity entirely. Add a damaged component to the entity to damage. Consume damage component in a system. > Or we might want to look up the properties of the piece of ground we're stood on Use a position component on the entity standing on the ground. Consume the position in a system and look at the properties of the terrain map at that position. Even simpler for grid based maps. > We're also ignoring interacting with other components or the world and how that might work You interact with other components by defining interactions in systems based on those components. You've created an ECS in a way that doesn't take advantage of any of the benefits, and complaining that all you're left with is the disadvantages.
- colllectorof 5y agoECS (which I have not used) sounds a lot like Traits. The name and core concepts for Traits were defined in 2003 in an ECOOP paper [1]. I think traits were first implemented by Squeak Smalltalk in 2005. [1] http://scg.unibe.ch/archive/papers/Scha03aTraits.pdf http://scg.unibe.ch/archive/papers/Scha03aTraits.pdf
- meheleventyone 5y agoVery similar although in an ECS the relationship is backwards, Entities get behaviour based on what data they contain rather than getting behaviour from traits and needing to add state to make them work. The ECS approach can lead to some confusing things like adding a component to an Entity and having strange behaviour result as a system the programmer didn’t expect to be triggered is run. This can lead to systems having quite complex definitions based not just on the components the system needs to run but also on the components that shouldn’t be present and so on.
- Zababa 5y agoFrom a distant point of view, everything is OOP. You can treat anything like a black box that you push button on to make things. You push things on your keyboard, without knowing how it works. Your keyboards activate things on your computer, without knowing how it works. The computer ask the screen to update with the new date, without knowing how it works. From a distant point of view, everything is data oriented. Your thought are transformed into keyboards presses by the keyboards, that are transformed into events by your computer, that is transformed into what you see by your screen. I could do the same with a frozen pizza factory: you can see the ingredients flow in the machines (functions), or you can see the different machines passing things to others like objects. The problem is that then the classification between "OOP" and "non-OOP" doesn't mean anything anymore and is now useless.
- meheleventyone 5y agoThis isn’t a distant point of view though. I make games every day professionally and think a lot about how to make making them more accessible. Both are part of my job. People building them shouldn’t just consider how an ECS looks under the hood but how it works for someone using it which is as a system for building runtime objects. Particularly if you look a little deeper than the popular Internet view of the basics to what an actual usable implementation looks like.