Friday, 14 August 2009

State Pattern : Transitions

Troy made some interesting comments on the last post, which got me thinking on a slightly higher level about how Units, States, Transitions and the like will work.

Something which isn't totally clear from my previous posts is how States change. In simple terms, each State handles the transition to the other states (when it needs to). The Units themselves don't handle State transitions.

There is a base State (in this case, Idle) which has default transitions to every other State. Simply put, the Idle State is this:


So, when a Unit is Idle, it can move straight to any other State.

Some specific examples

  • The Move state doesn't need to explicitly handle a transition to Attack, because the behaviour is default (i.e. no extra handling required) so it doesn't handle it. The framework then falls back to the Idle state when it can't find an AttackState handler on Move, and this moves directly to Attack. So we go Move -> Idle -> Attack.
  • The Fortified state does need to handle a transition to Attack - in that it can't be done. So if we are in the Fortified state, and the Attack command is issued, we handle this by

    Which means that Fortified -> Attack transition is prohibited. If we didn't specify the Handle(AttackStateContext.... method above, the framework would use the fallback transition on Idle which would permit the transition.
Troy also asks "Are Attack and Movement really different states of the Unit?"

Good question! What I eventually envision is something like

  1. Unit in idle state is issued an Attack command to a Unit 10 Hexes away
  2. The AttackStateContext is passed in to the Unit
  3. The Unit has a Range of 1 (hand to hand) so the Attack state moves to the Movement state
  4. The Movement state moves each turn (I need to implement ticks still)
  5. The Movement state eventually gets to the target Hex after X turns
  6. (assuming the enemy is still there) the Movement state transitions back to the Attack State.
  7. Attack State does the attacking!
That is a highly simplified version of what I'd like to eventually do, and there is a lot of work to be done, but I think it's possible. I'd love to hear opinions on this though, maybe you've done something similar, or have an alternative idea? All welcome! :)

2 comments:

Troy said...

I guess my problem with having the states changing based upon the *action* that is occuring is that you now need to track the state of states. How does the MovementState know to switch to the AttackState once it has gotten within range instead of switching to IdleState? I suppose it can be deduced via the StateContext being passed into it, but I also don't necessarily like that MovementState needs to know about AttackState and AttackStateContext.

The other thing to think of is Ayende/Oren's example of a unit upgrading from a spearman to a javelin thrower. If the state is so transient, how will that upgrade take place (and stick)?

I realize offering up criticism without alternatives isn't exactly useful, and we're both learning here, so here is my proposal:
1. The user/AI's selected action is a Command. The command is created and the current context is passed into the command. That Command is passed to the unit. In the above scenario you would create an AttackContext, construct an AttackCommand with that context, then pass that into the unit.
2. The State of the unit (spearman? javelin thrower?) is stored within the unit as a property of type State, and the Command is delegated to that state's Handle method. The major difference is here the longer lasting nature of the state.
3. The State then uses the command and context to change it's Strategy property. In the case you pointed out, it would switch to the MoveToHexAndAttackStrategy.
4. The unit then executes its State's current strategy (without knowing what it is).

Thoughts?

Troy Goode said...

I followed up my last comment with a blog post actually implementing my suggested solution. Thoughts?

http://www.squaredroot.com/2009/08/15/spearmen-javelin-throwers-and-the-state-pattern-oh-my/

Post a Comment