国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

雙層狀態機實現避免卡死的指引

2019-11-09 18:13:39
字體:
來源:轉載
供稿:網友

該指引系統的主要特性:

引入狀態機實現指引系統,使指引狀態切換和步驟控制更加清晰。指引系統不是絕對強制的指引,達成跳過條件時,指引是可以跳過的。指引有意外掛起檢測,當指引因為某些原因無法進行下去時(例如所在界面不對),會自動重置該條指引。指引完成條件的達成依賴于服務器回復,而不是簡單的客戶端點擊事件。指引步驟封裝,一條指引的多個步驟只用一個指令實現,使指引的流程在程序可控的范圍內。

實例與主要思路:

假設有一條指引:引導建造一個食品廠。完成第該指引要分成兩步,第一步,選擇可建造空地并打開建造界面;第二步,點擊建筑按鈕完成建造食品廠的指引。 對于上述描述的情形可以抽象兩層狀態機。第一層狀態機控制一條指引的開始、運行、完成的流程然后轉到下一條指引,我稱之為流程狀態機。第二層狀態機控制某條指引的具體步驟:選擇空地、開打界面、點擊按鈕等,我稱之為步驟狀態機。

偽代碼:

由于該指引系統應用到公司的實際項目,這里只給出偽代碼和完整注釋。

流程狀態機的狀態:public enum GuideState{ none = 0, //default start = 1, //指引開始 running = 2, //指引進行中,此時喚醒了一個步驟狀態機 pause = 3, //指引被暫停 complete = 4, //指引完成 hangup = 5, //指引內部主動掛機 waitResponse = 6, //等待服務器回復,收到服務器回復后完成指引}步驟狀態機的狀態:public enum GuideStep{ PRepare = 0, //準備 step01 = 1, //以下10個狀態表示10個不同的步驟 step02 = 2, step03 = 3, step04 = 4, step05 = 5, step06 = 6, step07 = 7, step08 = 8, step09 = 9, step10 = 10, playerInput = 99, //等待玩家輸入 hangup = 100, //主動掛起 hangupUnexpect = 101, //意外掛起 complete = 102, //完成}指引類的變量申明及初始化,可略過:public class BGuide : MonoBehaviour{ private static BGuide instance; [SerializeField] private GuideState guideState = GuideState.none; private GuideState GuideState { get { return guideState; } set { if (guideState == GuideState.none && value != GuideState.start) return; guideState = value; } } private Dictionary<string, Guide> guideMapper = new Dictionary<string, Guide>(); //待完成指引的字典 [HideInInspector] public List<string> happendList; //已完成指引列表 private string spawnGuideId = string.Empty; //activeGuide的spwans索引 private Guide activeGuide = null; //當前激活的指引 [SerializeField] private GuideStep guideStep = GuideStep.prepare; private int guideStepCount = 0; private float guideInterval = 0.5f; private float guideStepInterval = 0.3f; private Coroutine stepStateMachine; private GameObject arrowGo = null; private GuideMask guideMask = null; private Sequence activeGuideCompleteSequence = null; public static BGuide Instance { get { if (instance == null) { instance = new GameObject("BGuide").AddComponent<BGuide>(); } return instance; } } public void Init() { GuideState = GuideState.none; happendList = GetHappenedGuideList(); //初始化已完成指引列表 //獲取所有待完成指引,并排序 Dictionary<string, Guide> dic = GetTotalGuideMapper(); List<Guide> guideList = new List<Guide>(); foreach (KeyValuePair<string, Guide> kv in dic) { Guide guide = kv.Value; if (!happendList.Contains(guide.id) && guide.weak != 2) { guideList.Add(guide); } } guideList.Sort ( (Guide a, Guide b) => { return a.guideOrder - b.guideOrder; } ); guideMapper.Clear(); for (int i = 0; i < guideList.Count; i++) { guideMapper.Add(guideList[i].id, guideList[i]); } } //......}流程狀態機實現: #region guide state machine public void NetOperateDetect(int result, GuideStep failGotoStep, NetOperateType netOperate) { if (IsGuideWaitResponse() && netOperate == (NetOperateType)activeGuide.operateType) { if (result == 0) { SetGuideStep(GuideStep.complete); ActiveGuideComplete(); } else { SetGuideStep(failGotoStep); } } } protected void Update() { switch (GuideState) { case GuideState.start: case GuideState.complete: //流程狀態機開始或上一條指引完成,取出一條指引運行 { Guide guide = null; if (guideMapper.TryGetValue(spawnGuideId, out guide) && (bool)ExecuteExpression(guide.guideTrigger))//判斷上一條完成指引的spawns字段索引的指引是否能觸發 { //上一條指引能spwans一條指引 if (GuideRunningValid())//流程狀態機進入running狀態,環境合法性檢測 { GuideState = GuideState.running; activeGuide = guide; if (activeGuide.skipCondition != "" && (bool)ExecuteExpression(activeGuide.skipCondition)) { guideMapper.Remove(activeGuide.id); AGuide.SendGuideCompletedMessage(activeGuide.id); happendList.Add(activeGuide.id); } else { spawnGuideId = string.Empty; ActiveGuideStart(); guideMapper.Remove(activeGuide.id); } } } else { //上一條指引不能spwans一條新指引 if (GuideRunningValid())//流程狀態機進入running狀態,環境合法性檢測 { List<string> weakGuideCache = new List<string>(); foreach (KeyValuePair<string, Guide> kv in guideMapper) //遍歷guideMapper { guide = kv.Value; if ((bool)ExecuteExpression(guide.guideTrigger))//找出一條可觸發的指引 { GuideState = GuideState.running; activeGuide = guide; if (activeGuide.skipCondition != "" && (bool)ExecuteExpression(activeGuide.skipCondition))//判斷指引的跳過條件 { //跳過該指引 weakGuideCache.Add(activeGuide.id); } else { //執行該指引 ActiveGuideStart(); //指引開始,該函數的實現在下文 guideMapper.Remove(activeGuide.id); break; } } else if (guide.weak == 1) //weak == 1的指引不滿足觸發條件就跳過 { weakGuideCache.Add(guide.id); } } for (int i = 0; i < weakGuideCache.Count; i++) //weakGuideCache里的指引全跳過 { guideMapper.Remove(weakGuideCache[i]); BGuide.SendGuideCompletedMessage(weakGuideCache[i]); happendList.Add(weakGuideCache[i]); } } } }break; case GuideState.pause: //指引被暫停,打開EventSystem和FingerGesture { SetPlayerInput(true); }break; } //自動跳過條件檢測,強制完成該條指引 if (IsGuideRunning() && activeGuide != null && activeGuide.skipCondition != "" && (bool)ExecuteExpression(activeGuide.skipCondition)) { ActiveGuideComplete(); } //流程狀態機非法狀態檢測,強制完成該條指引 if (!IsGuideStateValid()) { ActiveGuideComplete(); } } public void ActiveGuideStart() { if (activeGuideCompleteSequence != null) { activeGuideCompleteSequence.Kill(); } try { SetPlayerInput(false); //關閉EventSystem和FingerGesture guideStep = GuideStep.prepare; //步驟狀態機進入prepare狀態 foreach (string expression in activeGuide.moduleID) //依次執行activeGuide.moduleID里的表達式 { ExecuteExpression(expression); //例子里的expression = "",通過中綴表達式解析器解析后會執行public void GuideBuilding(string buildingName)這個函數。 } } catch (Exception e) //出錯,強制完成該條指引 { GuideCloseAllDialogs(); ActiveGuideComplete(); } } #endregion

上段代碼中ExecuteExpression(expression)函數的實現可參考該文章: 可自定義函數、并且函數可任意嵌套的中綴表達式解析器

步驟狀態機的實現: #region build public void GuideBuilding(string buildingName) { GuideCloseAllDialogs(); SetGuideStep(GuideStep.step01); //設置步驟狀態機狀態:step01 this.stepStateMachine = StartCoroutine(GuideBuildingCoroutine(buildingName)); //起一個步驟狀態機 } private IEnumerator GuideBuildingCoroutine(string buildingName) { while(true) { switch (guideStep) { case GuideStep.step01: { SetPlayerInput(false); GuideFindSlotAndBuild //找到可建造空地,并打開建造界面,完成后進入第二步 (buildingName, () => { SetGuideStep(GuideStep.step02); }); HangupGuideStep(); }break; case GuideStep.step02: { SetPlayerInput(false); yield return new WaitForSeconds(guideStepInterval); ClickButton //點擊建筑界面的建造按鈕,點擊后關閉EventSystem和FingerGesture并等待服務器回復 ("buildView", "btn_name", 0, 200, () => { SetPlayerInput(false); WaitResponse(); } ); WaitPlayerInput(); //等待玩家輸入 }break; } yield return null; //合法性檢測 if (IsGuideStepWaitPlayerInput(GuideStep.step02) && !IsCurrentDialogValid("buildView")) //在第二步等待玩家輸入并且當前界面不是建造界面,刪除指引箭頭和mask,步驟狀態機進入意外掛起狀態 { ClearArrow(); ClearGuideMask(); HangupGuideStepUnexpect(); } if (guideStep == GuideStep.hangupUnexpect && AUIManager.GetCurrentDialog().dialogName == "HUD") //步驟狀態機進入意外掛起狀態,并且當前界面是主界面則重新開始該指引 { GuideCloseAllDialogs(); SetGuideStep(GuideStep.step01); } yield return null; } }
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 汽车| 涿州市| 巩义市| 南华县| 红原县| 彝良县| 辽源市| 洪泽县| 湖北省| 江永县| 封丘县| 中阳县| 天祝| 宜良县| 汕尾市| 鞍山市| 呼和浩特市| 甘泉县| 灵山县| 四会市| 鸡泽县| 绵竹市| 辽阳县| 泰来县| 东阿县| 浑源县| 桐城市| 冷水江市| 阳曲县| 大安市| 兴国县| 宜川县| 鄂托克前旗| 齐齐哈尔市| 缙云县| 清原| 拉孜县| 恩平市| 富源县| 田阳县| 平阳县|