首页 > 其他分享 >Unity游戏框架设计之消息管理器

Unity游戏框架设计之消息管理器

时间:2024-04-29 22:44:06浏览次数:17  
标签:管理器 messageSet 框架 messageConfig float param Unity messageName action

Unity游戏框架设计之消息管理器

简单介绍

消息管理器又可以称为任务管理器,主要解决延迟执行某些代码的问题。比如,我们希望一些代码可以延迟指定的时间后才执行,或者我们希望一些代码可以在固定的时间执行,又或者我们希望一些代码可以每隔一段时间就执行一次。消息管理器就是为了实现上述功能而开发的。下述的消息管理器是基于 Unity 的协程进行实现。

代码设计

public class MessageManager : SingletonMono<MessageManager>
{
    private readonly Dictionary<string, MessageConfig> _messageSet = new();

    private void CreateMessage<T>(string messageName, float delayTime, float intervalTime, int cycleCount, Action<T> action, T param)
    {
        if (FloatUtils.IsEqualsTo(intervalTime, 0f) && cycleCount <= -1)
        {
            LogManager.Instance.DebugWarning($"无法创建间隔时间为 0 的无限循环消息。messageName={messageName}");
            return;
        }
        IEnumerator task = CycleMessage(messageName, 0f, action, param);
        MessageConfig messageConfig = new MessageConfig(task, delayTime, intervalTime, cycleCount);
        _messageSet.Add(messageName, messageConfig);
    }

    public void PublishDelayMessage<T>(string messageName, float delayTime, Action<T> action, T param)
    {
        CreateMessage(messageName, delayTime, float.MaxValue, 1, action, param);
        PublishMessage(messageName);
    }

    public void PublishFiniteCycleMessage<T>(string messageName, float delayTime, float intervalTime, int cycleCount, Action<T> action, T param)
    {
        CreateMessage(messageName, delayTime, intervalTime, cycleCount, action, param);
        PublishMessage(messageName);
    }

    public void PublishInfiniteCycleMessage<T>(string messageName, float delayTime, float intervalTime, Action<T> action, T param)
    {
        CreateMessage(messageName, delayTime, intervalTime, -1, action, param);
        PublishMessage(messageName);
    }

    public void PublishTimingMessage<T>(string messageName, float fixedTime, Action<T> action, T param)
    {
        CreateMessage(messageName, fixedTime - Time.realtimeSinceStartup, float.MaxValue, 1, action, param);
        PublishMessage(messageName);
    }

    private void PublishMessage(string messageName)
    {
        if (!_messageSet.ContainsKey(messageName))
        {
            LogManager.Instance.DebugWarning($"消息不存在。messageName={messageName}");
            return;
        }
        MessageConfig messageConfig = _messageSet[messageName];
        StartCoroutine(SleepTime(messageConfig.DelayTime, () => StartCoroutine(messageConfig.Message)));
    }

    public void RemoveMessage(string messageName)
    {
        if (!_messageSet.ContainsKey(messageName))
        {
            LogManager.Instance.DebugWarning($"消息不存在。messageName={messageName}");
            return;
        }
        MessageConfig messageConfig = _messageSet[messageName];
        StopCoroutine(messageConfig.Message);
        _messageSet.Remove(messageName);
    }

    public void RemoveMessageIfExists(string messageName)
    {
        if (_messageSet.ContainsKey(messageName))
        {
            MessageConfig messageConfig = _messageSet[messageName];
            _messageSet.Remove(messageName);
            StopCoroutine(messageConfig.Message);
        }
    }

    public bool ContainMessage(string messageName)
    {
        return _messageSet.ContainsKey(messageName);
    }

    private IEnumerator CycleMessage<T>(string messageName, float intervalTime, Action<T> action, T param)
    {
        if (!_messageSet.ContainsKey(messageName))
        {
            yield break;
        }
        MessageConfig messageConfig = _messageSet[messageName];
        if (messageConfig.CycleCount >= 1)
        {
            messageConfig.CycleCount--;
        }
        else if (messageConfig.CycleCount == 0)
        {
            _messageSet.Remove(messageName);
            yield break;
        }
        yield return new WaitForSeconds(intervalTime);
        action.Invoke(param);
        if (FloatUtils.IsEqualsTo(intervalTime, 0f) && FloatUtils.IsNotEqualsTo(messageConfig.IntervalTime, 0f))
        {
            messageConfig.Message = CycleMessage(messageName, messageConfig.IntervalTime, action, param);
        }
        else
        {
            messageConfig.Message = CycleMessage(messageName, intervalTime, action, param);
        }
        StartCoroutine(messageConfig.Message);
    }

    private IEnumerator SleepTime(float delayTime, Action callback)
    {
        if (FloatUtils.IsGreaterThan(delayTime, 0f))
        {
            yield return new WaitForSeconds(delayTime);
        }
        callback();
    }

    private class MessageConfig
    {
        public IEnumerator Message;
        public readonly float DelayTime;
        public readonly float IntervalTime;
        public int CycleCount;

        public MessageConfig(IEnumerator message, float delayTime, float intervalTime, int cycleCount)
        {
            Message = message;
            DelayTime = delayTime;
            IntervalTime = intervalTime;
            CycleCount = cycleCount;
        }
    }
}

代码说明

(一)实现延迟消息(倒计时器)、定时消息(定时器)、有限循环消息和无限循环消息(循环调度器)。

(二)messageName 命名格式推荐 $"{ScriptName}{MethodName}{ID}" 。必须为所有的 messageName 添加唯一的 ID 后缀,防止出现冲突。唯一 ID 可以通过时间戳和递增的计数器来实现。由于在 Unity 中是单线程执行的,因此不必考虑线程安全问题,也不必考虑加锁问题。

(三)在传递的 action 参数中,必须先对当前执行环境进行检查,才能执行消息处理的代码。因为消息可能是延迟的,而延迟后的执行环境可能并不满足消息处理的条件。比如消息依赖的某些对象被禁用或销毁,此时应当停止消息处理,而是退出函数,甚至直接删除消息。

后记

由于个人能力有限,文中不免存在疏漏之处,恳求大家斧正,一起交流,共同进步。

标签:管理器,messageSet,框架,messageConfig,float,param,Unity,messageName,action
From: https://www.cnblogs.com/kkelin/p/18166773

相关文章

  • Unity游戏框架设计之协程管理器
    Unity游戏框架设计之协程管理器代码设计/**协程管理器*/publicclassCoroutineManager:SingletonMono<CoroutineManager>{/***创建CoroutineTask*/publicCoroutineTaskCreateCoroutine(IEnumeratorcoroutine,Action<bool>finishHandler......
  • Unity游戏框架设计之单例Mono
    Unity游戏框架设计之单例Mono简单介绍在编写Unity脚本的过程中,我们通常需要编写一些依赖于MonBehaviour生命周期且全局始终唯一的类,比如EventManager、TaskManager、ResourceManager和UIManager等等。我们可以基于单例模式,设计出名为SingletonMono的单例类,然后让拥......
  • httprunner测试框架(一):支持不同环境执行
     首先,httprunner已经是一个较完善的接口测试框架了,基本可以拿来即用,本文提供一种支持不同环境执行用例的实现思想,其余部分均是采用httprunner脚手架搭建-httprunner工作原理:执行前会先加载.env文件,将.env文件中的内容加载到内存中,如下图所示 -.env文件htttprunne......
  • 接口测试框架选择
    接口测试是现在比较有性价比的自动化测试方法目前常见的接口测试框架是1.Python+unittest+HtmlTestRunner;2.Python+Pytest+allure。下面描述一下2种框架的大概区别,可以自行判断使用的框架1、准备工作unittest是python自带的库,不用安装。可直接使用,该框架下需要仅需安......
  • 使用EF框架的优化(一)
    在.Net中使用EF框架(.Net7,数据库SQLserver)在EntityFramework(EF)中,LINQ查询会被翻译成对应的SQL查询语句,以便与数据库进行交互。EF根据LINQ查询中的方法调用和操作符来进行翻译,一些常见的规则包括:1.简单的查询表达式会直接被翻译成对应的SQL语句,如SELECT、FROM、WHERE、OR......
  • GUI 框架或UI工具包
    对于Go语言编写的GUI程序,以下是比较成熟的方案:1.fyne:Fyne是一个新的、易于使用的Go语言UI框架,他采用了基于模块的体系结构,提供了完整的API元素库,支持图形、文本、布局、画布等等。2.go-qml:GoQML是一个基于Go语言的跨平台界面设计工具,支持Windows,MacOSX,Ubun......
  • web自动化框架basepage
    #-*-coding:utf-8-*-#@Author:caiweichao#@explain:基类封装webdriver方法,方便调用,减少代码重复importrandomimporttimeimportallurefromseleniumimportwebdriverfromselenium.common.exceptionsimport*fromselenium.common.exceptionsimportT......
  • Linux软件包管理器,RPM和YUM的区别
    RPMRPM(RedhatLinuxPacketManger)是RedHat公司随RedhatLinux推出的一个软件包管理器,通过它能够轻松实现Linux软件的安装。但是,需要手动解决软件包的依赖关系。YUMYUM(YellowdogUpdater,Modified)是一个Shell前端软件包管理器。基于RPM包管理器,能够从指定的服务器自动......
  • golang中的ORM框架
    目录ORM框架GORM基本用法1.安装GORM2.连接数据库3.定义模型4.执行CRUD操作5.迁移和查询ORM框架在Golang中,ORM(Object-RelationalMapping,对象关系映射)框架是一种用于将面向对象的概念与关系型数据库中的表进行映射的工具。通过使用ORM框架,开发者可以更方便地执行数据库操......
  • 自动化测试框架-数据读取
     1.准备数据:数据格式为{json},放在json文件内,例如这样:   2.工具类:读取.json文件,保存在Map<testCaseName,JSONObject>内publicstaticMap<String,JSONObject>jsonToSearchFilter(StringfileName)throwsIOException{Map<String,JSONObject>result=ne......