关于Unity中的计数回调机制使用

在开发中也许会遇到这样一种情况,我有些事必须要等一些事完成才可以继续,但是这些事的完成时间是不可预测的,虽然说布尔值联合判断可以用在很多只需要完成两件事的情况,但是每次布尔值更改的时候都要去判断是否是否达标显得有点冗余,而且如果计数在三个或以上的话用布尔值显然显得麻烦,这时本文要介绍的归零计数回调就起到作用了,它易读易维护而且有泛用性

这里的计数回调除了上述功能外,还可以选择是否回调即刻清除注册,回调之后如果没清除监听,计数会回升到记录过的最高值,如果再次符合情况进行清零,则会再次被调用

先看看单个归零计数回调的类

public class clearNameCount
{
    protected Action cb;
    protected int totalCount = 0;
    protected int curTraverseIdx = 0;
    protected bool hasExecuted;

    protected bool onlyOnce;
    /// <summary>
    /// 表示一旦计数到达 ,执行了所有注册事件过后 
    /// 这个类是否销毁
    /// </summary>
    public bool OnlyOnce
    {
        get
        {
            return onlyOnce;
        }

        set
        {
            onlyOnce = value;
        }
    }

    public clearNameCount(Action cb, bool onlyOnce)
    {
        this.cb = cb;
        this.curTraverseIdx = 0;
        this.OnlyOnce = onlyOnce;
    }

    public clearNameCount()
    {

    }


    public virtual void AddTotalCount()
    {
        curTraverseIdx++;
        totalCount++;
    }

    public virtual void SetTotalCount(int total)
    {
        curTraverseIdx = total;
        totalCount = total;
    }



    public virtual void MinusTraverseIndex()
    {
        curTraverseIdx--;
        //Debug.LogError(" Util MinusCount after total " + total);
    }

    public virtual bool AllEventsExecuted()
    {
        //Debug.LogError(" Util Final " + "total " + total);
        if (curTraverseIdx <= 0)
        {
            if (!hasExecuted)
            {
                //Debug.LogError(" Util Final cb Execute");
                hasExecuted = true;
                cb();
            }
            return true;
        }
        return false;
    }


    public virtual void Reset()
    {
        curTraverseIdx = totalCount;
        hasExecuted = false;
    }
}

然后是整个归零回调总控制类

public class ClearNameCountDicUtil 
{
    static ClearNameCountDicUtil instance;
    public static ClearNameCountDicUtil Instance
    {
        get
        {
            if (instance == null)
            {
                instance = new ClearNameCountDicUtil();
            }
            return instance;
        }
    }


    protected Dictionary<string, clearNameCount> nameCountDic = new Dictionary<string, clearNameCount>();

   

    /// <summary>
    /// 用于异步加载的计数回调 需求是加载完一定数量的物品之后需要执行一些事情
    /// </summary>
    public virtual void RegisterCountCB(string name, Action clearCB, int count = -1, bool onlyOnce = true)
    {
        if (nameCountDic.ContainsKey(name))
        {
            nameCountDic.Remove(name);
        }
        nameCountDic.Add(name, new clearNameCount(clearCB, onlyOnce));

        if (count != -1)
        {
            SetTotalCount(name, count);
        }
    }

    public virtual void AddTotalCount(string name)
    {
        if (nameCountDic.ContainsKey(name))
        {
            clearNameCount nc = nameCountDic[name];
            nc.AddTotalCount();
        }
    }

    public virtual void SetTotalCount(string name, int times)
    {
        if (nameCountDic.ContainsKey(name))
        {
            clearNameCount nc = nameCountDic[name];
            nc.SetTotalCount(times);
        }
    }

    public virtual void UnregisterCountClearCb(string countKeyName)
    {
        if (nameCountDic.ContainsKey(countKeyName))
        {
            nameCountDic.Remove(countKeyName);
        }
    }


    /// <summary>
    /// 注意在调用结束回调包含MinusCount的协程方法前先调用完所有AddCount
    /// 因为不满足协程的循环条件的话  协程会瞬间结束
    /// 相当于先MinusCount 再 AddCount 了
    /// 甚至有时先一次性将所有的AddCount方法先调用再挨个回调MinusCount
    /// </summary>
    /// <param name="name"></param>
    public virtual void MinusTraverseIndex(string name)
    {
        if (nameCountDic.ContainsKey(name))
        {
            clearNameCount nc = nameCountDic[name];

            nc.MinusTraverseIndex();

            //Debug.LogError(" Util MinusCount name " + name);

            ExecutedJudge(name, nc);

        }
    }


    protected virtual void ExecutedJudge(string name, clearNameCount nc)
    {
        if (nc.AllEventsExecuted())
        {
            if (nc.OnlyOnce) //清除这个注册的引用计数
            {
                //Debug.LogError(" Util MinusCount nameCountDic.Remove(name) " + name);
                nameCountDic.Remove(name);
            }
            else //不清除 重置
            {
                nc.Reset();
            }
        }
    }



}

归零计数回调的用法有两种
第一种

  • 首先使用独特字符串进行进行监听注册,确保不与其他的计数回调产生冲突,这里的注册计数为0
ClearNameCountDicUtil.Instance.RegisterCountCB(TPCPeopleShiftTotal.Instance.exitShiftCountBack, () =>
        {
            ExitStateFnshAct();
        }, 0, false);
  • 然后在某些时候进行计数的若干次添加
      ClearNameCountDicUtil.Instance.AddTotalCount(TPCPeopleShiftTotal.Instance.exitShiftCountBack);
  • 最后进行计数的若干次减小,减小到计数归零的时候 注册的方法就会被调用
ClearNameCountDicUtil.Instance.MinusTraverseIndex(TPCPeopleShiftTotal.Instance.exitShiftCountBack);

第二种

  • 在监听的时候先直接写好次数
ClearNameCountDicUtil.Instance.RegisterCountCB(TPCPeopleShiftTotal.Instance.exitShiftCountBack, () =>
        {
            ExitStateFnshAct();
        }, 3, false);
  • 最后进行计数的若干次减小,减小到计数归零的时候 注册的方法就会被调用
ClearNameCountDicUtil.Instance.MinusTraverseIndex(TPCPeopleShiftTotal.Instance.exitShiftCountBack);

上述方法第一种更具灵活性,因为有时注册的具体次数不是一开始就能决定的


有时我们会遇到一种情况就是,我们对于有三件事,同时有两件事出现的时候就要做某件固定的事,只有一件事出现的时候要做另外一件固定的事,或者有四件事,同时有三件事出现的时候就要做某件固定的事,同时有两件事出现的时候就要做其他某件固定的事,只有一件事出现的时候要做另外一件固定的事,这些情况用布尔值进行判断也显得麻烦,例如,我有两个摇杆,一个控制移动,一个控制旋转,当其中任意一个或者两个都操作的时候我要记录被操纵的物体的变换信息,当没有任何一个被操作的时候我需要 停止记录并且清除信息,这些时候方便易读易维护且适用性广的自定义计数回调就排上用场了

自定义计数回调继承自归零计数回调

先看单个自定义计数回调类countCBStruct和customNameCount

public struct countCBStruct
{
    int matchInt;
    public int MatchInt
    {
        get
        {
            return matchInt;
        }
    }

    Action matchCB;

    bool isExecuted;
    public bool IsExecuted
    {
        get
        {
            return isExecuted;
        }
    }

    bool isExeOnce;
    public bool IsExeOnce
    {
        get
        {
            return isExeOnce;
        }

        set
        {
            isExeOnce = value;
        }
    }

    public countCBStruct(int matchInt, Action matchCB, bool isExeOnce = true)
    {
        this.matchInt = matchInt;
        this.matchCB = matchCB;
        this.isExeOnce = isExeOnce;
        isExecuted = false;
    }

    public void Execute()
    {
        if (isExeOnce)
        {
            if (!isExecuted)
            {
                matchCB?.Invoke();
                isExecuted = true;
            }
        }
        else
        {
            matchCB?.Invoke();
            isExecuted = true;
        }
    }
}

public class customNameCount : clearNameCount
{
    protected Dictionary<int, countCBStruct> regEvents = new Dictionary<int, countCBStruct>();

    int executeCBCount = 0;

    int oriTraverseIdx;

    public customNameCount()
    {

    }

    public customNameCount(countCBStruct[] eventStructs, int startTraverseIdx = 0)
    {
        foreach (var eventStruct in eventStructs)
        {
            if (!regEvents.ContainsValue(eventStruct))
            {
                regEvents.Add(eventStruct.MatchInt, eventStruct);
            }
        }

        oriTraverseIdx = startTraverseIdx;
        curTraverseIdx = startTraverseIdx;
    }

    public override void Reset()
    {
        base.Reset();
        curTraverseIdx = oriTraverseIdx;
    }

    public virtual void PlusTraverseIndex()
    {
        curTraverseIdx++;
        CheckWhetherMatchOne();
    }

    public override void MinusTraverseIndex()
    {
        base.MinusTraverseIndex();
        CheckWhetherMatchOne();
    }

    public void CheckWhetherMatchOne()
    {
        foreach (var regIndex in regEvents.Keys)
        {
            if (curTraverseIdx == regIndex)
            {
                regEvents[curTraverseIdx].Execute();
            }
        }
    }

    public override bool AllEventsExecuted()
    {
        bool isAllExecuted = true;
        foreach (var regEvent in regEvents.Values)
        {
            if (!regEvent.IsExecuted)
            {
                isAllExecuted = false;
            }
        }
        return isAllExecuted;
    }

}

然后是自定义计数回调计数总类


public class CustomNameCountDicUtil : ClearNameCountDicUtil
{
    static CustomNameCountDicUtil instance;
    public static new CustomNameCountDicUtil Instance
    {
        get
        {
            if (instance == null)
            {
                instance = new CustomNameCountDicUtil();
            }
            return instance;
        }
    }

    public  void RegisterCountCB(string name, countCBStruct[] eventsToReg)
    {
        if (nameCountDic.ContainsKey(name))
        {
            nameCountDic.Remove(name);
        }

        nameCountDic.Add(name, new customNameCount(eventsToReg));
    }

    public void PlusTraverseIndex(string name)
    {
        if (nameCountDic.ContainsKey(name))
        {
            customNameCount nc = nameCountDic[name] as customNameCount;

            nc.PlusTraverseIndex();

            //Debug.LogError(" Util MinusCount name " + name);

            ExecutedJudge(name, nc);
        }
    }

}

使用方法:

  • 首先注册回调
        List<countCBStruct> cbList = new List<countCBStruct>();
        countCBStruct noInputCB = new countCBStruct(0,()=> {
            //Debug.LogError(" SPCollideDtct RegJoyCtrlEvent 0");
            
            StopRcrdTrace();
        });
        cbList.Add(noInputCB);

        countCBStruct twoInputCB = new countCBStruct(2, () => {
            //Debug.LogError(" SPCollideDtct RegJoyCtrlEvent 2");
            StartRcrdTrace();
        });
        cbList.Add(twoInputCB);

        countCBStruct oneInputCB = new countCBStruct(1, () => {
            //Debug.LogError(" SPCollideDtct RegJoyCtrlEvent 1");
            StartRcrdTrace();
        });
        cbList.Add(oneInputCB);

        CustomNameCountDicUtil.Instance.RegisterCountCB(startTraceRegCountEvent, cbList.ToArray());
  • 然后增数减数
 RegisterFunc(MsgEvents.joyStickControlTPCORotStartMove, (o) =>
        {
            CustomNameCountDicUtil.Instance.PlusTraverseIndex(startTraceRegCountEvent);
        });

        RegisterFunc(MsgEvents.joyStickControlTPCORotEndMove, (o) =>
        {
            CustomNameCountDicUtil.Instance.MinusTraverseIndex(startTraceRegCountEvent);
        });

        RegisterFunc(MsgEvents.joyStickControlTPCOPosStartMove, (o) =>
        {
            CustomNameCountDicUtil.Instance.PlusTraverseIndex(startTraceRegCountEvent);
        });

        RegisterFunc(MsgEvents.joyStickControlTPCOPosEndMove, (o) =>
        {
            CustomNameCountDicUtil.Instance.MinusTraverseIndex(startTraceRegCountEvent);
        });

计数达到注册时候的数就会执行相应的回调

因为所有代码都在一个脚本里,最后贴上这个脚本

// ========================================================
// 功能描述:计数回调,有时我们需要等待几件完成时间不确定的事情的完成来执行其他事情
// 开协程等待不适合,所以引入了这种机制,当某个次数到达某个门槛的时候,就执行一次回调
// 作者:TsinNing 
// 创建时间:2020-01-03 17:10:23
// 版 本:1.0
//其他: 
// ========================================================
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;


#region 到零触发事件机制的计数回调
public class clearNameCount
{
    protected Action cb;
    protected int totalCount = 0;
    protected int curTraverseIdx = 0;
    protected bool hasExecuted;

    protected bool onlyOnce;
    /// <summary>
    /// 表示一旦计数到达 ,执行了所有注册事件过后 
    /// 这个类是否销毁
    /// </summary>
    public bool OnlyOnce
    {
        get
        {
            return onlyOnce;
        }

        set
        {
            onlyOnce = value;
        }
    }

    public clearNameCount(Action cb, bool onlyOnce)
    {
        this.cb = cb;
        this.curTraverseIdx = 0;
        this.OnlyOnce = onlyOnce;
    }

    public clearNameCount()
    {

    }


    public virtual void AddTotalCount()
    {
        curTraverseIdx++;
        totalCount++;
    }

    public virtual void SetTotalCount(int total)
    {
        curTraverseIdx = total;
        totalCount = total;
    }



    public virtual void MinusTraverseIndex()
    {
        curTraverseIdx--;
        //Debug.LogError(" Util MinusCount after total " + total);
    }

    public virtual bool AllEventsExecuted()
    {
        //Debug.LogError(" Util Final " + "total " + total);
        if (curTraverseIdx <= 0)
        {
            if (!hasExecuted)
            {
                //Debug.LogError(" Util Final cb Execute");
                hasExecuted = true;
                cb();
            }
            return true;
        }
        return false;
    }


    public virtual void Reset()
    {
        curTraverseIdx = totalCount;
        hasExecuted = false;
    }
}

public class ClearNameCountDicUtil 
{
    static ClearNameCountDicUtil instance;
    public static ClearNameCountDicUtil Instance
    {
        get
        {
            if (instance == null)
            {
                instance = new ClearNameCountDicUtil();
            }
            return instance;
        }
    }


    protected Dictionary<string, clearNameCount> nameCountDic = new Dictionary<string, clearNameCount>();

   

    /// <summary>
    /// 用于异步加载的计数回调 需求是加载完一定数量的物品之后需要执行一些事情
    /// </summary>
    public virtual void RegisterCountCB(string name, Action clearCB, int count = -1, bool onlyOnce = true)
    {
        if (nameCountDic.ContainsKey(name))
        {
            nameCountDic.Remove(name);
        }
        nameCountDic.Add(name, new clearNameCount(clearCB, onlyOnce));

        if (count != -1)
        {
            SetTotalCount(name, count);
        }
    }

    public virtual void AddTotalCount(string name)
    {
        if (nameCountDic.ContainsKey(name))
        {
            clearNameCount nc = nameCountDic[name];
            nc.AddTotalCount();
        }
    }

    public virtual void SetTotalCount(string name, int times)
    {
        if (nameCountDic.ContainsKey(name))
        {
            clearNameCount nc = nameCountDic[name];
            nc.SetTotalCount(times);
        }
    }

    public virtual void UnregisterCountClearCb(string countKeyName)
    {
        if (nameCountDic.ContainsKey(countKeyName))
        {
            nameCountDic.Remove(countKeyName);
        }
    }


    /// <summary>
    /// 注意在调用结束回调包含MinusCount的协程方法前先调用完所有AddCount
    /// 因为不满足协程的循环条件的话  协程会瞬间结束
    /// 相当于先MinusCount 再 AddCount 了
    /// 甚至有时先一次性将所有的AddCount方法先调用再挨个回调MinusCount
    /// </summary>
    /// <param name="name"></param>
    public virtual void MinusTraverseIndex(string name)
    {
        if (nameCountDic.ContainsKey(name))
        {
            clearNameCount nc = nameCountDic[name];

            nc.MinusTraverseIndex();

            //Debug.LogError(" Util MinusCount name " + name);

            ExecutedJudge(name, nc);

        }
    }


    protected virtual void ExecutedJudge(string name, clearNameCount nc)
    {
        if (nc.AllEventsExecuted())
        {
            if (nc.OnlyOnce) //清除这个注册的引用计数
            {
                //Debug.LogError(" Util MinusCount nameCountDic.Remove(name) " + name);
                nameCountDic.Remove(name);
            }
            else //不清除 重置
            {
                nc.Reset();
            }
        }
    }



}
#endregion

#region 自定义到达数字机制的计数回调

public struct countCBStruct
{
    int matchInt;
    public int MatchInt
    {
        get
        {
            return matchInt;
        }
    }

    Action matchCB;

    bool isExecuted;
    public bool IsExecuted
    {
        get
        {
            return isExecuted;
        }
    }

    bool isExeOnce;
    public bool IsExeOnce
    {
        get
        {
            return isExeOnce;
        }

        set
        {
            isExeOnce = value;
        }
    }

    public countCBStruct(int matchInt, Action matchCB, bool isExeOnce = true)
    {
        this.matchInt = matchInt;
        this.matchCB = matchCB;
        this.isExeOnce = isExeOnce;
        isExecuted = false;
    }

    public void Execute()
    {
        if (isExeOnce)
        {
            if (!isExecuted)
            {
                matchCB?.Invoke();
                isExecuted = true;
            }
        }
        else
        {
            matchCB?.Invoke();
            isExecuted = true;
        }
    }
}


public class customNameCount : clearNameCount
{
    protected Dictionary<int, countCBStruct> regEvents = new Dictionary<int, countCBStruct>();

    int executeCBCount = 0;

    int oriTraverseIdx;

    public customNameCount()
    {

    }

    public customNameCount(countCBStruct[] eventStructs, int startTraverseIdx = 0)
    {
        foreach (var eventStruct in eventStructs)
        {
            if (!regEvents.ContainsValue(eventStruct))
            {
                regEvents.Add(eventStruct.MatchInt, eventStruct);
            }
        }

        oriTraverseIdx = startTraverseIdx;
        curTraverseIdx = startTraverseIdx;
    }

    public override void Reset()
    {
        base.Reset();
        curTraverseIdx = oriTraverseIdx;
    }

    public virtual void PlusTraverseIndex()
    {
        curTraverseIdx++;
        CheckWhetherMatchOne();
    }

    public override void MinusTraverseIndex()
    {
        base.MinusTraverseIndex();
        CheckWhetherMatchOne();
    }

    public void CheckWhetherMatchOne()
    {
        foreach (var regIndex in regEvents.Keys)
        {
            if (curTraverseIdx == regIndex)
            {
                regEvents[curTraverseIdx].Execute();
            }
        }
    }

    public override bool AllEventsExecuted()
    {
        bool isAllExecuted = true;
        foreach (var regEvent in regEvents.Values)
        {
            if (!regEvent.IsExecuted)
            {
                isAllExecuted = false;
            }
        }
        return isAllExecuted;
    }

}


public class CustomNameCountDicUtil : ClearNameCountDicUtil
{
    static CustomNameCountDicUtil instance;
    public static new CustomNameCountDicUtil Instance
    {
        get
        {
            if (instance == null)
            {
                instance = new CustomNameCountDicUtil();
            }
            return instance;
        }
    }

    public  void RegisterCountCB(string name, countCBStruct[] eventsToReg)
    {
        if (nameCountDic.ContainsKey(name))
        {
            nameCountDic.Remove(name);
        }

        nameCountDic.Add(name, new customNameCount(eventsToReg));
    }

    public void PlusTraverseIndex(string name)
    {
        if (nameCountDic.ContainsKey(name))
        {
            customNameCount nc = nameCountDic[name] as customNameCount;

            nc.PlusTraverseIndex();

            //Debug.LogError(" Util MinusCount name " + name);

            ExecutedJudge(name, nc);
        }
    }

}
#endregion


发布了86 篇原创文章 · 获赞 13 · 访问量 5万+

猜你喜欢

转载自blog.csdn.net/weixin_43149049/article/details/104284441
今日推荐