State Machine Editor The State Machine EditorA state machine is a set of Transitions from a starting State when an Event arrives that becomes a final State at the end of the Transition and that will perform some Action during the Transition The State Machine Editor is a tool that can translate xml state machine models into c#, c++ or vb code. Features:
The 2nd generated API for the state machines uses the State Machine PatternIn the generated c# and WPF project that a button is created to trigger processing each event. Each state class has StateEntry, StateExit and Action events. The current state changes when an Action returns true. The Test Project generated maps each state's events to show the machine status. ... in MainWindow.xmal.cs public void OnLoaded(object obj, System.EventArgs e) { this.SetUpEvents(); this._stateMachineMonster.StateChanged += this.OnStateChanged; ... } ... public void SetUpEvents() { IState baseState = this._stateMachineMonster.CurrentState; if (("Moving" == baseState.StateName)) { Moving stateobj = ((Moving)(baseState)); stateobj.LookAbout += this.AnyAction; stateobj.ChompEnemy += this.AnyAction; stateobj.ChargeEnemy += this.AnyAction; stateobj.Nothing += this.AnyAction; stateobj.GoToFriend += this.AnyAction; stateobj.StateEntry += this.AnyEntry; stateobj.StateExit += this.AnyExit; return; } if (("Chasing" == baseState.StateName)) { In the statemachine class the current state is checked for an Action for the stateevent and either a new state name or null is returned. The StateChanged event is for use when the new CurrentState needs further initialization after it is changed. ... in the statemachine class events change the State class instance in an IState interface object 'CurrentState' public void MachineEventArrival(string stateevent) { // test if the stateevent runs an action if so run it and return a new statename or null string state = this.CurrentState.StateEventCheck(stateevent); // if the state remains the current state no StateEntry, StateChange or StateExit events need to be run if ((state == this.CurrentState.StateName)) { return; } if ((state != null)) { // runs the old state class's StateExit event this.CurrentState.OnExit(stateevent); // puts the new state class in CurrentState this.StateFromStateName(state); // if it is being used by someone run the StateChange event if ((this.StateChanged != null)) { this.StateChanged(this, new EventArgs()); } // run the new state class's StateEntry event this.CurrentState.OnEntry(stateevent); } } The first API between the real world and the State Machines was designed as a multicasting black boxA button is created to trigger processing each event. The stack traces shown below show how the event arrives, is tested, any Action run, and the state change if one occures. private void EventButtonOnClick(object sender, RoutedEventArgs routedEventArgs) {... case "EnemySuspected": this.chevnt = "EnemySuspected"; // check if 'EnemySuspected' event is valid evtst = _monster.MonsterInputReady.EventsReadyFromState(_monster.GetCurrentState()); if(evtst != null) { // tell the state machine to run the event 'EnemySuspected' retv = _monster.RunMonsterEventEnemySuspected(DateTime.Now.ToString()); } break; For this to work, methods are attached at start up to events that come from the state machine. public void StartTest() { _monster.MonsterEventEnemyClose += this.TestInputEventEnemyClose; _monster.MonsterEventEnemyFound += this.TestInputEventEnemyFound; _monster.MonsterEventEnemySuspected += this.TestInputEventEnemySuspected; //...missing _monster.MonsterActions.MonsterActionLookAbout += this.TestActionEventLookAbout; _monster.MonsterActions.MonsterActionChompEnemy += this.TestActionEventChompEnemy; _monster.MonsterActions.MonsterActionChargeEnemy += this.TestActionEventChargeEnemy;//... _monster.MonsterInputReady.MovingCheckEventReady += this.CheckForEventInStateMoving; _monster.MonsterInputReady.ChasingCheckEventReady += this.CheckForEventInStateChasing; _monster.MonsterInputReady.FleeingCheckEventReady += this.CheckForEventInStateFleeing; //... } The state machine tests if an event is valid for the state named 'Moving' The test code logs that it's checking Call Stack
public string CheckForEventInStateMoving(object sender, MonsterTestEventsReadyArgs e) { string nowstate = this._monster.GetCurrentState(); string runs = " running CheckForEventInStateMoving"; string message = string.Format("{0} In state {1} with id = {2} inst = {3}", runs, nowstate, e.Sm_ID, e.Sm_Instance); this.Writer(message); System.Collections.Generic.Dictionary validevnts = this._monster.MonsterInputReady.ListEventsFromState("Moving"); if (validevnts.ContainsKey(this.chevnt)) { return this.chevnt; } return null; } Called by the state machine when an event is known to be valid for the current state. The test code logs that the event arived Call Stack
public bool TestInputEventEnemySuspected(object sender, MonsterInputEventArgs e) { EventTextBlock.Text = "EnemySuspected"; string nowstate = this._monster.GetCurrentState(); string runs = " running MonsterEventEnemySuspected"; string message = string.Format("{0} In state {1} [{2}] for id = {3} instance = {4}", runs, nowstate, e.Comment, e.Sm_ID, e.Sm_Instance); this.Writer(message); return true; } Called by the state machine to perform the the action 'LookAbout' Call Stack
public bool TestActionEventLookAbout(object sender, MonsterActionsEventArgs e) { ActionTextBlock.Text = "LookAbout"; string nowstate = this._monster.GetCurrentState(); string runs = " running Action MonsterEvent_LookAbout"; string message = string.Format("{0} In state {1} with id = {2} inst = {3}", runs, nowstate, e.Sm_ID, e.Sm_Instance); this.Writer(message); return true; } |