找回密码
 立即注册
查看: 461|回复: 0

Unity怎么暂停协程Unity协程管理方案

[复制链接]
发表于 2021-7-15 17:57 | 显示全部楼层 |阅读模式
协程是游戏开发中非常常用的方法,类似一个子线程单独出来处理一些问题,性能开销较小。当然我们更多时候用的是他的延时执行功能

使用多了,难免有这样那样的需求。比如:暂停。比如:管理大量协程等
协程要在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[id];        }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老师《全民飞机大战》框架设计系列

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
懒得打字嘛,点击右侧快捷回复 【右侧内容,后台自定义】
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Unity开发者联盟 ( 粤ICP备20003399号 )

GMT+8, 2024-11-15 11:07 , Processed in 0.089732 second(s), 26 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表