作者:卡卡西0旗木

泰斗原文:http://www.taidous.com/forum.php?mod=viewthread&tid=32785&_dsign=78057cb0


有限状态机很多人都听过,但是真正理解的人却不多。很多人虽然都也写了FSMState,FSM这样的类。但还是自己处理着状态的跳转,执行等等。
这里要先罗嗦几句了,其实程序员,最重要的还是对基础和概念的理解,真正理解透了,做什么都是很容易的。
对状态机没怎么了解的,可以看看维基百科的解释:http://zh.wikipedia.org/wiki/%E6%9C%89%E9%99%90%E7%8A%B6%E6%80%81%E6%9C%BA
看了上面的介绍,简单来说,FSM就是一个图,这个图的每个结点是一个状态,图还声明了一个节点接收到怎样的输入就会跳转到什么结点。
好了。如果到这里你还不明白FSM,那么再反复好好先看看上面的介绍。然后再来看代码不急。

1、定义一个状态类
组成状态机的基本元素之一就是状态,这里我们先定义这样一个类

[Java] 纯文本查看 复制代码

/**
 * 
 * @author cjunhong
 * @email [email]john.cha@qq.com[/email]
 * @date 2014年12月2日 下午5:45:54
 */
public class FiniteState<T> {

        private final int                                state;
        private IFiniteStateExecutor<T>        stateExecutor;

        /**
         * @param state
         */
        public FiniteState(int state) {
                this.state = state;
        }

        /**
         * 
         * @param fightStateMachine
         * @param t
         * @param now
         * @param duration
         */
        public void doState(FiniteStateMachine<T> fightStateMachine, T t, long now, int duration) {
                stateExecutor.execute(fightStateMachine, t, now, duration);
        }

        /**
         * @param stateExecutor
         *            the stateExecutor to set
         */
        public void setStateExecutor(IFiniteStateExecutor<T> stateExecutor) {
                this.stateExecutor = stateExecutor;
        }

        /**
         * @return the state
         */
        public int getState() {
                return state;
        }

        /*
         * (non-Javadoc)
         * 
         * @see java.lang.Object#toString()
         */
        @Override
        public String toString() {
                return "FightState [state=" + state + "]";
        }

        /**
         * 当切换到状态的时候调用
         */
        public void onInit(FiniteStateMachine<T> stateMac, T t, long now, int duration) {
                stateExecutor.onInit(stateMac, t, now, duration);
        }
}

这个类很简单,state属性在每个状态机中保持唯一即可,表明一个状态值。
stateExecutor属性则是表明在这个状态下要处理的行为,比如:在巡逻状态下,你要控制角色走动,那么stateExecutor就是走路的代码。

2、状态的行为
如果状态机只是状态的跳转,而状态没任何行为,那么它其实意义也不是很大。我们更多的时候是想要处理:在什么状态下,做什么事。
因此,我们这里把“做什么事”这个抽象出来一个接口IFiniteStateExecutor。

[Java] 纯文本查看 复制代码

/**
 * 
 * @author cjunhong
 * @email [email]john.cha@qq.com[/email]
 * @date 2014年12月2日 下午10:20:47
 */
public interface IFiniteStateExecutor<T> {

        /**
         * 
         * @param fightStateMachine
         * @param hoster
         * @param now
         * @param duration
         */
        void execute(FiniteStateMachine<T> fightStateMachine, T hoster, long now, int duration);

        /**
         * 
         */
        void onInit(FiniteStateMachine<T> stateMac, T t, long now, int duration);

}

这个接口很简单,就是定义了这个行为初始化和执行的方法。

3、状态机核心
说了这么多,还没讲道真正状态机的处理。但是如果细心的同学,可以发现上面的代码中都引用了一个FiniteStateMachine的类。没错,这个类正是状态机的核心。
我们先看看代码:

[Java] 纯文本查看 复制代码

/**
 * 
 * @author cjunhong
 * @email [email]john.cha@qq.com[/email]
 * @date 2014年12月2日 下午5:41:37
 */
public class FiniteStateMachine<T> {

        private static final Logger                                                                                LOGGER                                        = LoggerFactory.getLogger(FiniteStateMachine.class);

        private final List<FiniteStateTransaction<T>>                                        TRANSACTION_LIST_HOLDER        = new ArrayList<FiniteStateTransaction<T>>(0);

        private FiniteState<T>                                                                                        lastState;
        private FiniteState<T>                                                                                        currentState;
        private Map<Integer, FiniteState<T>>                                                        allState                                = new HashMap<>();
        private Map<FiniteState<T>, List<FiniteStateTransaction<T>>>        transactions                        = new HashMap<>();

        private Map<String, Integer>                                                                        intParams                                = new HashMap<>();
        private Map<String, Boolean>                                                                        boolParams                                = new HashMap<>();
        private Map<String, Long>                                                                                longParams                                = new HashMap<>();
        private IFiniteStatesProcesser<T>                                                                statesProcesser;
        private IOnFiniteStateChangeProcesser<T>                                                onStateChangeProcesser;

        public FiniteStateMachine(        IFiniteStatesProcesser<T> statesProcesser,
                                                                IOnFiniteStateChangeProcesser<T> onStateChangeProcesser) {
                if (statesProcesser == null) {
                        statesProcesser = new IFiniteStatesProcesser<T>() {
                                @Override
                                public void process(FiniteStateMachine<T> stateMachine,
                                                                        FiniteState<T> currentState,
                                                                        T t,
                                                                        long now,
                                                                        int duration) {
                                }
                        };
                }
                this.statesProcesser = statesProcesser;
                if (onStateChangeProcesser == null) {
                        onStateChangeProcesser = new IOnFiniteStateChangeProcesser<T>() {
                                @Override
                                public void onChange(        FiniteStateMachine<T> stateMachine,
                                                                                T fightScene,
                                                                                FiniteState<T> oldState,
                                                                                FiniteState<T> newState) {
                                }
                        };
                }
                this.onStateChangeProcesser = onStateChangeProcesser;

        }

        /**
         * 将一个状态设置为默认状态
         * 
         * @param state
         */
        public void setDefaultState(int state) {
                FiniteState<T> fightState = allState.get(state);
                if (fightState == null) {
                        throw new NullPointerException("Can not found such state " + state + " as default state.");
                }
                setDefaultState(fightState);
        }

        /**
         * 设置参数
         * 
         * @param key
         * @param value
         */
        public void setInteger(String key, int value) {
                intParams.put(key, value);
        }

        public void setBoolean(String key, boolean value) {
                boolParams.put(key, value);
        }

        public void tick(T t, long now, int duration) {
                if (lastState != currentState) {
                        currentState.onInit(this, t, now, duration);
                        LOGGER.info("Change State -- old state=" + lastState + ", new state=" + currentState);
                        onStateChangeProcesser.onChange(this, t, lastState, currentState);
                        lastState = currentState;
                }
                currentState.doState(this, t, now, duration);
                processOnCurrentState(currentState, t, now, duration);
                checkCurrentState();
        }

        /**
         * 
         * @param currentState
         * @param t
         * @param now
         * @param duration
         */
        public void processOnCurrentState(FiniteState<T> currentState, T t, long now, int duration) {
                statesProcesser.process(this, currentState, t, now, duration);
        }

        /**
         * 检查当前状态,并在需要的时候进行跳转。
         */
        private void checkCurrentState() {
                FiniteState<T> state = null;
                List<FiniteStateTransaction<T>> list = transactions.get(currentState);
                for (FiniteStateTransaction<T> t : list) {
                        if (t.check(intParams, boolParams, longParams)) {
                                state = t.getDstState();
                                break;
                        }
                }
                if (state != null && state != currentState) {
                        currentState = state;
                }
        }

        /**
         * 将一个状态设置为默认状态
         * 
         * @param fightState
         */
        public void setDefaultState(FiniteState<T> fightState) {
                if (fightState == null) {
                        throw new NullPointerException("Default state can not be null.");
                }
                currentState = fightState;
        }

        /**
         * 增加一个状态,如果已存在,则不添加。
         * 
         * @param state
         * @return 返回当前状态。
         */
        public FiniteState<T> addState(int state) {
                FiniteState<T> fightState = allState.get(state);
                if (fightState == null) {
                        fightState = new FiniteState<T>(state);
                        allState.put(state, fightState);

                        if (transactions.get(fightState) == null) {
                                transactions.put(fightState, TRANSACTION_LIST_HOLDER);
                        }
                }
                return fightState;
        }

        /**
         * 
         * @param state
         * @param executor
         * @return
         */
        public FiniteState<T> addState(int state, IFiniteStateExecutor<T> executor) {
                FiniteState<T> addState = addState(state);
                addState.setStateExecutor(executor);
                return addState;
        }

        /**
         * 为两个状态之间添加关联。如果两个状态已经存在关联,则返回该关联。
         * 
         * @param src
         * @param dst
         * @return
         */
        public FiniteStateTransaction<T> addTranscation(FiniteState<T> src, FiniteState<T> dst) {
                List<FiniteStateTransaction<T>> list = transactions.get(src);
                boolean checkContains = true;
                if (list == TRANSACTION_LIST_HOLDER) {
                        list = new LinkedList<>();
                        transactions.put(src, list);
                        checkContains = false;
                }
                FiniteStateTransaction<T> fightTransaction = null;
                if (checkContains) {
                        for (FiniteStateTransaction<T> t : list) {
                                if (t.getDstState() == dst) {
                                        fightTransaction = t;
                                        break;
                                }
                        }
                }
                if (fightTransaction == null) {
                        fightTransaction = new FiniteStateTransaction<T>(dst);
                        list.add(fightTransaction);
                }
                return fightTransaction;
        }

        /*
         * (non-Javadoc)
         * 
         * @see java.lang.Object#toString()
         */
        @Override
        public String toString() {
                return "FightState<T>Machine [currentState=" + currentState + ", intParams=" + intParams + ", boolParams=" + boolParams + "]";
        }

        /**
         * @return the currentState
         */
        public FiniteState<T> getCurrentState() {
                return currentState;
        }
}

tick方法即是状态机的触发,你只要在每帧中调用这个方法,状态机就会自己根据一些输入的情况进行状态跳转,并执行当前状态下应该执行的行为。
tick中调用了checkCurrentState,正是这个方法对当前状态进行检查和跳转。
我们详细看看这段代码:

[Java] 纯文本查看 复制代码

        private void checkCurrentState() {
                FiniteState<T> state = null;
                List<FiniteStateTransaction<T>> list = transactions.get(currentState);
                for (FiniteStateTransaction<T> t : list) {
                        if (t.check(intParams, boolParams, longParams)) {
                                state = t.getDstState();
                                break;
                        }
                }
                if (state != null && state != currentState) {
                        currentState = state;
                }
        }

我们把当前状态跳转到其它状态这样的关系通过一个FiniteStateTransaction的类进行保存。这个类中又包含了跳转的跳转的条件ITransactionCondition。

4、状态跳转FiniteStateTransaction的定义

 

[Java] 纯文本查看 复制代码
/**
 * 
 * @author cjunhong
 * @email [email]john.cha@qq.com[/email]
 * @date 2014年12月2日 下午5:50:58
 */
public class FiniteStateTransaction<T> {

        private List<ITransactionCondition>        list        = new LinkedList<>();
        private FiniteState<T>                                dst;

        /**
         * @param dst
         */
        public FiniteStateTransaction(FiniteState<T> dst) {
                this.dst = dst;
        }

        public void addCondition(ITransactionCondition fightCondition) {
                list.add(fightCondition);
        }

        /**
         * 
         * @param intParams
         * @param boolParams
         * @param longParams
         * @return
         */
        public boolean check(Map<String, Integer> intParams, Map<String, Boolean> boolParams, Map<String, Long> longParams) {
                for (ITransactionCondition c : list) {
                        if (!c.check(intParams, boolParams, longParams)) {
                                return false;
                        }
                }
                return true;
        }

        /**
         * @return
         */
        public FiniteState<T> getDstState() {
                return dst;
        }

}

可以看到这个类中包含了一个条件列表和一个目标状态。
他的check方法就是检查是否所有条件都满足。

5、条件的定义

 

[Java] 纯文本查看 复制代码
public interface ITransactionCondition {

        /**
         * 
         * @param intParams
         * @param boolParams
         * @param longParams
         * @return
         */
        boolean check(Map<String, Integer> intParams, Map<String, Boolean> boolParams, Map<String, Long> longParams);

}


6、条件的一些实现。
我分别实现了布尔值、int、long的条件

[Java] 纯文本查看 复制代码

/**
 * 
 * @author cjunhong
 * @email [email]john.cha@qq.com[/email]
 * @date 2014年12月2日 下午9:49:55
 */
public class BoolCondition implements ITransactionCondition {

        private String        key;
        private boolean        expectValue;

        /**
         * 
         * @param key
         * @param expectValue
         */
        public BoolCondition(String key, boolean expectValue) {
                this.key = key;
                this.expectValue = expectValue;
        }

        @Override
        public boolean check(Map<String, Integer> intParams, Map<String, Boolean> boolParams, Map<String, Long> longParams) {
                Boolean currBool = boolParams.get(key);
                if (currBool == null) {
                        return false;
                }
                return currBool == expectValue;
        }

}

[Java] 纯文本查看 复制代码

/**
 * 
 * @author cjunhong
 * @email [email]john.cha@qq.com[/email]
 * @date 2014年12月2日 下午9:38:25
 */
public class IntCondition implements ITransactionCondition {

        public static final byte        EQUALS                = 0;
        public static final byte        SMALLER                = 1;
        public static final byte        LARGER                = 2;
        public static final byte        NOT_EQUALS        = 3;

        private String                                key;
        private byte                                compareType;
        private int                                        compareValue;

        /**
         * 
         * @param key
         * @param compareType
         * @param compareValue
         */
        public IntCondition(String key, byte compareType, int compareValue) {
                this.key = key;
                this.compareType = compareType;
                this.compareValue = compareValue;
                if (compareType != EQUALS && compareType != LARGER && compareType != SMALLER) {
                        throw new IllegalArgumentException("compareType can noly be one of the IntCondition.EQUALS、IntCondition.LARGER、IntCondition.SMALLER");
                }
        }

        @Override
        public boolean check(Map<String, Integer> intParams, Map<String, Boolean> boolParams, Map<String, Long> longParams) {
                Integer integer = intParams.get(key);
                if (integer == null) {
                        return false;
                }
                switch (compareType) {
                case EQUALS:
                        return integer == compareValue;
                case LARGER:
                        return integer > compareValue;
                case SMALLER:
                        return integer < compareValue;
                case NOT_EQUALS:
                        return integer != compareValue;
                }
                return false;
        }
}

[Java] 纯文本查看 复制代码

/**
 * 
 * @author cjunhong
 * @email [email]john.cha@qq.com[/email]
 * @date 2014年12月2日 下午9:38:25
 */
public class LongCondition implements ITransactionCondition {

        public static final byte        EQUALS                = 0;
        public static final byte        SMALLER                = 1;
        public static final byte        LARGER                = 2;
        public static final byte        NOT_EQUALS        = 3;

        private String                                key;
        private byte                                compareType;
        private long                                compareValue;

        /**
         * 
         * @param key
         * @param compareType
         * @param compareValue
         */
        public LongCondition(String key, byte compareType, long compareValue) {
                this.key = key;
                this.compareType = compareType;
                this.compareValue = compareValue;
                if (compareType != EQUALS && compareType != LARGER && compareType != SMALLER) {
                        throw new IllegalArgumentException("compareType can noly be one of the IntCondition.EQUALS、IntCondition.LARGER、IntCondition.SMALLER");
                }
        }

        @Override
        public boolean check(Map<String, Integer> intParams, Map<String, Boolean> boolParams, Map<String, Long> longParams) {
                Long integer = longParams.get(key);
                if (integer == null) {
                        return false;
                }
                switch (compareType) {
                case EQUALS:
                        return integer == compareValue;
                case LARGER:
                        return integer > compareValue;
                case SMALLER:
                        return integer < compareValue;
                case NOT_EQUALS:
                        return integer != compareValue;
                }
                return false;
        }
}


7、其它接口
上面已经看完了整个FSM大致的类和接口的设计了。大家可以发现FiniteStateMachine的构造方法中还传入两个接口:
        IFiniteStatesProcesser<T> statesProcesser,
        IOnFiniteStateChangeProcesser<T> onStateChangeProcesser
先看看代码,这两个接口主要分别用于状态机的输入和当状态改变时的通知。

[Java] 纯文本查看 复制代码

public interface IFiniteStatesProcesser<T> {

        /**
         * 
         * @param stateMachine
         * @param currentState
         * @param hoster
         * @param now
         * @param duration
         */
        void process(FiniteStateMachine<T> stateMachine, FiniteState<T> currentState, T hoster, long now, int duration);
}

[Java] 纯文本查看 复制代码

/**
 * 
 * @author cjunhong
 * @email [email]john.cha@qq.com[/email]
 * @date 2014年12月7日 下午5:02:03
 */
public interface IOnFiniteStateChangeProcesser<T> {

        /**
         * 
         * @param stateMachine
         * @param hoster
         * @param oldState
         * @param newState
         */
        void onChange(FiniteStateMachine<T> stateMachine, T hoster, FiniteState<T> oldState, FiniteState<T> newState);

}


8、怎么用
看了上面那么多代码,头晕了。怎么用这个状态机。
看看下面的测试代码:

[Java] 纯文本查看 复制代码

package com.duoyu001.framework.game.fsm;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.duoyu001.framework.game.fsm.condition.impl.BoolCondition;
import com.duoyu001.framework.game.fsm.condition.impl.IntCondition;

/**
 *
 * @author cjunhong
 * @email [email]john.cha@qq.com[/email]
 * @date 2015年1月10日 下午9:58:12
 */
public class TestFSM {

        private static final Logger        LOGGER        = LoggerFactory.getLogger(TestFSM.class);

        static class Monster {
                private boolean        target;
                private int                distance2Target        = 800;
                private int                targetHP                = 3;
        }

        private static final int        STATE_WAIT                        = 0;
        private static final int        STATE_BATTLE                = 1;
        private static final int        STATE_CHARSE                = 2;

        private static final String        KEY_TARGET_EXIST        = "tar";
        private static final String        KET_DISTANCE                = "dis";
        private static final String        KEY_TARGET_DEAD                = "tarDead";

        private static final int        ATTACK_RANGE                = 300;

        /**
         * @param args
         */
        public static void main(String[] args) {
                FiniteStateMachine<Monster> finiteStateMachine = new FiniteStateMachine<Monster>(        createStatesProcesser(),
                                                                                                                                                                                        createOnStateChangeProcesser());
                FiniteState<Monster> wait = finiteStateMachine.addState(STATE_WAIT);
                wait.setStateExecutor(new IFiniteStateExecutor<TestFSM.Monster>() {
                        @Override
                        public void onInit(FiniteStateMachine<Monster> stateMac, Monster t, long now, int duration) {
                        }

                        @Override
                        public void execute(FiniteStateMachine<Monster> fightStateMachine, Monster hoster, long now, int duration) {
                                LOGGER.info("待机中");
                                hoster.target = true;
                        }
                });

                FiniteState<Monster> battle = finiteStateMachine.addState(STATE_BATTLE);
                battle.setStateExecutor(new IFiniteStateExecutor<TestFSM.Monster>() {
                        @Override
                        public void onInit(FiniteStateMachine<Monster> stateMac, Monster t, long now, int duration) {
                        }

                        @Override
                        public void execute(FiniteStateMachine<Monster> fightStateMachine, Monster hoster, long now, int duration) {
                                LOGGER.info("战斗中, 目标剩余血量=" + hoster.targetHP);
                                hoster.targetHP--;
                                if (hoster.targetHP < 0) {
                                        hoster.targetHP = 0;
                                }
                        }
                });

                FiniteState<Monster> charse = finiteStateMachine.addState(STATE_CHARSE);
                charse.setStateExecutor(new IFiniteStateExecutor<TestFSM.Monster>() {
                        @Override
                        public void onInit(FiniteStateMachine<Monster> stateMac, Monster t, long now, int duration) {
                        }

                        @Override
                        public void execute(FiniteStateMachine<Monster> fightStateMachine, Monster hoster, long now, int duration) {
                                hoster.distance2Target -= 250;
                                if (hoster.distance2Target < 0) {
                                        hoster.distance2Target = 0;
                                }
                                LOGGER.info("追击中,距离=" + hoster.distance2Target);
                        }
                });

                finiteStateMachine.setDefaultState(wait);

                // 待机>战斗
                // 存在目标
                FiniteStateTransaction<Monster> wait2Battle = finiteStateMachine.addTranscation(wait, battle);
                wait2Battle.addCondition(new BoolCondition(KEY_TARGET_EXIST, true));

                // 追击>战斗
                // 和目标的距离小于攻击距离
                FiniteStateTransaction<Monster> move2Battle = finiteStateMachine.addTranscation(charse, battle);
                move2Battle.addCondition(new IntCondition(KET_DISTANCE, IntCondition.SMALLER, ATTACK_RANGE));

                // 追击>待机
                // 目标死亡
                FiniteStateTransaction<Monster> move2Wait = finiteStateMachine.addTranscation(charse, wait);
                move2Wait.addCondition(new BoolCondition(KEY_TARGET_DEAD, true));

                // 战斗>移动
                // 和目标的距离大于攻击距离
                FiniteStateTransaction<Monster> battle2Move = finiteStateMachine.addTranscation(battle, charse);
                battle2Move.addCondition(new IntCondition(KET_DISTANCE, IntCondition.LARGER, ATTACK_RANGE));

                // 战斗>待机
                // 目标死亡
                FiniteStateTransaction<Monster> battle2Wait = finiteStateMachine.addTranscation(battle, wait);
                battle2Wait.addCondition(new BoolCondition(KEY_TARGET_DEAD, true));

                Monster m = new Monster();
                for (int i = 0; i < 10; i++) {
                        finiteStateMachine.tick(m, 0, 0);
                }
        }

        /**
         * @return
         */
        private static IOnFiniteStateChangeProcesser<Monster> createOnStateChangeProcesser() {
                // TODO Auto-generated method stub
                return null;
        }

        /**
         * @return
         */
        private static IFiniteStatesProcesser<Monster> createStatesProcesser() {
                return new IFiniteStatesProcesser<TestFSM.Monster>() {

                        @Override
                        public void process(FiniteStateMachine<Monster> stateMachine,
                                                                FiniteState<Monster> currentState,
                                                                Monster hoster,
                                                                long now,
                                                                int duration) {
                                stateMachine.setBoolean(KEY_TARGET_EXIST, hoster.target);
                                stateMachine.setBoolean(KEY_TARGET_DEAD, hoster.targetHP == 0);
                                stateMachine.setInteger(KET_DISTANCE, hoster.distance2Target);
                        }
                };
        }

}


运行一下,打印下面内容:
23:52:23.682 [main] INFO  c.d.f.game.fsm.FiniteStateMachine - Change State -- old state=null, new state=FightState [state=0]
23:52:23.685 [main] INFO  c.d.framework.game.fsm.TestFSM - 待机中
23:52:23.685 [main] INFO  c.d.f.game.fsm.FiniteStateMachine - Change State -- old state=FightState [state=0], new state=FightState [state=1]
23:52:23.685 [main] INFO  c.d.framework.game.fsm.TestFSM - 战斗中, 目标剩余血量=3
23:52:23.685 [main] INFO  c.d.f.game.fsm.FiniteStateMachine - Change State -- old state=FightState [state=1], new state=FightState [state=2]
23:52:23.685 [main] INFO  c.d.framework.game.fsm.TestFSM - 追击中,距离=550
23:52:23.685 [main] INFO  c.d.framework.game.fsm.TestFSM - 追击中,距离=300
23:52:23.685 [main] INFO  c.d.framework.game.fsm.TestFSM - 追击中,距离=50
23:52:23.685 [main] INFO  c.d.f.game.fsm.FiniteStateMachine - Change State -- old state=FightState [state=2], new state=FightState [state=1]
23:52:23.685 [main] INFO  c.d.framework.game.fsm.TestFSM - 战斗中, 目标剩余血量=2
23:52:23.685 [main] INFO  c.d.framework.game.fsm.TestFSM - 战斗中, 目标剩余血量=1
23:52:23.685 [main] INFO  c.d.f.game.fsm.FiniteStateMachine - Change State -- old state=FightState [state=1], new state=FightState [state=0]
23:52:23.685 [main] INFO  c.d.framework.game.fsm.TestFSM - 待机中
23:52:23.685 [main] INFO  c.d.f.game.fsm.FiniteStateMachine - Change State -- old state=FightState [state=0], new state=FightState [state=1]
23:52:23.685 [main] INFO  c.d.framework.game.fsm.TestFSM - 战斗中, 目标剩余血量=0
23:52:23.685 [main] INFO  c.d.f.game.fsm.FiniteStateMachine - Change State -- old state=FightState [state=1], new state=FightState [state=0]
23:52:23.685 [main] INFO  c.d.framework.game.fsm.TestFSM - 待机中

好了,上面测试例子只是一个简单的怪物AI。真实游戏中的AI会比这个复杂的多,大家可以利用状态机自行进行设计~。
对了,上面用的是Java。但是没事,原理是一样的~大家可以自行根据需要转成其它语言的~~~我就是同时写C#和Java的,语言只是工具嘛~~~