# TinyToolKit **Repository Path**: wiit/TinyToolKit ## Basic Information - **Project Name**: TinyToolKit - **Description**: 汇总平时开发中的常用功能模块,例如:事件中心、界面管理、计时器、数据结点、音频管理、有限状态机、对象池、资源加载、本地化、网络等。 - **Primary Language**: C# - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 2 - **Created**: 2023-02-06 - **Last Updated**: 2023-02-06 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # TinyToolKit TinyToolKit是一个基于Unity引擎的工具套件(基础框架),主要目的在于能规范化开发过程,提供常用功能模块,缩短项目开发时间。 主要功能模块包括:事件中心、界面管理、计时器、数据结点、音频管理、有限状态机、对象池、资源加载、本地化、网络等。 ## 编辑器窗口 ### TinyToolKit窗口 通过编辑器扩展实现 TinyToolKit 的编辑窗口,包含两种模式 Manager 和 Editor。 打开路径:TinyToolKit/Window/TinyToolKit 在Manager模式下,可以在编辑器运行后,实时查看各个功能模块的运行数据,例如AB包资源加载情况、计时器的运行情况、 ![Manager模式](https://gitee.com/opportunitystudio/TinyToolKit/raw/master/TinyToolKit/Pic/Manager.png) 在Editor模式下,主要功能包括:常量列表和UI配置表的编辑输出,多国语言的可视化编辑,AssetBundle资源打包。 ![AssetBundle资源打包](https://gitee.com/opportunitystudio/TinyToolKit/raw/master/TinyToolKit/Pic/AssetBundle.png) ![多国语言的可视化编辑](https://gitee.com/opportunitystudio/TinyToolKit/raw/master/TinyToolKit/Pic/Localization.png) ### ShaderLab查询窗口 记录ShaderLab相关的内容,包含编译指令、渲染状态、预定义宏、矩阵变换、函数方法等内容,支持存储、查询、修改、删除的功能。 ![ShaderLab查询窗口](https://gitee.com/opportunitystudio/TinyToolKit/raw/master/TinyToolKit/Pic/Shader.png) ## 基础工具 ### 日志输出 大量的日志打印也会影响一定的性能。通过宏定义来控制是否打印日志,可以减小性能的浪费。 **类图** ``` graph BT A[TLogTool]-.->B[ILogTemplate] ``` **用法** 日志打印根据重要程度分为四个等级,调试,信息,警告,错误。 ```c# public enum LogLevel { DEBUG,//调试 INFO,//信息 WARNING,//警告 ERROR//错误 } ``` 注意:日志参数的数量尽量不要超过3个,否则生成可变参数数组,产生更多的内存分配。 ```c# TLogTool.Debug(""); TLogTool.Info(""); TLogTool.Warning(""); TLogTool.Error(""); ``` **编辑器添加宏定义** 日志输出可以通过宏定义来设置,可以规定哪些级别的日志可以输出,哪些级别的日志内容被屏蔽。可以在TinyToolKit窗口中进行设置。 **自定义日志模板** 日志模板类需要继承自接口TLogTool.ILogBase,实现Log方法,并调用TLogTool.SetLogTemplate()设置日志的模板即可。如果没有自定义日志模板,系统会自动调用默认的DefaultLogTemplate模板。 ``` using UnityEngine; namespace TinyToolKit { public class DefaultLogTemplate : TLogTool.ILogBase { public void Log(TLogTool.LogLevel level, object msg) { switch (level) { case TLogTool.LogLevel.DEBUG: Debug.Log("" + msg.ToString() + ""); break; case TLogTool.LogLevel.INFO: Debug.Log("" + msg.ToString() + ""); break; case TLogTool.LogLevel.WARNING: Debug.LogWarning("" + msg.ToString() + ""); break; case TLogTool.LogLevel.ERROR: Debug.LogError("" + msg.ToString() + ""); break; } } } } ``` ### 事件中心 为了降低各个业务模块之间的耦合度,使用一套消息通信机制很有必要。事件中心模块基于观察者模式提供了游戏事件的订阅、注销和广播的功能。 **用法** 定义事件类型,不同事件类型有自己的消息枚举,方便维护各自内部的消息事件 ``` public enum MathType { Add } ``` 订阅事件 ``` EventCenter.Subscribe(MathType.Add, Add); ``` 注销事件 ``` EventCenter.Unsubscribe(MathType.Add, Add); ``` 广播事件 ``` EventCenter.Broadcast(MathType.Add, 1, 2); ``` **注意** 事件的订阅与注销在使用生命周期内,应当成对出现。比如实体显示时订阅、隐藏时注销,界面打开时订阅、关闭时注销。 ### 引用池 为了减少系统频繁地创建和销毁引用类型对象时的开销,加入引用池的模块,以实现复用引用类型对象的功能。在引用类型对象使用结束后,将其清理并缓存起来,以供后续使用。 **类图** ``` graph BT A[TReferencePool] -.-> B[ReferenceBasePool] B -.-> C[IReference] ``` **用法** 若要定义引用类,只需要继承IReference接口,并实现Clear方法。 ``` public class ReferenceExample : IReference { //回收时,清理数据 public void Clear() { } } ``` 从引用池获取引用 ``` //ReferenceExample reference = TReferencePool.Acquire(typeof(ReferenceExample)) as ReferenceExample; ReferenceExample reference = TReferencePool.Acquire(); ``` 向引用池添加指定数量的引用 ``` TReferencePool.Add(100); ``` 将引用归还引用池 ``` TReferencePool.Release(reference); ``` 获取引用池内正在使用的引用个数 ``` TReferencePool.GetUsingReferenceCount() ``` 获取引用池内还未使用的个数 ``` TReferencePool.GetUnusedReferenceCount() ``` 移除引用池内指定个数的引用 ``` TReferencePool.Remove(10); ``` 移除引用池内所有的引用 ``` TReferencePool.RemoveAll(); ``` 获取引用池的数量 ``` TReferencePool.Count ``` 清空所有引用池 ``` TReferencePool.ClearAllPools(); ``` ### 静态类扩展 **GameObject** 获取组件,没有组件则增加 ``` gameObject.GetOrAddComponent() ``` 销毁自身对象 ``` gameObject.DestroySelf() ``` 立刻销毁自身 ``` gameObject.DestroyImmediate() ``` 在场景加载时,不销毁自身 ``` gameObject.DontDestroyOnLoad() ``` 查找子物体,如果不存在则创建 ``` gameObject.FindOrCreate(name) ``` 判断当前对象是否为空 ``` gameObject.IsNull() ``` **Transform** 设置绝对位置的X坐标,其他方法类似 ``` transform.SetPosX(x) ``` 设置局部坐标的X值,其他方法类似 ``` transform.SetLocalPosX(x) ``` 重设局部坐标 ``` transform.Reset() ``` 递归遍历所有子对象,查找目标 ``` transform.FindTargetInChildren(targetName) ``` 设置子节点,并重设子节点局部坐标 ``` transform.SetStandardChild(child) ``` 查找子类对象,如果找不到则创建 ``` transform.FindOrCreate(childName,isIncludeAllChildren) ``` **String** 判断是否为空或是否为空字符串 ``` string.IsNullOrEmpty() ``` ## 界面管理 基于UGUI封装了窗体的各种属性和方法,例如界面进入、退出、暂停、回复等功能。通过UI管理器来调用各个窗体的切换显示,并支持模态窗体显示。在窗体结束使用后不进行销毁,等待下一次的调用。资源加载方式支持Resources动态加载,或AB包加载。 >“模态”:模态对话框(Modal Dialogue Box,又叫做模式对话框),是指在用户想要对对话框以外的应用程序进行操作时,必须首先对该对话框进行响应。如单击【确定】或【取消】按钮等将该对话框关闭。 **类图** ``` graph BT A[TUIManager]-.->B[UIFormBase] ``` **用法** 1. 所有的窗体类需要派生自UIFormBase,UIFormBase作为窗体的基类,实现了一些窗体的特性和方法,并提供了默认的实现。 - 可以重写的方法,方便在UI窗体状态发生改变的时候,更新界面 初始化窗体,只调用一次 ``` void OnInit() ``` 界面进入,每一次进入时都调用 ``` void OnEnter() ``` 界面暂停,每一次暂停时都调用 ``` void OnPause() ``` 界面继续,每一次继续时都调用 ``` void OnResume() ``` 界面退出,每一次退出时都调用 ``` void OnExit() ``` - 辅助方法 打开窗体 ``` UIFormBase OpenUIForm(string uiFormName) ``` 关闭窗体 ``` void CloseUIForm(string uiFormName) ``` 关闭自身窗体 ``` void Close() ``` 2. 生成UI配置表,可以直接使用TinyToolKit编辑器来创建UI配置表,可以将其放在Resources文件夹内自动读取,或者通过调用方法来指定配置表。格式如下: ```json { "UIFormPaths": [ { "UIFormName": "ChooseHeroForm", "UIFormSavePath": "Assets/TinyToolKit_SimpleDemo/Resources/UIForm/ChooseHeroForm.prefab" }, { "UIFormName": "LoginUIForm", "UIFormSavePath": "Assets/TinyToolKit_SimpleDemo/Resources/UIForm/LoginUIForm.prefab" } ] } ``` 3. UI管理器 获取UI管理器 ``` TUIManager uiManager = TinyTool.Instance.GetManager(); ``` 设置并解析UIForm的Json格式配置表 ``` void SetUIFormPaths(string jsonMsg) ``` 打开窗体 ``` UIFormBase OpenUIForm(string uiFormName) ``` 关闭窗体 ``` void CloseUIForm(string uiFormName) ``` 获取指定窗体 ``` UIFormBase GetUIForm(string uiFormName) ``` 关闭所有窗体 ``` void CloseAllUIForms() ``` ## 计时器 **功能** 高效便捷计时器工具,定时任务可循环、可替换、可取消。 协程定时的弊端:取消定时,循环操作,多个协程管理等不方便,依赖于MonoBehaviour,不能扩展到其他地方。 **类图** ``` graph BT A[TTimerManager]-.->B[TimerTask] ``` **用法** 定时管理器的相关操作 获取定时管理器 ``` TTimerManager timerManager = TMainManager.Instance.GetManager(); ``` 添加定时任务,返回当前定时任务的ID号,回调方法callback在每一次计时任务完成后,都会调用一次 ``` int AddTimerTask(Action callback,float duration,TimerUnit timerUnit = TimerUnit.Second ,int repeatCount = 1) int AddTimerTask(Action callBack,T obj, float duration, int repeatCount = 1) ``` 暂停定时任务 ``` bool PauseTimerTask(int taskID) ``` 恢复定时任务 ``` bool ResumeTimerTask(int taskID) ``` 删除定时任务 ``` bool DeleteTimerTask(int taskID) ``` 替换定时任务 ``` bool ReplaceTimerTask(int taskID, Action callback, float duration, TimerUnit timerUnit = TimerUnit.Second, int repeatCount = 1) ``` 添加帧定时任务 ``` int AddTimeTaskByFrame(Action callback, int frameCount, int repeatCount = 1) int AddTimeTaskByFrame(Action callBack,T obj,int frameCount, int repeatCount = 1) ``` 暂停帧定时任务 ``` bool PauseTimerTaskByFrame(int taskID) ``` 恢复帧定时任务 ``` bool ResumeTimerTaskByFrame(int taskID) ``` 删除帧定时任务 ``` bool DeleteTimerTaskByFrame(int taskID) ``` 替换帧定时任务 ``` bool ReplaceTimerTaskByFrame(int taskID, Action callback, int frameCount, int repeatCount = 1) ``` 根据任务ID获取任务的状态 ``` TaskState GetTaskState(int taskID) ``` 定时器拓展方法 ``` string ConvertSecondsToTime(int secondTime) string GetNowLocalTime() int GetYear() int GetMonth() int GetDay() int GetWeek() int GetHour() int GetMinute() int GetSecond() ``` ## 数据结点 存储游戏运行中的数据,将任意类型的数据以树状结构进行存储 **类图** ``` graph BT A[TDataNodeManager]-.->B[DataNode] B -.-> C[TinyData] ``` **用法** 使用该方法进行存储的数据,需要继承自TinyData类,例如: ``` public class T_Int : TinyData { public T_Int(int value):base(value) { } } public class T_String : TinyData { public T_String(string value):base(value) { } } ``` 也可以存储自定义的类,为了方便编辑器面板查看具体值,可以重写ToString方法,例如: ``` public class MyHero { public string name; public bool sex; public int level; } public class T_MyHero : TinyData { public T_MyHero(MyHero value):base(value) { } public override string ToString() { return $"name:{Value.name},sex:{Value.sex},level:{Value.level}"; } } ``` 获取数据结点管理器 ``` TDataNodeManager dataNodeManager = TinyTool.Instance.GetManager(); ``` 管理器的主要方法示例: ``` //注意这里的路径都需要写全路径,但不用包含"Root" dataNodeManager.SetData("Player.Name.FirstName",new T_String("Yu")); dataNodeManager.GetData("Player.Name.LastName"); dataNodeManager.GetNode("Player.Name"); dataNodeManager.RemoveNode("Player.Name"); ``` 结点类的主要方法示例: ``` DataNode player = root.GetChildNode("Player"); player.AddChildNode("Name", new T_String("Lili")); player.HasChildNode("Name"); player.RemoveChildNode("Name"); player.GetData(); ``` ## 音频管理 音频管理器将程序中使用的音频分为了三类:背景音乐、特效音效、UI音效。 主要实现功能: - 控制音乐的播放控制 - 全局音量管理 - 背景音乐的淡入淡出效果 - 可跨场景持久化播放 - 是否允许同时播放相同的音效 - 音频缓存池 - 可以设置2D\3D音效,将其绑定在目标对象身上 **用法** 获取音频管理器 ``` TSoundManager soundManager = TinyTool.Instance.GetManager(); ``` 播放音频 ``` int PlayMusic(...) int PlayFxSound(...) int PlayUISound(...) ``` 暂停音频 ``` void Pause(...) void PauseAllMusic(...) void PauseAllFxSounds(...) void PauseAllUISounds(...) void PauseAll(...) ``` 恢复播放音频 ``` void Resume(...) void ResumeAllMusic(...) void ResumeAllSounds(...) void ResumeAllUISounds(...) void ResumeAll(...) ``` 停止播放音频 ``` void Stop(...) void StopAllMusic(...) void StopAllFxSounds(...) void StopAllUISounds(...) void StopAll(...) ``` 获取音频AudioItem信息 ``` void GetMusicAudio(...) void GetFxSoundAudio(...) void GetUISoundAudio(...) ``` ## 有限状态机 **定义** 有限状态机(FSM),是指在不同阶段呈现不同运行状态的系统,这些状态是有限的,不重叠的。这样的系统在某一时刻一定会处于其中所有状态中的一个状态,此时它接收一部分输入,并产生相应的响应,并且迁移到可能的状态。提供了描述和控制应用逻辑的强大功能,常常应用于控制NPC的行为,图形界面管理等。FSM可以使得各个状态之间相互独立,互不影响,避免了状态和状态之间的耦合度,具有规则简单,可读性和可验证性等优点。 **功能** FSM管理器提供创建、使用、切换和销毁状态机的功能。允许同一个有限状态机被多个实例运用,但需要注意有限状态机的名称不能重复。 **类图** ``` graph BT subgraph FSM系统 A[FsmSystem]-.->B[IFsm] A[FsmSystem]-.->C[FsmBase] end A-->D[FsmState] subgraph FSM管理器 E[FsmManager]-.->F[IFsmManager] E[FsmManager]-.->G[ManagerBase] E[FsmManager]-->A end ``` **用法** - 有限状态机管理器的相关操作 1. 获取有限状态机管理器 ``` TFsmManager fsmManager = TinyTool.Instance.GetManager(); ``` 2. 创建有限状态机实例 创建有限状态机,持有者为owner,类型为T,有限状态机实例名称为name,states是有限状态机的状态 ``` IFsm CreateFsm(string name, T owner, params FsmState[] states) where T : class IFsm CreateFsm(string name, T owner, List> states) where T : class ``` 3. 判断是否存在有限状态机 ``` bool HasFsm(string name) where T : class bool HasFsm(Type ownerType, string name) ``` 4. 获取有限状态机 ``` IFsm GetFsm(string name) where T : class FsmBase GetFsm(Type ownerType, string name) FsmBase[] GetAllFsms() void GetAllFsms(List fsms) ``` 5. 销毁有限状态机 ``` bool DestroyFsm(FsmBase fsm); bool DestroyFsm(Type ownerType, string name); bool DestroyFsm(string name) where T : class; bool DestroyFsm(IFsm fsm) where T : class; ``` 6. 获取有限状态机的数量 ``` int FsmCount { get; } ``` - 有限状态机的状态相关操作 1. 定义有限状态机的状态 有限状态机的状态均派生自FsmState,T是该有限状态机的持有者类型。 ``` using UnityEngine; using TinyToolKit; using TinyToolKit.FSM; public class PatrolState : FsmState { //有限状态机开启的时候调用 protected internal override void OnInit() { base.OnInit(); TLogTool.Debug("Patrol_OnInit"); } //进入该状态的时候调用 protected internal override void OnEnter() { base.OnEnter(); TLogTool.Debug("Patrol_OnEnter"); } //离开该状态的时候调用 protected internal override void OnLeave() { base.OnLeave(); TLogTool.Debug("Patrol_OnLeave"); } //本状态在轮询的时候调用 protected internal override void OnUpdate() { base.OnUpdate(); TLogTool.Debug("Patrol_OnUpdate"); } //该有限状态机销毁的时候调用 protected internal override void OnDestroy() { base.OnDestroy(); TLogTool.Debug("Patrol_OnDestroy"); } } ``` 2. 有限状态机的相关操作 开启有限状态机 ``` void Start() where T2 : FsmState void Start(Type stateType) ``` 切换有限状态机的状态 ``` void ChangeState() where T2 :FsmState void ChangeState(Type stateType) ``` 判断是否存在状态 ``` bool HasState() where T2 : FsmState bool HasState(Type stateType) ``` 获取有限状态机的状态 ``` T2 GetState() where T2 : FsmState FsmState GetState(Type stateType) FsmState[] GetAllStates() void GetAllStates(List> results) ``` 切换有限状态机的状态 ``` void ChangeState(Type stateType) void ChangeState() where T2 : FsmState ``` 状态机的数据处理 ``` bool HasData(string name) object GetData(string name) T2 GetData(string name) where T2 : class void SetData(string name, object data) void SetData(string name, T2 data) where T2 : class bool RemoveData(string name); ``` - 常用属性 ``` // 获取有限状态机的名称 string Name { get; } // 获取有限状态机的完整名称 string FullName { get; } // 获取有限状态机持有者 T Owner { get; } // 获取有限状态机的状态数量 int FsmStateCount { get; } // 判断该状态机是否正在运行 bool IsRunning { get; } // 判断该状态机是否被销毁 bool IsDestroyed { get; } // 获取当前有限状态机的状态 FsmState CurrentState { get; } // 获取当前状态的全名 string CurrentStateName { get; } // 获取当前状态持续时间 float CurrentStateTime { get; } ``` ## 对象池 对象池管理器,提供了对象缓存池的功能,避免频繁的创建和销毁各种对象,减少程序性能消耗。 **类图** ``` graph BT A[TObjectPool]-- 实现接口 -->B[IObjectPool] A-.->C[ObjectPoolItem] D[TObjectManager]-.->A D-- 实现接口 -->E[IObjectManager] ``` **用法** 1. 获取对象池管理类 ``` TObjectPoolManager objectPoolManager = TinyToolKit.TinyTool.Instance.GetManager(); ``` 2. 对象池管理类的方法 判断是否已经存在poolName对应的对象池 ``` bool HasObjectPool(string poolName) ``` 根据对象池名返回TObjectPool ``` TObjectPool GetObjectPool(string poolName) ``` 创建对象池 ``` TObjectPool CreateObjectPool(...) ``` 销毁对象池 ``` bool DestroyObjectPool(string poolName) ``` 实例化对象池中的对象 ``` GameObject SpawnObject(string poolName) ``` 实例化对象池中的对象 ``` GameObject SpawnObject(...) ``` 回收对象池中的对象 ``` bool RecycleObject(GameObject obj) ``` 3. 对象池类的方法 产生对象 ``` T Spawn() ``` 回收对象 ``` bool Recycle(T obj) ``` 优先释放未被使用的对象,如果释放数量大于剩余未使用的数量,则释放所有未使用的 ``` void Release(int releaseCount) ``` 释放所有未被使用的对象 ``` void ReleaseAllUnused() ``` 间隔一定时间,自动释放未使用的对象 ``` void ActiceAutoRelease(float time) ``` 取消自动释放 ``` void DeacticeAutoRelease() ``` ## 资源加载 提供两种资源加载的方式:Resources加载、AB包加载 Resources加载主要功能: - 资源缓存池,加载过的资源会被缓存起来,下一次加载可以直接从缓存池中获取 - 提供同步、异步加载资源的方法 AB包加载: - 资源缓存池 - 同步、异步加载本地资源 - 支持预加载远程资源 - 提供资源的编辑器模式,仅可在编辑器内使用。为了开发时的方便,避免反复构建AssetBundle,该模式下,所有资源利用UnityEditor.AssetDatabase直接从磁盘加载资源,即使保存勾选此选项,在发布后此选项也将失效 **用法** ### Resources 管理器 主要封装了Resources动态加载资源的方法,可以同步或异步加载资源,同时添加了缓存池功能。 获取Resources管理器 ``` TResourcesManager resourcesManager = TinyTool.Instance.GetManager(); ``` 加载资源 ``` Object LoadAsset(string resPath) T LoadAsset(string resPath) ``` 加载指定文件夹路径下的所有的资源 ``` Object[] LoadAllAssets(string resPath) T[] LoadAllAssets(string resPath) ``` 异步加载资源 ``` void LoadAssetsAsync() ``` 卸载资源 ``` void UnloadUnusedAssets() ``` ### AssetBundle 管理器 AB包资源加载分为:编辑器模拟模式 和 AB包加载模式。 **编辑器模拟模式:** 模拟加载AB包资源,并没有真正的去加载AB包,而是通过编辑器API直接加载Assets目录下的资源,该模式在发布后将会失效。编辑器模式可以预演发布状态下的各种情况,如资源异步加载等,方便调试发布时的相关问题。在开发阶段,解决了频繁打AB包资源的问题,提高了开发效率。 **AB包加载模式:** 该模式需要预先构建并准备完成AB包资源,是真机测试阶段使用的模式。基于引用计数,简化AB包资源的加载和卸载。有两种加载AB包资源的方式:本地加载、服务器加载(非缓存下载,缓存加载)。支持同步或异步加载AB包资源对象。支持AB包版本对比,提供简单的加密解密AB包资源的方式,避免AB包资源被轻易破解。注意:服务器加载AB包资源的缓存加载模式不支持加载加密的AB包资源。 获取AssetBundle管理器 ``` TAssetBundleManager assetBundleManager = TinyTool.Instance.GetManager(); ``` 加载本地AB配置表 ``` AssetBundleConfig LoadABConfig(string targetPath) ``` 下载AB包配置表 ``` void LoadABConfigAsync(...) ``` 异步加载AB包资源,可以将AB包下载至本地,或者加载到内存中 ``` void LoadABResAsync(...) ``` 获取当前下载的进度 ``` float GetDownloadProgress() ``` 同步加载本地资源或缓存资源,如果缓存中没有该AB包,会尝试从本地加载 ``` T LoadResource(...) ``` **异步加载Asset资源的方法消耗性能有待改善** 初始化用于异步加载资源的协程,需要在异步加载Asset方法之前调用 ``` void InitCoroutine(ReadPathType readPathType,string path) ``` 异步加载本地资源,可以同时异步加载多个资源 ``` void LoadLocalResAsync(...) ``` 释放资源 ``` //AssetBundle.Unload(true) 可能会导致克隆出来的预制体对象丢失贴图和材质 //在Instantiate将运存中的预制体克隆到内存后,根据依赖关系找到对应的贴图和材质。所以当预制体的AB包卸载后,丢失引用,但克隆的对象还在。 //如果cache为true,则资源会被缓存下来,等待下一次调用 //如果cache为false,当引用次数为0时,obj资源会被置空,对应的AB包资源也会被完全卸载 bool ReleaseResource(Object obj, bool cache = true) ``` ## 本地化 提供本地化功能,主要解决一个程序需要实现多种语言切换的功能。 **用法** 获取本地化管理器 ``` TLocalizationManager localizationManager = TinyTool.Instance.GetManager(); ``` 自定义模式下,设置翻译配置表 ``` void SetLanTranslates(Language lan, string jsonMsg) ``` 切换至本机系统语言 ``` bool ChangeSystemLanguage() ``` 切换至指定语言 ``` bool ChangeLanguage(Language lan) ``` 根据关键词判断是否存在该翻译 ``` bool HasTranslation(string key) ``` 根据关键词得到该翻译 ``` string GetTranslation(string key) ``` 添加翻译 ``` bool AddTranslation(string key, string value) ``` 根据关键词移除翻译 ``` bool RemoveTranslation(string key) ``` 提供两个回调方法,在切换语言时、切换语言结束后的回调函数 ``` public event Action OnLanguageChanged; public event Action OnLanguageChangedLater; ``` ## 网络 - 通过UDP广播自动获取局域网IP地址 - 提供使用Socket长连接功能,支持TCP协议,可以同时建立多个客户端与服务器进行通信,主要支持局域网开发 > UDP广播:与单播的区别就是IP地址不同,广播使用广播地址,将信息发送到在同一个广播网络上的每一个主机,但本地广播不会被路由器转发的。 ## 扩展工具 ### Xml 序列化 定义:序列化,又称串行化,是.NET运行时环境用来支持用户定义类型的流化的机制。其目的是以某种存储形式使自定义对象持久化,或者将这种对象从一个地方传输到另一个地方。简单来说就是**将对象保存到文件中**。 如Unity的场景文件和预制体默认就是以二进制的文件保存在工程目录下。 **1. 序列化** 将类序列化为Xml文件,需要引用命名空间:System.Xml.Serialization 需要为序列化的类,加上System.Serializable的标签 [XmlAttribute()] 序列化属性 [XmlElement()] 序列化字段 [XmlArray()] 序列化数组 ``` [System.Serializable] public class TestSerialize { [XmlElement("Id")] public int Id { get; set; } [XmlElement("Name")] public string Name { get; set; } [XmlArray("IntValueList")] public List IntValueList { get; set; } } ``` **2. 常用方法** Xml序列化 ``` TinyUtility.XML.XmlSerialize(TinyUtility.Path.GetStreamingAssetsPath() + "XMLtest.xml", test); ``` Xml反序列化 ``` TestSerialize test = TinyUtility.XML.XmlDeSerialize(TinyUtility.Path.GetStreamingAssetsPath() + "XMLtest.xml"); ``` ```` TestSerialize test = TinyUtility.XML.XmlDeSerialize(typeof(TestSerialize),TinyUtility.Path.GetStreamingAssetsPath() + "XMLtest.xml") as TestSerialize; ```` **3. 自定义XML函数集模板** 修改DefaultXmlTemplate脚本,可以自定义XML函数集模板 ``` namespace TinyToolKit { /// /// 默认的XML函数集辅助模板 /// public class DefaultXmlTemplate : TinyUtility.XML.IXmlTemplate { public void XmlSerialize(string savePath, object obj) { //TODO } public T XmlDeSerialize(string targetPath) where T : class { //TODO } public object XmlDeSerialize(Type objectType, string targetPath) { //TODO } } } ``` ### Json 函数集 **1. 常用方法** ``` // 将对象序列化为JSON字符串 string ToJson(object obj); // 将Json字符串反序列化为对象 T ToObject(string json); // 将JSON字符串反序列化为对象 object ToObject(Type objectType, string json); ``` 示例: ``` Test01 test02 = TinyUtility.Json.ToObject(str); ``` ``` string str = TinyUtility.Json.ToJson(test); ``` **2. 自定义Json函数集模板** 通过修改DefaultJsonTemplate可以自定义Json函数集格式 ```c# public class DefaultJsonTemplate : TinyUtility.Json.IJsonTemplate { public string ToJson(object obj) { return JsonUtility.ToJson(obj); } public T ToObject(string json) { return JsonUtility.FromJson(json); } public object ToObject(Type objectType, string json) { return JsonUtility.FromJson(json,objectType); } } ``` # 特别感谢 Ellan Jiang 的 [GameFramework](https://github.com/EllanJiang) 框架 凉鞋 的 [Qframework](https://qframework.cn/intro) 框架