4 ms·
Showing the how without showing the why is probably not helpful IMO. Why is important here. Using ECS is somewhat like treating your game state like a normali
by reificator 8y ago
Showing the how without showing the why is probably not helpful IMO. Why is important here.
Using ECS is somewhat like treating your game state like a normalized database. It lets you perform operations on all the items of a certain type at once.
Say in my game I need to recenter my origin on a regular basis. In an open world game, you want to make sure that players don't start to see errors caused by floating point arithmetic, and the further away their position gets from 0, the worse this gets. To fix it, one option is to transform all positions by the same amount to keep the player's absolute position near (0, 0, 0).
To do this in the hierarchy style, the code might look like this: (Using JS because I was writing it today so that's where my brain is)
var gameObjects = world.getAllGameObjects();
var offset = [-1000, 0, 500]; // Pretend it's a real vector
// Iterate through every single object in the game
// (Not using foreach or filtering in either example, sue me)
for(var gameObject in gameObjects) {
// Branch on every game object just to see if it's positioned in the world
if(gameObject.position !== null) {
// Do what I really wanted to do
gameObject.position.add(offset);
}
}
Meanwhile, the ECS version would look more like this:
// This can vary greatly based on implementation
// I'm going to go with an option that reads easily
// This should just give back the list of components, which we'll say is an array.
// Lookup time in this fictional system is the cost of a dictionary lookup.
var positions = world.getComponents('position');
var offset = [-1000, 0, 500]; // Pretend it's a real vector
// Iterate through only the things we care about
// Not using map here, sue me
for(var position in positions) {
// Do what I really wanted to do
position.add(offset);
}
Not only is the second example shorter, but it's also doing a lot less work. We're adding a vector to an array of vectors. No branching, no touching objects we don't care about, nothing extra.
Many ECS systems will allow you to filter down to the set of entities that have two or more components at the same time. Obviously more expensive, but still not as wasteful as checking every object or adding an update function to run every tick on every relevant entity.
The above code was written just before bedtime and not against a real ECS library or OO hierarchy, so please forgive any obvious errors.
- jplayer01 8y agoMy biggest problem with ECS is that most articles talk about why and on a very abstract level how it works, but there are rarely if ever useful examples of how to implement an ECS.
- reificator 8y agoYep, that is definitely an issue. If I made a living in games I'd probably try to fill that hole myself, but it's a hobby for me, and one that doesn't get much time allocated.
- skypjack 8y agoMy goal is exactly to give details on how to implement different component-based models from easier ones up to hardest ones to develop and provide links to real-world implementations. In the last part, I'd like to go in depth into one or two of them, but I'm doing all of this in my free time, so it will take a while to publish everything. I hope you'll stay tuned and keep reading, because feedback like these ones are invaluable.
- fenomas 8y ago> Showing the how without showing the why is probably not helpful IMO. Why is important here. I was replying to someone who asked about the What.
- reificator 8y agoSure, but when introducing someone to a new paradigm, the why is part of the what.
- fenomas 8y agoThe why is what TFA is about. If you think the person I replied to was asking for an introduction to the paradigm, you could probably reply to them directly instead of dragging me about it. Incidentally, FWIW I think your post about the why completely misses the point of ECS. Looping over entities with a particular property is easily done with OOP hierarchies or anything else. The benefits of ECS are elsewhere - that you can freely add or remove an entity's properties (without type issues or hot code becoming polymorphic), that the data you frequently iterate over can be stored in friendly contiguous chunks, the usual benefits of composition over inheritance, and so forth.
- reificator 8y agoIf I came across as harshly critical I apologise, that was not my intention. I meant to say that the why is to treat your data like a normalized database, which provides those properties you list at the bottom. In fact my example demonstrates at least the following properties: > (without type issues or hot code becoming polymorphic), that the data you frequently iterate over can be stored in friendly contiguous chunks My example was not to show that you can loop over every entity. It was to show how easy it is to loop over only what you care about without doing extraneous work, by iterating over a contiguous chunk of exactly what you need to update. I was going to add an example of creating a regenerating health component and system, but I didn't for a couple of reasons. One, it was already past bedtime. Two, I would have compared it against adding a tick handler and so it would need to be a larger example with more explanation of the way the imagined engine works. The post was already pretty long in the first place so I decided against it.
- infogulch 8y ago> like treating your game state like a normalized database This makes me curious, how bad would it be to actually store game state in say, an in-memory sqlite database? I feel like this could get you some nice things, like auto-destroying all components of an entity via foreign key deletion, being able to merge/join entities with the intersection of multiple components etc. Assuming the clunkiness of interacting with sqlite is abstracted away, I wonder what the real performance differences would be.
- reificator 8y agoI've wondered that as well. My gut feeling is that when crossing the SQL boundary you would lose a lot of the performance you would otherwise be gaining from using an ECS to begin with. Especially when talking to the GPU. I'd love to be proven wrong if someone has the time though.
- imtringued 8y agoCompared to iterating over an array of structs (or a struct of arrays if you want to be fancy) it's probably multiple orders of magnitude slower. And lets be honest, half of my performance problems in webapps are caused by the overhead of sending a query, the database is rarely bottlenecked by inserting or updating the data on the physical storage device if I do not use bulk insert or bulk update methods.
- setr 8y agoI assume you mean sending a query over the network, as most webapps do; sending it to a local sqlite file should be far less impactful.
- reificator 8y agoBut still not free. Please try it out though, I would love to see a proof of concept that took the ECS-as-database approach. Like I said earlier in the thread I expect it would not do well, but I'd be interested to see the results either way.