A bit of technical stuff.
So the game was designed from the beginning with a focus on the AI sub system. I wanted it to be
flexible enough to add some really interesting AI later, both to make the game more challenging to play (and develop!) and also to make cpu v cpu matches more meaningful in a career mode.
Taking advantage of the state machine pattern, the player is a state machine in itself and it has states such as "running," "dribbling" etc. with only react to outside conditions and update the player animation. For example, if the player's velocity is non zero, he automatically goes into the running state. This merely loads in the correct animation frames and updates the animation each frame. Likewise, the running state transitions into the dribbling state if the ball is under the players control. The only difference is that the ball is knocked forward on contact.
This has nothing to do with AI so far.
The player *has a* brain object. The brain is responsible for surveying the game environment (and team instructions) to make decisions and trigger "behaviours." A behaviour is a locomotion controller such as "seek," "interpose" or "jump."
For example, the seek behaviour is triggered when the brain wants the player to run to a specific location on the pitch. It is only the behaviour object which has privileges to directly update the player's velocity property.
A special vase in the behaviour space is the jump behaviour. Since the jump behaviour must set the players z velocity, it is correctly placed in the AI::Locomotion space, but can create an unwanted side effect if the brain decides to initiate a seek behaviour before the player has come back to earth. We then end up with a player floating around in mid air (as pointed out before, for playability reasons, the player does not react like a regular physical object, merely a sprite moving around the screen with no acceleration or outside forces and therefore there is no gravity applied to him to correct the problem).
The solution for this was to think in terms of real world objects (OO ftw). What's really going on is that your brain knows it wants to run somewhere, but you can't execute the physical movements (behaviour/locomotion) necessary to achieve the goal whilst you are in the middle of the jump.
So now the brain manages a queue of behaviours and each behaviour object has a method to check "canStop()." Most behaviours are able to stop immediately, but in the case of the jump behaviour, it will only return true when the player is back on the ground again. When false is returned, the brain adds the behaviour to the queue and, each update, if there is anything in the queue it will try to switch tot he next behaviour in the queue.