This feels a lot like a database. Obviously there's some more nuance to it than just that, but you essentially build out your columns (components), and then use your primary ID to determine the value of each component. It's simple, and straightforward, good job.
What's the benefits of storing the data in separate lists when all lists contains data for all entities instead of baking it all into one entity struct? Like the Move function. Why read physics and transform from their lists when they just be part of the entity itself?
Doing this means every entity would need every component in the entity struct, even if they don't use said component, which would become a memory burden as more and more components get added. There are ways to instead have one massive list which contains every component, laid out in a specific order for the fastest possible traversal, but it's pretty complex and honestly I don't think I need that level of efficiency for a basic ECS. This is just my compromise between ease of use and speed.
its a shame that most people who talk about ecs talk about caching performance. unless youre making a AAA game, caching will not help you. it didnt matter when you were using oop in unity, it wont help you now XD. but omg ecs makes so many headaches go away its brilliant
I agree. I'm working on a video to solve a couple of the problems that remain in this implementation, but at the end of the day, I'm not out to beat EnTT or DOTS; I just want to make a decent ECS for my game
Very good video! Really thought the visuals, diagrams, and editing helped succinctly give a good idea of what an ECS is for those unfamiliar. Just wanted to clarify one thing for others and the future. Data Oriented Design is not actually packing data close together, keeping objects in memory linearly is tight packing and linear memory iteration/access. Data Oriented Design is the concept/practice of keeping all data isolated in objects, without any logic, and having functions (usually global functions) operate directly on that data from other sections of code.
Thank you! :) I just did a quick search and the definition seems muddy, from what I understand Data oriented Design is designing for cache friendliness, while Data Oriented Programming is what you described. I could be wrong though
Have you ever considered nodes instead of components? I am working on a Prefabs Nodes Systems (PNS) kernel because I did not like how loose components are in ECS. Yes that is the entire idea in ECS. But you can only decouple the data and not the behavior in the first place. So what is the point? You are confusing yourself because "data does not show the way" anymore. That is not even data oriented design anymore either. You are limited to one component type per entity too. This makes it impossible to design an entire prefab. ECS makes lasagna code. Code that is too loose. Systems are important though. They do fetch data bunches without needing a handle. They do multi threading. They are handy for adding plugins to the base application too. That is why my own kernel is from ground up plugin based too via systems. Bevy oddly does not force plugins. And obviously plugins can be static too. Which makes me wonder why Bevy is so crude with it. You want to be flexible? Well. Use plugins too. So. Frankly. The only good things about ECS is the Systems and plugins part? And not the rest!? So make a hybrid and make handles great again with nodes? Oh. Since I code with Rust. That of course means no inheritance. Just for the record... The node handles are index based and do not hold a pointer. An entity handle in Bevy is just a single index to an entity too. Though in PNS because of the prefabs part it seems I am forced to add another index for the prefabs instance. But I am still researching. I wonder if there would be more than 256 prefabs for a single application. Because that would mean I can get away with a small u8 index. Other kernels use handle systems that require some kind of version so that a deleted data is not confused with a new one that is on the same spot so using the same index. But the prefabs part of the PNS should actually fix this and not need the versioning at all. Because the nested prefabs can be statically nested or dynamically nested. Meaning any static sub member is also spawned keeping the handles with a valid index in their respective usage context.
"But what if I want a weapon that behaves like both a sword and a bow? It can't derive from both..." C++: "Are you sure about that?" Truth be told, C++ does allow multiple inheritance, and has even solved the diamond problem via virtual inheritance; if a class B inherits from class A virtually, then rather than including an A inside B, it includes just a pointer to an A inside B, allowing multiple parent objects to all inherit from a common grandparent (or even higher) and still only have one of the object within them.
Honestly, I sorta regret the example I provide of the downfalls of inheritance; I think there's better ways to show why composition is (generally) more pleasant to work with and saying "Can't derive from both" is misleading, but it can get messy and you do have to have to know what you're doing (Multiple inheritance can easily become a smell) The bottom line is; I think it's easier to scale than OOP. I could be wrong though, don't forget you're talking to a guy that hasn't made a full scale game with both and this is my first rodeo. I'm planning on making a postmortem video when the project is done though to see if ECS and all the other decisions I made through the series were the right ones
To a point, but components are basically just tag structs that may or may not contain data. The system portion can then very efficiently find entities that match component queries (sword, iron, long) etc and handle the component data and entity they belong to. It’s a really cool system to work with BUT it can get really messy when everything in your game uses it.
not so much, Traits are functions that will still use a vtable to determine the "derived" type that is calling the function, so not much different from OO. ECS is meant to be used for splitting out your data so you group like-data elements in arrays or collections that can be iterated over contiguously in memory (cache-friendly)
yeah i'll sub. I like that your ECS is keeping relatively simple, but I would be wary about the unvetted benefits of _decoupling_ and _reusability_ in your early stage project.
I don't have a discord (maybe in the future when the game develops more!) but I have some public projects like my latest video on my Github at github.com/chrischristakis
Classic. Step 1. Provide the shittiest most contrived example of inheritance. Step 2. Mention Cache exists Step 3. Don't show any of the actual implementation Step 4. ??? Step 5. Profit It's like those devlogs are made in a factory. Always exactly the same. This doesn't even solve any problem. Just a knee jerk reaction to add ECS because internet said ECS = good
Wanting to use ECS to learn about it in a game that'll almost certainly benefit from it isn't a knee jerk reaction. Also it's a dev log meant to document progress and rationale, not a tutorial. There's plenty of resources online for that already.