3 ms·
I've thought about this in the past too, and come to the conclusion it is too difficult. Part of what I don't like about ECS is that it's too dynamic, you can't
by jms55 5y ago
I've thought about this in the past too, and come to the conclusion it is too difficult. Part of what I don't like about ECS is that it's too dynamic, you can't add static typing like this.
Sure, you can say that a "Skeleton" entity has an HP component, an AI component, etc. But there's no way of enforcing static typing on this.
Say you have some function that takes an Entity, validates it's a Skeleton, and then returns a SkeletonEntity which is just a wrapper around Entity for static typing purposes. Perhaps add some helper methods for fetching components, allowing you to operate on an OOP-like API with very little runtime cost. Seems like it works.
But there's no way to guarantee the skeleton STAYS as a skeleton for the future. You might add another thing later on that converts an entity with AI into FriendlyAI, and your SkeletonEntity implicitly relied on the AI being a SkeletonAI. Heck, you can't trust _any_ Entity. That handle to an entity you have might not even point to an Entity anymore, it could've been deleted.
ECS is very dynamic, which is great for designing open-ended games where you don't/can't plan every interaction in advance. It also has great performance, and is typically the _only_ sane way to implement games in a language without inheritance (I don't think Composition + Interfaces is very scalable). But for heavily structured games that want tight coupling between entities, it relies on you implicitly keeping your promises about what an entity means. You can't go and add new behavior that modifies existing entities later on - The compiler won't warn you, and you may end up crashing your program at runtime, unless you were very diligent about adding checks in your code for the coupling you assumed existed, and having good fallbacks for one those assumptions are violated.
- lamontcg 5y ago> But there's no way to guarantee the skeleton STAYS as a skeleton for the future. It seems like there needs to be some guarantees made about this. You can't have background jobs asynchronously changing players into spaceships and vice versa while there's other jobs running systems against those. I would guess that most games made with ECS systems that are threaded would deal with this by having a queue of requests to change entity components that would get processed once at the start of an update cycle and then a consistent state would be shown to all the systems in that update. That's really a state change in a finite state machine and I would imagine there's some work out there on systems of FSMs and concurrent updates and keeping things sane. Deletion could similarly be scheduled until the next tick and since systems should be stateless they shouldn't be saving those handles (or if you allow them to save the handle for some reason, you require them to check if the handle has been marked as deleted every tick).