|
Yes, where M is a small constant. Using a bit set, it drops to O(N × M/64) = O(N × M), assuming you can compact all the combinations together in one word. I'm not fundamentally opposed to a bitset, but I don't particularly care for RTTI.
Using queues trades checks for memory. Instead of iterating the smallest queue of objects and checking that (A) all component bits are set or (B) the entity is in all the correct queues, we just iterate the queue with the correct combination. This is good when the number of components needed in a single combination is large, but the number of necessary unique combinations is small.
In the general case, it's terrible, as the number of combinations grows exponentially in the number of behaviors. You'd want to use queues when you need to iterate all tanks which use tank logic and have tank physics and a position, and all ninjas which use ninja logic and have ninja physics and a position, but no other combinations. In this case, you'd have as many as four checks depending on which bits were assigned to which component, but you'd only need two additional queues to which such tanks and ninjas could add themselves, thus saving all checks and iterating in O(N), N being the number of matches.
Again, these queues are only possible when this information is known at compile time. It's fine if the tank and ninja objects can remove these behaviors at runtime, as long as we can create the checks to manage those queues when this happens at compile time.
Knowing combinations at compile time helps in the completely dynamic case, too, as it enables you to reduce the number of checks to O(N × M/64), where M is the number of behaviors in your combination instead of the total number of behaviors.
|