Unity怎么暂停协程Unity协程管理方案
协程是游戏开发中非常常用的方法,类似一个子线程单独出来处理一些问题,性能开销较小。当然我们更多时候用的是他的延时执行功能使用多了,难免有这样那样的需求。比如:暂停。比如:管理大量协程等
协程要在Mono类执行,销毁物体会停止协程,咋办
下面提供协程的一个管理器方案。
核心类有3个:
image.png
使用的时候只需要使用CoroutineMgr
CoroutineItem
using System.Collections;using UnityEngine;public class CoroutineItem : MonoBehaviour{ public enum CoroutineState{ WAITTING, RUNNING, PASUED, STOP } public CoroutineState State{get;set;} public IEnumerator Body(IEnumerator routine){ while(State == CoroutineState.WAITTING){ yield return null; } while(State == CoroutineState.RUNNING){ if(State == CoroutineState.PASUED){ yield return null; }else{ if(routine!=null&&routine.MoveNext()){ yield return routine.Current; }else{ State = CoroutineState.STOP; } } } }}CoroutineCtrl
using System.Collections;using UnityEngine;public class CoroutineCtrl{ private static int _id; public int ID{get;private set;} private CoroutineItem _item; private MonoBehaviour _mono; private IEnumerator _routine; private Coroutine _coroutine; public CoroutineCtrl(MonoBehaviour mono, IEnumerator routine) { _item = new GameObject().AddComponent<CoroutineItem>(); _mono = mono; _routine = routine; ResetData(); } public void Start() { _item.State = CoroutineItem.CoroutineState.RUNNING; _coroutine = _mono.StartCoroutine(_item.Body(_routine)); } public void Pause() { _item.State = CoroutineItem.CoroutineState.PASUED; } public void Stop() { _item.State = CoroutineItem.CoroutineState.STOP; } public void Continue() { _item.State = CoroutineItem.CoroutineState.RUNNING; } public void ResetStart() { if(_coroutine != null){ _mono.StopCoroutine(_coroutine); } Start(); } private void ResetData(){ ID = _id++; }}CoroutineMgr
using System.Collections;using System.Collections.Generic;using UnityEngine;public class CoroutineMgr : MonoSingleton<CoroutineMgr>{ private Dictionary<int,CoroutineCtrl> _ctrlDic; public CoroutineMgr(){ _ctrlDic = new Dictionary<int, CoroutineCtrl>(); } public int Execute(IEnumerator routine,bool autoStart = true){ CoroutineCtrl ctrl = new CoroutineCtrl(this,routine); _ctrlDic.Add(ctrl.ID,ctrl); if(autoStart){ StartExecute(ctrl.ID); } return ctrl.ID; } public void ExecuteOnce(IEnumerator routine){ CoroutineCtrl ctrl = new CoroutineCtrl(this,routine); ctrl.Start(); } public void StartExecute(int id){ var ctrl = GetCtrl(id); if(ctrl!=null){ ctrl.Start(); } } public void PauseExecute(int id){ var ctrl = GetCtrl(id); if(ctrl!=null){ ctrl.Pause(); } } public void StopExecute(int id){ var ctrl = GetCtrl(id); if(ctrl!=null){ ctrl.Stop(); } } public void RestartExecute(int id){ var ctrl = GetCtrl(id); if(ctrl!=null){ ctrl.ResetStart(); } } private CoroutineCtrl GetCtrl(int id){ if(_ctrlDic.ContainsKey(id)){ return _ctrlDic; }else{ Debug.LogError($"当前id不存在,id:{id}"); return null; } }}MonoSingleton
//简易的Mono单例类,如无必要,代码中尽量少用using UnityEngine;public class MonoSingleton<T> : MonoBehaviour where T:MonoBehaviour{ private static T _instance; public static T Instance { get { if(_instance == null) { GameObject go = new GameObject(typeof(T).Name); DontDestroyOnLoad(go); _instance = go.AddComponent<T>(); } return _instance; } }}测试
using System.Collections;using UnityEngine;using UnityEngine.UI;public class CoroutineTest : MonoBehaviour{ public Button mBtnStart; public Button mBtnPause; public Button mBtnStop; private int id = 0; private void Awake() { mBtnStart.onClick.AddListener(ClickStart); mBtnPause.onClick.AddListener(ClickPause); mBtnStop.onClick.AddListener(ClickStop); } private void Start() { // CoroutineMgr.Instance.ExecueOnce(DoSomething()); 只需要执行一次,不需要控制的用这个 id = CoroutineMgr.Instance.Execute(DoSomething());//需要多次执行和管理的用这个,保存下id,用id调用控制方法 } void ClickStart() { CoroutineMgr.Instance.RestartExecute(id); } void ClickPause() { CoroutineMgr.Instance.PauseExecute(id); } void ClickStop() { CoroutineMgr.Instance.StopExecute(id); } IEnumerator DoSomething() { print($"当前携程ID为{id}"); print("协程开始"); var timer = 0; while ( timer<30) { yield return new WaitForSeconds(1); timer++; print($"协程进行第{timer}秒"); } print("协程完成"); }}
以上方案出自Siki学院Andy老师《全民飞机大战》框架设计系列
页:
[1]