6 ms·
I think the prevalence of these sorts of issues is why ECS is such an appealing architecture in game design. OOP seems to always devolve. A new feature is neede
by SeanAnderson 3y ago
I think the prevalence of these sorts of issues is why ECS is such an appealing architecture in game design. OOP seems to always devolve. A new feature is needed for the game, the feature breaks some well established design rule, it's challenging/slow to refactor everything to make sense while considering the new feature, and so a kludge is implemented where existing objects are forced to be more flexible than planned.
Of course, this can happen with ECS, too, but it feels easier to avoid. Systems which are coupled to individual components of entities, rather than whole objects, provide an extreme degree of flexibility as long as the components stay small.
(bonus: another example of this occurring in Fallout 3 - https://www.pcgamer.com/heres-whats-happening-inside-fallout-3s-metro-train/ https://www.pcgamer.com/heres-whats-happening-inside-fallout...)
- baq 3y agoECS is IMHO a logical consequence of observing that game worlds are not object oriented (as it is taught in schools, so class hierarchies etc.) Add a sprinkle of performance requirements and you get what is understood as ECS frameworks. …but it turns out that the ‘world is not made of class hierarchies’ observation is not limited to games, hence Rust’s and go’s approaches to OOP: ditch inheritance at the language level.
- dale_glass 3y agoThe world isn't, but some things are. Doesn't Rust have a problem with GUI frameworks because they heavily use inheritance?
- s-lambert 3y agoI don't think it does, I think Rust GUI frameworks have the same problem as Rust game engines, there's more people making frameworks than people actually making applications. They mostly seem to be going in the same direction as web UI frameworks though, which don't use much inheritance either.
- seanalltogether 3y agoECS makes sense in games because OOP enforces lots of rules downstream in your inheritors, which is good for GUIs, but bad for games when producers keep asking for that one npc or boss to do something special that breaks the rules. ECS is just so much more flexible which is good for some design systems and bad for others.
- baq 3y agoE.g. react does just fine with functional components; I'd say it does much better than with the old class-based ones. Inheritance works well enough in exception classes, e.g. I can catch OSError and specifically handle FileNotFoundError differently on a language level, but it's nothing composition couldn't handle, either.
- Coder1996 3y agoI disagree re: React. To me, class-based has one advantage over functional. A component is an object and therefore perhaps ought to be represented by a class. That being said, functional maybe is a bit simpler.
- baq 3y ago> A component is an object and therefore perhaps ought to be represented by a class. That's what those who ditch inheritance altogether when designing languages challenge and it turns out not much of value is lost :) 'Component is an object' is something you'd hear from an OOP practitioner which isn't exactly convincing to people thinking functionally.
- Coder1996 3y agoI actually use a little bit of both OOP and functions. What I don't understand, I suppose, is if a Component isn't an object that acts, then what is it?
- adr1an 3y agoI had to look that up. From Wikipedia: Entity component system (ECS) is a software architectural pattern mostly used in video game development for the representation of game world objects. An ECS comprises entities composed from components of data, with systems which operate on entities' components. ECS follows the principle of composition over inheritance, meaning that every entity is defined not by a type hierarchy, but by the components that are associated with it. Systems act globally over all entities which have the required components.
- DeathArrow 3y agoECS is a kind of Data Oriented Programming / Data Oriented Design. In Data Oriented Programming data and code are separated (no encapsulation). This makes changes much easier to do and helps a lot with managing state.
- jvanderbot 3y agoFor what it's worth, I'm not aware of anyone who believes inheritance "ontologies" was a good idea, nowadays. Interfaces sure, but composition is just better for this reason. ECS is a formalization of that, and probably even perpetuated the idea, but it's everywhere I look now.
- mistrial9 3y ago> I'm not aware of anyone who believes inheritance "ontologies" was a good idea, nowadays. like, all of anything you could program, ever? for any purpose?
- Telemakhos 3y agoInheritance works for essential things and composition for accidental things. Use both together to get the full Aristotelian deal.
- Spivak 3y agoExcept of course for all the ontologies in your language's standard library that you don't even notice. Your IO hierarchy, exception hierarchy, your collections hierarchy. As long as you don't kingdom of nouns everything any repeat the mantra: "classes are just interfaces with code reuse" you'll be fine.
- TeMPOraL 3y agoAh, ECS. The most ill-defined software pattern since IoC/DI. Everyone seems to have their own understanding of it, usually somewhere on the spectrum between "what if we kept the game state in a relational database"[0] and "what if we put any individual type of information into its own big array, so it's CPU-cache-friendly"[1]. I wrote several such systems for my own toy games, at various points of that spectrum[2], and I still have a bunch of open questions I can't seem to get my head around. The biggest such question is: how the hell do you handle "cross-cutting concerns" in an ECS architecture, especially in the data-oriented programming version, where "cross-cutting concerns" are basically any kind of logic ("system") that needs to access more than one component of an entity at the time, especially if it does so conditionally? Like e.g.: - Physics, rendering, animation, and game logic all need to access some subset of the same position, orientation, dimensions, velocity, acceleration, mass, tensor of inertia, etc. - Any kind of logic that goes like "IF something(component 1) THEN doSomethingTo(component 2) ELSE doSomethingTo(component 3)". How are you supposed to preserve data locality in such cases? Is it even theoretically possible? I may have some fundamental misunderstanding about the definitions here[3], but I haven't found any clear answer to the questions above, whether theoretical or practical. Back when I last looked, couple years ago, I couldn't find any non-toy game written ECS-first and with source available to study. Maybe this has changed now. -- [0] - Which, as far I recall, was the original idea behind the pattern. It's also a very interesting one in general - if you squint, a lot of code all of us write for our projects is just half-baked attempts at setting up specific indexes and hand-rolling queries to a bunch of vectors, hashmaps, or (gasp) object graphs. [1] - AKA "data-oriented programming", in this case mostly preferring "Structs of Arrays" over "Arrays of Structs". [2] - One of them was literally just "let's store all game state in an in-memory SQLite database, because guess what, it's actually fast enough to be queried at 60 FPS!". [3] - In my defense, most of the guides, tutorials and articles I read back in the day were themselves confused between "SQL approach" and "SoA approach" (see [0]), or worse, mixed in "whatever abomination Unity passed as ECS back then" and even something semi-related from .NET world. It took me a lot of time to understand that everyone's using their own blend of all those ideas, and this left me unsure about what one's really supposed to do.
- Joking_Phantom 3y agoI think the answer is that ECS isn't supposed to solve those problems directly. It's just a framework that makes a certain class of problems very easy to solve. But big picture complexity is still up to the developer's skill and wisdom. Knowing which parts of the game should go into ECS, and which parts go somewhere else. Which systems flow from another system. Which system is allowed to manipulate the data directly and which systems are only able to read data reasonably, but not write. And how your design of the game may need to change to suit the limitations of your computer and your ability to program. ECS is like any other framework. It is a tool or system, for organizing your efforts. Be very liberal with using it in its intended scope. Be judicious when its at the edge of its scope. Be very skeptical when its outside of its scope.
- octavius__ 3y agoAnother recent example is from Starfield, where shops inventories are handled by a physical chest hidden underneath the shop. You can use noclip to loot the chest and get shop items for free.
- TeMPOraL 3y agoThat kind of makes logical sense, though. Physical hidden chests are, after all, how almost all real life shops implement inventories. Those are typically inaccessible to players, too. (There is a part of shopping experience where the player grabs items and puts them in their own chest/basket prior to purchase. This works thanks to the security scheme of law enforcement NPCs dragging your ass to jail you can't save-scum your way off, should you steal something. But this is too complex to implement in a game, unless you're making the next GTA.) Hell, even the bunnies and spectral radio cats make sense, to a degree. This reminds me of the ol' Flash games or Klik&Play/The Games Factory-made games. In all of them, you'd find yourself placing support objects on the scene but outside the screen boundary. I used to laugh at it, but eventually realized it kind of makes sense, if you think of the game as a theatre play - there's lots going on at the edges of the stage, just beyond what the audience can see. Or think back to RAD tools from Borland (Delphi, C++ Builder) - they had a notion of abstract objects like "Timer" as invisible UI controls that could be placed in the window you're designing. On the one hand, this makes no sense - an abstract timer doesn't have "position" or "size", not at runtime. On the other hand, it was intuitive and convenient at design time.
- noirscape 3y agoThe recent Pokemon games also had a bug where the various support objects placed on the map for cutscenes were made visible during battles. Since they lacked a model, they'd default to the first model in the games object list, which was a PokeBall, but then also loaded up every single texture onto it, resulting in various maps getting random multicolored PokeBalls in the floor (usually at their 0,0 point). The approach to me also makes sense if you think of these support objects as "directors" for the gameplay. They usually track a specific bit of state to then act on once it's met. It's a pretty clever technique for rapid development (you can usually do what support objects do without them but it'd take a lot more effort in the game engine to do it that way) that can sometimes backfire in entertaining ways.
- jerf 3y agoI'm not really sure this is an OO vs. ECS vs. any other design architecture thing, as evidenced by a lot of your other replies. I think it's just a general programming pattern that it's very tempting to take a large dependency on in order to get some small bit of functionality. Then, Hyrum's Law takes over [1], and you end up with a few more bits of dependency on the massive bit of code you pulled in. And you pull in a few more massive dependencies for just little bits of functionality, and organically grow a few more attachments to the huge code base. And before you know it, you've got 10 massive dependencies, and you only use vanishing fractions of their functionality, but extracting any of them is a huge pain. It's true that OO design pushed game engines in this direction; if you need something that only the last "full on NPC" node in the inheritance tree provides, which is very believable, then your designers are going to use it, even if they don't need most of the rest of what it provides. But I think this is something your designers are generally going to do anyhow. They aren't professional programmers and they aren't sitting there worried about long term code quality (especially not in the games industry), they are worried about getting their job done, and under any design it's going to be easier for them to reach for a large stick and pare it down than to reach for the small stick and then laboriously figure out how to attach the extra bit it needs. It doesn't matter how easy it is to attach the extra bit, it's going to be easier for them to grab the big, all-in-one provider. They're going to figure they may need the other stuff later anyhow, and they're reasonably likely to be right so it's hard to even call that irrational. You can see this pattern all over in programming. I know of multiple codebases where I work that suffer from this pattern without any games being involved. Developers could implement new subsystems either as independent subsystems that they minimally connected into the main product, but have relatively few services provided by default to those subsystems, or they could start from day one fully integrated into the rather massive monolith with all the services it provided, even if it wasn't great with those services. And generally they would choose the latter, making the monolith even larger and the crossing mishmash of dependencies on the large services even bigger and more complicated. Maybe they were even right at the time, but now we've got some fairly large and complicated balls that can't be replaced in a big bang, but also can't hardly be replaced incrementally, because everything depends on everything. Upgrading any portion is a nightmare. They reached for the super complicated, relatively powerful objects that provided all the services even if they just needed a couple things, and now they're all in a spaghetti pile. And there's hardly any OO in sight, this is all really just procedural despite the occasional OO island. You can see this in the still-growing general understanding in the programming community that dependencies are not free. The benefits you can obtain from a dependency are enormous, immediate, and easy to see. The costs are subtle, to the point that you can be mocked by developers for thinking they even exist (though I see this particular attitude fading, fortunately), but it's easy for them to grow into at least the order-of-magnitude of the benefits, and sometimes exceed them. [1]: https://www.hyrumslaw.com/ https://www.hyrumslaw.com/
- deleted 3y ago[deleted]