Both your possible solutions are unnecessarily complicated or brittle: generally, ill-advised.
Polymorphism
Your question title is
Make the components of an ECS polymorphic
but then you don't want to use polymorphism since you state,
I basically just want a clean solution. It must not use polymorphism, it should solve the above problem in a neat way.
...
I'm pretty sure that adding some kind of real polymorphism to the components would be possible and I could figure out how to do it.
So you contradict yourself utterly. You want polymorphism without using polymorphism, is that it?
Since you have given no reason as to why you think polymorphism in an ECS is problematic, I can tell you straight off the cuff that it is, 99% of the time, normal and desirable in engines and ECS. Polymorphism is little more than a function pointer, which is a way to redirect logic without the costly use of conditionals (if
, for
, while
, for each
, ?
etc.) whose use you suggest in ex. #2. I've implemented polymorphism in C (which lacks it) and it is a very simple and efficient concept.
So, polymorphism is the neat and elegant solution. That's why it's such a widespread approach.
Iteration
I would like to be able to loop through all entities with a collision component
OK, then every time you create a new collidable entity, you add that entity to a discreteseparate list/vector that contains all collidable entities, OR (better yet), add its component (which has a back-reference to its owning entity) to such a list/vector. Update same whenever an entity / component dies.
Golden Rule
Keep things simple in engineering - don't overcomplicate - or you will very quickly get yourself into ruts you cannot easily get out of, and that way lies a loss of motivation to get your project flying.