状态机_fsm(Finite State Machine)

一.状态机


状态机

二.个人理解的状态机


个人理解的状态机.jpg

三.自己搭建一个状态机


搭建状态机步骤

状态机,管理多个状态,每个状态有多个动作,状态下动作的改变切换到另一个状态
1.创建状态机的管理(Manager)
using UnityEngine;
using System.Collections;

namespace SpacePlanner
{
    /// <summary>
    /// 处理用户的一些复杂输入,并不是全部
    /// 尤其是那些一步一步进行的操作
    /// </summary>
    public class UserInputHandler : MonoBehaviour
    {
        public bool IsRunning
        {
            get
            {
                return fsm != null;
            }
        }

        static UserInputHandler _instance;
        public static UserInputHandler Instance
        {
            get
            {
                if (_instance == null)
                {
                    GameObject go = new GameObject("UserInputHandler");
                    _instance = go.AddComponent<UserInputHandler>();
                }
                return _instance;
            }
        }
        
        FSM4InputHandler fsm;       
        void Update()//状态机的执行入口
        {
            if (fsm != null)
                fsm.Run();
        }

        public void StartHandleBuildWallInput()
        {
            fsm = new FSM4InputHandler();


            var tmpState = new State(fsm, "StartState");
            tmpState.AddAction(new MouseClickToStart("InBuildWallState"));
            tmpState.AddAction(new MouseMoveBeforeBuild());
            tmpState.AddAction(new MouseRightClickToStop());
            fsm.AddState(tmpState);
            fsm.curState = tmpState;

            tmpState = new State(fsm, "InBuildWallState");
            tmpState.AddAction(new MouseRightClickToStop());
            tmpState.AddAction(new MouseClickToContinue("StartState"));
            tmpState.AddAction(new MouseMoveInBuild());
            fsm.AddState(tmpState);

        }

   //     public void StartHandleBuildWallInput()
   //     {
   //         fsm = new FSM4InputHandler();
          
   //         var tmpState = new State(fsm, "StartState");
   //         tmpState.AddAction(new MouseClickToStart("InBuildWallState"));
            //tmpState.AddAction(new MouseMoveBeforeBuild());
   //         tmpState.AddAction(new MouseRightClickToStop());
   //         fsm.AddState(tmpState);
   //         fsm.curState = tmpState;

   //         tmpState = new State(fsm, "InBuildWallState");
   //         tmpState.AddAction(new MouseRightClickToStop());
   //         tmpState.AddAction(new MouseClickToContinue());
   //         tmpState.AddAction(new MouseMoveInBuild());
   //         fsm.AddState(tmpState);
           
   //     }

        public void StartHandleBuildAreaInput()
        {
            fsm = new FSM4InputHandler();
            //var tmpState = new State(fsm, "StartState");
            //tmpState.AddAction(new MoveBeforBuildArea());
            //tmpState.AddAction(new ClickToStartBuildArea("InBuildAreaState"));
            //fsm.AddState(tmpState);
            //fsm.curState = tmpState;

            var tmpState = new State(fsm, "InBuildAreaState");
            tmpState.AddAction(new MoveInBuildArea());
            tmpState.AddAction(new ClickToContinueBuildArea());
            tmpState.AddAction(new RightClickToStopBuildArea());
            fsm.AddState(tmpState);
            fsm.curState = tmpState;
        }

        public void StartHandleBuildDoorInput()
        {
            fsm = new FSM4InputHandler();

            var tmpState = new State(fsm, "StartState");
            tmpState.AddAction(new MouseMoveBeforeAddDoor());
            tmpState.AddAction(new MouseClickToAddDoor());
            tmpState.AddAction(new MouseRightClickToStopAddDoor());
            fsm.AddState(tmpState);
            fsm.curState = tmpState;
        }


        /// <summary>
        /// Alan添加的建立户型状态机控制
        /// </summary>
        public void StartHandleBuildUnitInput()
        {
            fsm = new FSM4InputHandler();

            var tmpState = new State(fsm, "StartState");
            tmpState.AddAction(new MouseMoveBeforeAddUnit());
            tmpState.AddAction(new MouseClickToAddUnit());
            tmpState.AddAction(new MouseRightClickToStopAddUnit());
            fsm.AddState(tmpState);
            fsm.curState = tmpState;
        }

        public void StartHandleBuildWinInput()
        {
            fsm = new FSM4InputHandler();
            var tmpState = new State(fsm, "StartState");
            tmpState.AddAction(new MouseMoveBeforeBuildWin());
            tmpState.AddAction(new MouseClickToBuildWin());
            tmpState.AddAction(new MouseRightClickToStopBuildWindow());
            fsm.AddState(tmpState);
            fsm.curState = tmpState;
        }

        //public void StartHandleBuildHandrailInput()
        //{
        //  fsm = new FSM4InputHandler();
        //  var tmpState = new State(fsm, "StartState");
        //  tmpState.AddAction(new MouseMoveBeforeAddHandrail());
        //  tmpState.AddAction(new MouseClickToAddHandrail());
        //  tmpState.AddAction(new MouseRightClickToStopAddHandrail());
        //  fsm.AddState(tmpState);
        //  fsm.curState = tmpState;
        //}

        public void StartHandleBuildPillarInput()
        {
            fsm = new FSM4InputHandler();
            var tmpState = new State(fsm, "StartState");
            tmpState.AddAction(new MouseMoveBeforeAddSpaceObject());
            tmpState.AddAction(new MouseClickToAddSpaceObject());
            tmpState.AddAction(new MouseRightClickToStopAddSpaceObject());
            fsm.AddState(tmpState);
            fsm.curState = tmpState;
        }

        public void StartSetApartmentMapMeasureInput()
        {
            fsm = new FSM4InputHandler();

            var tmpState = new State(fsm, "StartState");
            tmpState.AddAction(new MouseClickToStartSetMeasure("InSetApartmentMapMeasureState"));
            tmpState.AddAction(new MouseRightClickToStopSetMeasure());
            fsm.AddState(tmpState);
            fsm.curState = tmpState;

            tmpState = new State(fsm, "InSetApartmentMapMeasureState");
            tmpState.AddAction(new MouseClickToFinishSetMeasure());
            tmpState.AddAction(new MouseRightClickToStopSetMeasure());
            tmpState.AddAction(new MouseMoveInSetMeasure());
            fsm.AddState(tmpState);
        }
       具体分析这个状态机的例子
       1.2个状态"StartState"状态,"InBuildWallState"状态
       2"StartState"状态的三个动作MouseClickToStartMeasure,MouseMoveBeforeMeasure,MouseRightClickToStopMeasure
       3"InBuildWallState"状态的三个动作MouseMoveInMeasure,MouseClickToContinueMeasure,MouseRightClickToStopMeasure
       4 状态下的动作切换到另一个状态
        public void StartHandleMeasureInput()
        {
            fsm = new FSM4InputHandler();


            var tmpState = new State(fsm, "StartState");
            tmpState.AddAction(new MouseClickToStartMeasure("InBuildWallState"));
            tmpState.AddAction(new MouseMoveBeforeMeasure());
            tmpState.AddAction(new MouseRightClickToStopMeasure());
            fsm.AddState(tmpState);
            fsm.curState = tmpState;

            tmpState = new State(fsm, "InBuildWallState");
            tmpState.AddAction(new MouseRightClickToStopMeasure());
            tmpState.AddAction(new MouseClickToContinueMeasure("StartState"));
            tmpState.AddAction(new MouseMoveInMeasure());
            fsm.AddState(tmpState);

        }

        public void StopHandleInput() // 关闭状态机
        {
            fsm = null;
        }
    }
}

2.状态控制(入口)

using UnityEngine;
using System.Collections;
using System.Collections.Generic;

namespace SpacePlanner
{
    public static class FSM_CACHE_KEY
    {
        public static readonly string SELECTED = "SELECTED";
    }

    public class FSM4InputHandler
    {
        IDictionary<string, State> states = new Dictionary<string, State>();//所有的状态

        public State curState;//当前的状态
        public State GetState(string name)
        {
            return states[name];
        }
        
        public void Run()
        {
            curState = curState.OnStay();
        }

        State startState;
        public State StartState
        {
            get
            {
                return startState;
            }
            set { startState = value; }
        }

        public void AddState(State state)
        {
            if (!states.ContainsKey(state.name))
            {
                states.Add(state.name, state);
                if (states.Count == 1)
                    StartState = state;

            }
        }
    }
}

3.状态控制(State)

using UnityEngine;
using System.Collections;
using System.Collections.Generic;

namespace SpacePlanner
{
    /// <summary>
    /// 用户所处的交互状态
    /// </summary>
    public class State
    {
        public string name;//状态的名字
        public FSM4InputHandler fsm;//所属的状态机

        public State(FSM4InputHandler fsm, string name)
        {
            this.fsm = fsm;
            this.name = name;
            this.actions = new List<StateAction>();
        }

        protected List<StateAction> actions;//在这个状态下的所用动作都保留下来

        public void AddAction(StateAction action)
        {
            actions.Add(action);
            action.SetFSM(fsm);
        }
        ____状态机的执行方法与切换________
        /// <summary>
        /// 处于该状态下时需要执行的方法
        /// </summary>
        /// <returns>下一个状态</returns>
        public virtual State OnStay()
        {
            foreach (var action in actions)
            {
                try
                {
                    if (action.Execute() && action.nextState != null)
                        return fsm.GetState(action.nextState);
                }
                catch (System.Exception e)
                {
                    Debug.Log(e.ToString());
                    Debug.Log("状态机执行action异常,转到初始状态");
                    return fsm.StartState;
                }
            }

            return this;
        }
    }
}

4.动作的抽象方法

using UnityEngine;
using System.Collections;
using System;


namespace SpacePlanner
{
    public abstract class StateAction
    {
        public StateAction() { } //没有状态的切换
        public StateAction(string nextState)//有状态的切换
        {
            this.nextState = nextState;
        }
        FSM4InputHandler _fsm;
        public FSM4InputHandler FSM
        {
            get { return _fsm; }
        }
        public void SetFSM(FSM4InputHandler fsm)
        {
            _fsm = fsm;
        }
        public string nextState = null;
        public abstract bool Execute();//这个方法时核心,让每个状态下不同的动作重写该方法,从而达到不一样的效果
    }
    
  
}

5.动作的执行方法(每个状态下都有多个动作,每个动作的具体效果的实施)

MouseClickToStartMeasure

using UnityEngine;
using System.Collections;
using System;

namespace SpacePlanner
{
    public class MouseClickToStartMeasure : StateAction
    {
        public MouseClickToStartMeasure(string nextState) : base(nextState)
        {
        }

        public override bool Execute()
        {
            var uiMgr = UIManager.Instance;
            if (uiMgr.ClickOnDrawingPanel())
            {
#if UNITY_ANDROID || UNITY_IPHONE
                uiMgr.DrawingPanel.SetAuxiliaryMeasureActive(false);
#endif
                Vector3 screenPos = uiMgr.ClickDrawingPanelData.position;
                Vector3 rwPos = TransformHelper.ScreenToRealWorldPoint(screenPos);
                Debug.Log("鼠标点击开始测量" + screenPos + rwPos + TransformHelper.ScreenToUISpacePoint(screenPos, uiMgr.DrawingPanel.transform, false));
                //SPApplication.Instance.SendNotification(MVCNotifications.TO_C_BEGIN_BUILD_WALL, new BoolAndVec(rwPos, true));
                SPApplication.Instance.SendNotification(MVCNotifications.TO_C_BEGIN_MEASURE, new BoolAndVec(rwPos, true));
                RulerManager.Instance.ClearCurRulers();
                return true;
            }
            return false;
        }
    }
}

MouseMoveBeforeMeasure

using UnityEngine;
using System.Collections;
using System;

namespace SpacePlanner
{
    public class MouseMoveBeforeMeasure : StateAction
    {
        public MouseMoveBeforeMeasure() : base()
        {
        }

        public override bool Execute()
        {
            var uiMgr = UIManager.Instance;
            if (uiMgr.IsPointerOverDrawingPanel())
            {
#if UNITY_EDITOR || UNITY_STANDALONE
                Vector3 screenPos = Input.mousePosition;
#elif UNITY_ANDROID || UNITY_IPHONE
                Vector3 screenPos = uiMgr.DragDrawingPanelData.position;
#endif
                Vector3 rwPos = TransformHelper.ScreenToRealWorldPoint(screenPos);
                //VOAndVector3 data = new VOAndVector3(null, rwPos);
                MeasurePointAndVector data = new MeasurePointAndVector(null,rwPos);
                //Debug.Log("鼠标移动在测量之前"+rwPos);
                //SPApplication.Instance.SendNotification(MVCNotifications.TO_C_UPDATE_AUXILIARY_LINE, data);
                SPApplication.Instance.SendNotification(MVCNotifications.TO_C_UPDATE_AUXILIARY_LINE_MEASURE, data);
                //FPBApplication.Instance.SendNotification(ApplicationConstants.TO_V_POINTER_MOVE_WHEN_DRAW_WALL, screenPos);
            }

            return false;
        }
    }
}

MouseRightClickToStopMeasure

using UnityEngine;
using System.Collections;
using System;

namespace SpacePlanner
{
    public class MouseRightClickToStopMeasure : StateAction
    {
        public MouseRightClickToStopMeasure() : base()
        {
        }

        public override bool Execute()
        {
//#if UNITY_EDITOR || UNITY_STANDALONE
            if (Input.GetMouseButtonDown(1))
//#elif UNITY_ANDROID || UNITY_IPHONE
//            //if (UIManager.Instance.IsTouchReleased())
                 //SendNotification(MVCNotifications.TO_V_CLEAR_AUXILIARY_WALL_MEASURE);// 关掉辅助墙
//#endif
            {
                //画墙结束后把UIFloatExitButton隐藏掉
                //GameObject uiFloatPanel = GameObject.Find("UIFloatExitButton(Clone)");
                //uiFloatPanel.SetActive(false);   
                //SPApplication.Instance.SendNotification(MVCNotifications.TO_C_STOP_BUILD_WALL_MEASURE, DrawingSelection.selectedObject);
                SPApplication.Instance.SendNotification(MVCNotifications.TO_C_STOP_BUILD_WALL_MEASURE, DrawingSelection.SelectMeasurePoint);
                //DrawingSelection.selectedObject = null;
                DrawingSelection.SelectMeasurePoint = null;
                CursorManager.Instance.setNormalCursor();
                return true;
            }
            return false;
        }
    }
}

2.测量状态下的动作

MouseMoveInMeasure

using UnityEngine;
using System.Collections;
using System;
using SpacePlanner.Core.DataStructure;

namespace SpacePlanner
{
    public class MouseMoveInMeasure : StateAction
    {
        public MouseMoveInMeasure() : base()
        {
        }

        public override bool Execute()
        {
            var uiMgr = UIManager.Instance;
            MeasurePoint measurePoint = DrawingSelection.SelectMeasurePoint;
            if (uiMgr.IsPointerOverDrawingPanel())
            {
#if UNITY_EDITOR || UNITY_STANDALONE
                Vector3 screenPos = Input.mousePosition;
#elif UNITY_ANDROID || UNITY_IPHONE
                //Vector3 screenPos = uiMgr.DragDrawingPanelData.position;

                Vector3 endPos = uiMgr.DragDrawingPanelData.position;
                Vector3 dir = (measurePoint.Start - endPos).normalized;
                float circleRadius = 100f;
                Vector3 screenPos = endPos + dir * circleRadius;
#endif
                Vector3 rwPos = TransformHelper.ScreenToRealWorldPoint(screenPos);
                Wall wall = DrawingSelection.selectedObject as Wall;
                VOAndVector3 data = new VOAndVector3(wall, rwPos);
                //MeasurePoint measurePoint = DrawingSelection.SelectMeasurePoint;
                MeasurePointAndVector data1 = new MeasurePointAndVector(measurePoint,rwPos);
                //Debug.Log("在测量时移动鼠标" + screenPos + rwPos);
                SPApplication.Instance.SendNotification(MVCNotifications.TO_C_UPDATE_AUXILIARY_WALL_MEASURE, data1);
                SPApplication.Instance.SendNotification(MVCNotifications.TO_C_UPDATE_AUXILIARY_LINE_MEASURE, data1);
                //FPBApplication.Instance.SendNotification(ApplicationConstants.TO_V_POINTER_MOVE_WHEN_DRAW_WALL, screenPos);
            }

            return false;
        }
    }
}

MouseClickToContinueMeasure

using UnityEngine;
using System.Collections;
using System;
using SpacePlanner.Core.DataStructure;
using PureMVC.Patterns;

namespace SpacePlanner
{
    public class MouseClickToContinueMeasure : StateAction
    {
        public MouseClickToContinueMeasure(string nextState) : base(nextState)
        {
        }

        public override bool Execute()
        {
            var uiMgr = UIManager.Instance;

            Vector3 screenPos = uiMgr.ClickDrawingPanelData.position;
            Vector3 rwPos = TransformHelper.ScreenToRealWorldPoint(screenPos);
            Debug.Log("鼠标点击结束画一面墙" + screenPos + rwPos + TransformHelper.ScreenToUISpacePoint(screenPos, uiMgr.DrawingPanel.transform, false));
            Wall wall = DrawingSelection.selectedObject as Wall;
            MeasurePoint measurePoint = DrawingSelection.SelectMeasurePoint;
            UndoManager.Instance.AddNotification();

#if UNITY_EDITOR || UNITY_STANDALONE
            if (uiMgr.ClickOnDrawingPanel())
            {
                
                //SPApplication.Instance.SendNotification(MVCNotifications.TO_C_BUILD_ONE_WALL_DONE_MEASURE, wall);
                SPApplication.Instance.SendNotification(MVCNotifications.TO_C_BUILD_ONE_WALL_DONE_MEASURE, measurePoint);
                //UndoManager.Instance.AddNotification(new Notification(MVCNotifications.TO_C_BUILD_ONE_WALL_DONE, wall));// 添加命令到UndoManager里
                return true;
            }
#elif UNITY_ANDROID || UNITY_IPHONE
            if (uiMgr.IsTouchReleased())
             {
                          
                //SPApplication.Instance.SendNotification(MVCNotifications.TO_C_BUILD_ONE_WALL_DONE_MEASURE, wall);
                SPApplication.Instance.SendNotification(MVCNotifications.TO_C_BUILD_ONE_WALL_DONE_MEASURE_ANDROID, measurePoint);               
                //UndoManager.Instance.AddNotification(new Notification(MVCNotifications.TO_C_BUILD_ONE_WALL_DONE, wall));// 添加命令到UndoManager里
                return true;
              }
#endif
            {
                RulerManager.Instance.DisplayAllWallRuler();// 刷新标尺
            }
            return false;
        }
    }


}

MouseRightClickToStopMeasure

using UnityEngine;
using System.Collections;
using System;

namespace SpacePlanner
{
    public class MouseRightClickToStopMeasure : StateAction
    {
        public MouseRightClickToStopMeasure() : base()
        {
        }

        public override bool Execute()
        {
//#if UNITY_EDITOR || UNITY_STANDALONE
            if (Input.GetMouseButtonDown(1))
//#elif UNITY_ANDROID || UNITY_IPHONE
//            //if (UIManager.Instance.IsTouchReleased())
                 //SendNotification(MVCNotifications.TO_V_CLEAR_AUXILIARY_WALL_MEASURE);// 关掉辅助墙
//#endif
            {
                //画墙结束后把UIFloatExitButton隐藏掉
                //GameObject uiFloatPanel = GameObject.Find("UIFloatExitButton(Clone)");
                //uiFloatPanel.SetActive(false);   
                //SPApplication.Instance.SendNotification(MVCNotifications.TO_C_STOP_BUILD_WALL_MEASURE, DrawingSelection.selectedObject);
                SPApplication.Instance.SendNotification(MVCNotifications.TO_C_STOP_BUILD_WALL_MEASURE, DrawingSelection.SelectMeasurePoint);
                //DrawingSelection.selectedObject = null;
                DrawingSelection.SelectMeasurePoint = null;
                CursorManager.Instance.setNormalCursor();
                return true;
            }
            return false;
        }
    }
}

总结一下状态机的流程(注意事项)
1.有状态切换的动作,stateAction的构造函数不一样,需要把状态传过去。
2.状态,动作,动作改变状态。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,923评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,154评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,775评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,960评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,976评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,972评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,893评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,709评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,159评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,400评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,552评论 1 346
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,265评论 5 341
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,876评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,528评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,701评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,552评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,451评论 2 352

推荐阅读更多精彩内容

  • 状态机是无论科研探索还是科技应用方面都非常重要的一种分析工具。几乎在所有涉及到随时间演化的问题中,都可以找到状态机...
    Esmool阅读 4,414评论 0 26
  • iOS APP上架流程详解 字数2714 阅读100 评论0 喜欢1 前言:作为一名 iOS 开发工程师, APP...
    EverythingIsOk阅读 267评论 0 0
  • 这个系列最终实现的状态机并不是一个标准的状态机,把状态机的很多标准的概念进行了简化,对概念的东西做了减法,实现了具...
    iPolaris阅读 34,843评论 2 40
  • 在研究Raft算法的时候,看到其是使用状态机实现的,于是找了一篇论文,了解了一下状态机. 论文原文为Impleme...
    AlstonWilliams阅读 3,142评论 0 4
  • 从母系社会以后,历史好像都是由男人主导着、推进着。氏族社会之后的的炎黄,再之后的尧、舜、禹等等,其首领或者统治者都...
    史七阅读 169评论 0 0