Not a comment on your organization, but on the implementation of your state mask. It appears you're trying to implement a bitmask for character attributes with binary ORs ("|") not logical ORs ("||"). A more common implementation:
enum {CAN_JUMP = 1, CAN_FLY = 2, CAN_OTHER = 4, ...=8 }; // actual bit positions within the mask
...
unsigned int mask;
See reply by SeanMiddleditch. Always prefer
(1 << x), either hand-coded or via a macro or constant expression over raw numbers for bit-based enumerations. One of the things I would propose to the new C++ standard is to add
bitenum { A, B, C }; to do this for us as it is very common.
In my simple implementation I have a IBehaviour class that goes in the Actor class, but AI and Game Logic is supposed to be in a AI class (the Game class in that case). Do you think the following approach is +- correct?
Although I said the game knows about the game logic, I suppose I was technically talking about each game states, not the Game class itself.
CMainMenuState and CCreditsState will have entirely different logic from CMainGameState, and indeed game logic could change between parts of the main game (see Sonic the Hedgehog 2 which mixed primitive 3D gameplay between its side-scrolling gameplay).
The game state is what decides the logic for each part of the game.
Other than that, what you are implementing is a state machine. You can swap behavior classes in and out of an actor and change how it behaves, so a single actor can have one of many “behaviors” at any given time. This is mostly useful for AI, not a player-controlled character (the human’s mind is the state machine that decides what behaviors to inflict upon his or her in-game persona). While it provides a fairly nice way to encapsulate various enemy behaviors, be warned that it can get tedious and possibly become spaghetti trying to code them all one-by-one as you figure out what code needs to moved around to avoid duplication etc.
The biggest problem with your implementation (I won’t get into the circular dependency, which I would solve by making IBehavior know about ActorBase rather than Actor, or make IBehavior know about Actor but only AIActor has an IBehavior, etc.) is that you are setting flags to indicate potentially valid states.
The only time you need to know if the player can jump is when the player tries to jump. In order to figure out “just in case” a player can jump you are doing some kind of ground test etc. every frame when 99% of the time that information isn’t needed on that frame.
Somewhere in the game logic (the state class that handles the main gameplay) there simply needs to be a boolean indicating, “Yes, the player can jump now,” or, “No, the player cannot jump now,” which is tested only when the player tries to jump, and immediately handled appropriately (not saved as a flag to be deferred for later processing).
Most (if not all) “can I perform this action” tests are done similarly, otherwise you will get a ridiculous explosion of state-setting tests which will invariably lead to bugs. While making Dolphin Trainer DS, my coworker tried to do this, and as a result there are out-lying cases where the dolphin would land back in the water after a jump but fail to correct its alignment and start swimming with its nose pointing down.
For this reason, while it was important to note that your enumerations were not actually bit masks, actually you can just get rid of it entirely.
Bit masks are more suitable for keeping track of character statuses. I don’t mean potential statuses such as “can jump” but currently active statuses such as “power jump is active”.
L. Spiro