Although this question was asked a while ago, I find some of the assumptions worth discussing:
Let's say I have an ECS with physics and I want to kill the player
when a arrow hit him. So I have a callback when there is a collision.
Now there is of course different behaviors with different collisions
within 2 bodies (heal with heart, damage livings with weapons, etc...)
so plenty of combinations of collisions.
That's a list management problem. I don't see this as a problem with ECS, but with how a particular ECS is implemented. Instead of running full "list-of-everything against list-of-everything" potential collisions, you could set up certain specialised sub-lists that would divide your processing of things like "hearts hitting players to give them health" vs "arrows and other stuff that hurts hitting players to reduce their health". You could maintain those lists through deltas, rather than doing enormous list rebuilds every frame. You could also process some of these lists occasionally, not every frame.
These exhaustive if
or switch
statements you mention are, broadly speaking, a bad idea, given the cost that mis-predicted conditionals have on your CPU pipeline. I'd probably define a 32- or 64-bit set of binary flags that covers certain combinations, compare (bitwise AND or OR) these as a single CPU operation against each entity's flags (branchless logic), and get them into separate lists before doing any collision detection.
I would think in ECS I will check the components each body has and
call the appropriate behavior, but of course the more behaviors I have
the more it will cost, because each combination should be checked for
each collision.
Any well-organised, easy-to-reason-about architecture incurs runtime performance overheads. If you employed some kind of AI to optimise much of the code that exists in the world today, you'd indeed get code that works well and lightning fast, but it would be totally unmaintainable by humans. (We may find in future that this might apply to AI software architects, as well.) Which do you prefer? I've had enough headaches on the job to know that maintainability is king in my book.
More generally, don't ECS add more cost when there are more behaviors
? In traditional way (OOP with inheritance), no matter how many
different behaviours you have (the count of derived classes), you will
always pay only one method call. In ECS, you update each system at
each frame, so the more systems you have the more it will cost, even
if there is no entities that use it.
In my experience of profiling, deeply nested conditionals are one of the main contributors to bad performance. Since most logic in a game engine is nested in one or more conditionals, wouldn't you rather keep conditional logic shallow? -- that part of what's a good ECS does.
Superficially, yes, more components means a higher cost over the same number of entities. But what matters is what happens within those blocks, and how deeply nested that (conditional) logic becomes. And remember, you don't have to process all of them every frame. This is true of either approach, ECS or regular.
Unlike typical Finite State Machines of about 15+ years ago (and some people still write code this way), ECS doesn't force you to go down a deep rabbithole of conditional blocks and method calls to reach the key logic you need to run in this moment, instead it says, "all things are pretty superficial, and we treat them largely the same". By superficial, I mean the main loop that runs through all components by all entities should be sitting somewhere quite near the root of your call-stack at all times. Anything beneath that should be fairly shallow.
If anything, smart list management (including maintaining updated lists through well-designed delta element add & remove approaches) is a far greater contributor to runtime performance.
Conclusion
Don't take a shallow view of the problem. Try it out yourself, experiment and profile within a bounded, well-defined spec. Application architectures are rarely simple things, so it's rarely possible to make simple assumptions about them, without concrete examples to talk about.
If you're worried about performance, spend your time wisely on choosing or implmenting a good ECS (don't struggle with deep inheritance hierarchies) and use the time that gains you to optimise sections of your ECS and other game logic.