本文共 16562 字,大约阅读时间需要 55 分钟。
Unity 之 实用工具类分享
前言:最近做项目,每次新建一个项目都有重新去写一些工具类,有些东西写过了,就想这去之前的项目里面找,可是总是找了好一会才找到,实在是有些费劲;于是我总结了几个常用的工具类,以后做项目的时候直接导入工程使用就行了。
文末分享了一个UnityStriptsTools.unitypackage供大家使用。
一,单例
挂载到游戏物体上的单例实现
using System.Collections;using System.Collections.Generic;using UnityEngine;////// 单例/// public class Singleton: MonoBehaviour where T: Singleton { private static T _instance; public static T Ins { get { return _instance; } } protected virtual void Awake() { _instance = (T)this; } protected virtual void OnDestory() { _instance = null; }}
使用示例:这样就其他脚本中反问时,就不需要通过对应的GameObject.GetComponent<>() 来获取了,直接类名.Ins
这样可以了
示例代码:(记得要挂载到游戏物体上哦)
using System.Collections;using System.Collections.Generic;using UnityEngine;////// 单例使用示例/// 外部访问直接 --> SingletonTest.Ins.Show();/// public class SingletonTest : Singleton{ void Start() { //外部访问示例 //SingletonTest.Ins.Show(); } /// /// 外部单例访问测试 /// public void Show() { }}
二,对象池
通过一个公用脚本来统一管理需要动态加载的物体(如:子弹),这样用起来会方便很多,大量重复调用时也不有频繁生成销毁的销耗。
使用方法:将脚本挂载到一个空物体上,将其作为回收游戏对象的父物体,然后可以结合上面的单例一起使用,详情代码请看注释。
using System.Collections.Generic;using System.Reflection;using UnityEngine;////// 对象池/// public class PoolManager : MonoBehaviour//Singleton{ //最大容量 --> 你需要根据实际情况来调整这个数值 private int maxSize = 50; private List objectPool; #region 1.使用单例工具类 --> 需要删除"MonoBehaviour"并打开注释 "Singleton " //protected override void Awake() //{ // base.Awake(); // InitPool(); //} #endregion #region 2.自给自足,单例初始化 private static PoolManager _instance; public static PoolManager Ins { get { return _instance; } } protected virtual void Awake() { _instance = (PoolManager)this; InitPool(); } protected virtual void OnDestory() { _instance = null; } #endregion /// /// 初始化对象池 /// void InitPool() { objectPool = new List(); } /// /// 处理游戏体的所有子物体 -- 注意通过对象池生成的物体不要使用这个方法回收 /// /// public void Dispose(Transform tr) { Transform[] ch = new Transform[tr.childCount]; for (int i = 0; i < ch.Length; i++) { ch[i] = tr.GetChild(i); } for (int i = 0; i < ch.Length; i++) { ch[i].gameObject.SetActive(false); ch[i].SetParent(transform); objectPool.Add(ch[i].gameObject); ch[i] = null; } GameObject uselessObj; while (objectPool.Count > maxSize) { uselessObj = objectPool[0]; objectPool.RemoveAt(0); Destroy(uselessObj); } Resources.UnloadUnusedAssets(); } ////// 加载预制体 /// 参数示例:(transform, "Prefabs/GameObject") /// /// 父物体 /// 加载路径 ///public GameObject LoadPrefab(Transform parent, string path) { string[] nameArr = path.Split('/'); string name = nameArr[nameArr.Length - 1]; GameObject obj = LoadPrefab(path, name); obj.transform.SetParent(parent); SetLoaclScale(obj); obj.gameObject.SetActive(true); return obj; } /// /// 加载预制体 /// /// 父物体 /// 加载路径 ///GameObject LoadPrefab(string path, string name) { GameObject obj = null; for (int i = 0; i < objectPool.Count; i++) { if (objectPool[i].name == name) { obj = objectPool[i]; objectPool.RemoveAt(i); break; } } if (obj == null) { obj = Instantiate(Resources.Load (path)); obj.name = name; } return obj; } /// /// 设置本地缩放 /// /// private void SetLoaclScale(GameObject prefab) { RectTransform rect = prefab.GetComponent(); if (rect) { rect.anchoredPosition3D = Vector3.zero; rect.offsetMin = Vector2.zero; rect.offsetMax = Vector2.zero; rect.localScale = Vector3.one; } else { //prefab.transform.localPosition = Vector3.zero; prefab.transform.localScale = Vector3.one; } } /// /// 删除游戏体到对象池 /// /// public void Dispose(GameObject obj) { obj.SetActive(false); obj.transform.SetParent(transform); objectPool.Add(obj); } ////// 清空对象池 /// public void ClearPool() { for (int i = 0; i < objectPool.Count; i++) { Destroy(objectPool[i]); } objectPool.Clear(); } }
三,公共方法类
记录了几个常用方法:List,Dictionary 转字符串,加载Json,XML文件, 加载Sprite,SpriteAtlas,Material,Texture资源,概率随机数。
可根据实际使用进行增删改。
using System.Collections.Generic;using System.Text;using System.Xml;//using LitJson;using UnityEngine;using UnityEngine.U2D;////// 公共方法类/// public static class CommandMethod{ #region List,Dictionary 转字符串 // 需要转换什么类型,转换为什么格式自己重载就可以了 // ** 建议不要写成泛型的方式,为避免装箱拆箱。** public static string ListToJson(int[] data) { StringBuilder content = new StringBuilder(); content.Append("["); for (int i = 0; i < data.Length; i++) { if (i == data.Length - 1) content.Append(data[i] + "]"); else content.Append(data[i] + ","); } return content.ToString(); } public static string ListToJson(Listlist) { StringBuilder content = new StringBuilder(); content.Append("["); for (int i = 0; i < list.Count; i++) { content.Append(i + ":" + list[i]); } content.Append("]"); return content.ToString(); } public static string DicToJson(Dictionary dictionary) { StringBuilder content = new StringBuilder(); content.Append("{"); foreach (var key in dictionary.Keys) { content.Append(key + ":" + dictionary[key] + ","); } content.Append("}"); return content.ToString(); } #endregion #region 加载Json,XML文件 /// /// 加载Json文件 --> 需要在工程中添加Litjson.dll文件,否则会报错 /// /// /////public static JsonData LoadJson(string path) //{ // TextAsset asset = Resources.Load (path); // if (!asset) // { // Debug.LogError("加载Json文件 错误,路径是:" + path); // return null; // } // // 将读取到的字符串转换为JsonData 返回去 // return JsonMapper.ToObject(asset.text); //} /// /// 加载XMl文件 /// /// ///public static string LoadXML(string path) { XmlDocument Xdoc = new XmlDocument(); Debug.Log("当前目录是:" + path); //Application.dataPath); //加载XML 文件 Xdoc.Load(path + ".xml"); //获取跟节点 XmlElement root = Xdoc.DocumentElement; Debug.Log("根元素是:" + root.Name); // data : 下一个子节点的名称 //XmlNode dataNode = root.SelectSingleNode("data"); //获取根节点下的子节点 //Debug.Log("节点名称"+dataNode.Name); StringBuilder content = new StringBuilder(); // 读取到的字符串 for (int i = 0; i < root.ChildNodes.Count; i++) { content.Append(root.ChildNodes[i].InnerText + ","); } return content.ToString(); } #endregion #region 概率随机数 /// /// 指定概率随机数 /// 参数示例[10,20,30] -> 解释为数组索引0.1.2产生概率分别为 17%, 33%,50% /// /// 几率数组(%) ///public static int RandArr(int[] rate) { // 求和 int total = 1; // 随机数区间 [0,10) 左闭右开,所以初始值设置为1 for (int i = 0; i < rate.Length; i++) { total += rate[i]; } // 求随机 int r = Random.Range(1, total); int t = 0; // 计算返回随机数组索引 for (int i = 0; i < rate.Length; i++) { t += rate[i]; if (r < t) { return i; } } return 0; } #endregion #region 加载Sprite,SpriteAtlas,Material,Texture资源 /// /// 加载Sprite /// /// ///public static Sprite LoadSprite(string path) { return Resources.Load (path); } /// /// 已加载图集记录 /// private static Dictionarym_UISpriteAtlasDic = new Dictionary (); /// /// 加载指定路径图集中的指定名称图片 /// /// /// ///public static Sprite LoadSprite(string _atlasPath, string _spriteName) { Sprite tempSprite = null; SpriteAtlas tempAtlas = GetSpriteAtlas(_atlasPath); Debug.Log(_atlasPath + ".." + (tempAtlas == null)); if (tempAtlas != null) tempSprite = tempAtlas.GetSprite(_spriteName); return tempSprite; } /// /// 获取一个图集 /// /// ///static SpriteAtlas GetSpriteAtlas(string atlasName) { if (m_UISpriteAtlasDic.ContainsKey(atlasName)) { if (m_UISpriteAtlasDic[atlasName] == null) m_UISpriteAtlasDic[atlasName] = Resources.Load (atlasName); } else { m_UISpriteAtlasDic.Add(atlasName, Resources.Load (atlasName)); } return m_UISpriteAtlasDic[atlasName]; } /// /// 加载材质球 /// /// ///public static Material LoadMaterial(string path) { return Resources.Load (path); } /// /// 加载贴图 /// /// ///public static Texture LoadTexture(string path) { return Resources.Load (path); } #endregion}
四,切换场景不销毁
使用方法:将脚本挂载到,切换场景时不销毁的物体上即可。
using UnityEngine;////// 加载时不销毁的对象/// public class DontDestroy : MonoBehaviour{ private void Awake() { DontDestroyOnLoad(gameObject); } }
五,自我销毁
定时炸弹,挂载到不同游戏物体上,通过Inspector面板赋值Delay,经过Delay时间后自动销毁。
using UnityEngine;using System.Collections;////// 自我销毁/// public class SelfDestroying : MonoBehaviour{ // 自动销毁到计时 public float Delay; void Awake() { StartCoroutine(SelfDestroy(Delay)); } private IEnumerator SelfDestroy(float delay) { yield return new WaitForSeconds(delay); Destroy(gameObject); }}
六,进度条
切换场景时的进度条,需要显示%多少的文本,就给m_PassageText赋值,不需要则可以不用管,或者删除相关代码。
using System.Collections;using System.Collections.Generic;using UnityEngine;using UnityEngine.UI;using UnityEngine.SceneManagement;public class LoadIng : MonoBehaviour{ // 进度条 public Slider m_slider; // 进度文本 --> 不需要就删除 public Text m_PassageText; void Start() { //m_slider = this.transform.GetComponent(); // 记得修改要加载的场景名称 StartCoroutine(StartLoadingSecne("Main")); } private IEnumerator StartLoadingSecne(string sceneName) { AsyncOperation op = SceneManager.LoadSceneAsync(sceneName); op.allowSceneActivation = false; int curProgressValue = 0; while (curProgressValue == 90 || op.progress == 0.9) //!op.isDone { //progress 的取值范围在0.1 - 1之间, 但是它不会等于1 //也就是说progress可能是0.9的时候就直接进入新场景了 if (curProgressValue < (op.progress * 100)) { curProgressValue++; } SetLoading(curProgressValue); yield return new WaitForEndOfFrame(); } // 模拟加载到100% while (curProgressValue < 100) { curProgressValue++; SetLoading(curProgressValue); yield return new WaitForEndOfFrame(); } op.allowSceneActivation = true; yield return op; } void SetLoading(float value) { m_slider.value = value / 100f; if (m_PassageText) { m_PassageText.text = "Loading..." + value / 100f + "%"; } }}
七,为Image添加监听
为Image,Text 这种没有Button组件的UI添加监听事件,自己继承EventTrigger,实现了一个工具类,使用方法往后看:
using System.Collections;using System.Collections.Generic;using UnityEngine;using UnityEngine.EventSystems;public class EventTriggerListener : EventTrigger{ public delegate void VoidDelegate(GameObject go); public VoidDelegate onClick; public VoidDelegate onSelect; public VoidDelegate onBegainDrag; //public VoidDelegate onDown; //public VoidDelegate onUp; public VoidDelegate onPress; public VoidDelegate DesPress; static public EventTriggerListener Get(GameObject go) { EventTriggerListener listener = go.GetComponent(); if (listener == null) listener = go.AddComponent (); return listener; } public override void OnPointerClick(PointerEventData eventData) { if (onClick != null) { onClick(gameObject); } } public override void OnSelect(BaseEventData eventData) { if (onSelect != null) onSelect(gameObject); } public override void OnBeginDrag(PointerEventData eventData) { if (onBegainDrag != null) onBegainDrag(gameObject); } public override void OnPointerDown(PointerEventData eventData) { if (onPress != null) { onPress(gameObject); } } public override void OnPointerUp(PointerEventData eventData) { if (DesPress != null) { DesPress(gameObject); } }}
使用实例:通过EventTriggerListener给 可交互的UI组件添加点击事件,示例代码如下:
using UnityEngine;using UnityEngine.UI;public class EventListenerTest : MonoBehaviour{ public Text text; public Image image; void Start() { //添加监听 EventTriggerListener.Get(text.gameObject).onClick = OnButtonClick; EventTriggerListener.Get(image.gameObject).onClick = OnButtonClick; //取消监听 // Destroy(EventTriggerListener.Get(image.gameObject).GetComponent()); } void OnButtonClick(GameObject go) { Debug.Log("OnButtonClick ..." + go.name); //根据点击不同按钮做指定的事情 switch (go.name) { case "Back": Debug.Log("OnButtonClick ... Back"); break; case "GoOn": Debug.Log("OnButtonClick ... GoOn"); break; } }}
八,时间工具类
这个没什么可说的了,根据自己的需求增删改就行了。
using System;using UnityEngine;////// 时间工具类/// public static class TimerTools{ ////// 获取当前的时间戳(秒) /// ///public static long GetNowTime() { TimeSpan cha = (DateTime.Now - TimeZone.CurrentTimeZone.ToLocalTime(new DateTime(1970, 1, 1))); long t = (long)cha.TotalSeconds; return t; } /// /// 获取两个时间戳时间间隔(单位秒) /// /// 时间戳1(10位) /// 时间戳2(10位) ///public static int GetSecondInterval(long timestapMax, long timestapMin) { //Debug.Log("时间戳间隔: " + timestapMax + " " + timestapMin); int resultTime = (int)Mathf.Round((float)((timestapMax - timestapMin))); return resultTime; } /// /// 计时时间转 00:00格式 /// /// 转换时间 /// 显示小时 ///public static string TimerIntToString(int time, bool showHour = false) { if (showHour) { return (time / 3600 > 9 ? "" : "0") + time / 3600 + ":" + ((time % 3600) / 60 > 9 ? "" : "0") + (time % 3600) / 60 + ":" + (time % 60 > 9 ? "" : "0") + time % 60; } else { return (time / 60 > 9 ? "" : "0") + time / 60 + ":" + (time % 60 > 9 ? "" : "0") + time % 60; } } /// /// 两个日期是否是同一天 /// /// /// ///public static bool IsOneDay(string DateTime1, string DateTime2) { DateTime t1 = Convert.ToDateTime(DateTime1); DateTime t2 = Convert.ToDateTime(DateTime2); Debug.Log(t1 + ".." + t2 + "---" + t1.Day + ".." + t2.Day); return (t1.Year == t2.Year && t1.Month == t2.Month && t1.Day == t2.Day); } #region 时间戳 和 DateTime 相互转换 /// /// DateTime转换为Unix时间戳 /// /// ///public static long DateTimeToUnix(DateTime dateTime) { DateTime startTime = TimeZone.CurrentTimeZone.ToLocalTime(new System.DateTime(1970, 1, 1)); // 当地时区 // 相差秒数 long timeStamp = (long)(dateTime - startTime).TotalSeconds; Console.WriteLine(); return timeStamp; } /// /// Unix时间戳转换为 DateTime /// /// ///public static string UnixToDateTime(long unixTimeStamp) { //long unixTimeStamp = 1478162177; DateTime startTime = TimeZone.CurrentTimeZone.ToLocalTime(new System.DateTime(1970, 1, 1)); // 当地时区 DateTime dt = startTime.AddSeconds(unixTimeStamp); Debug.Log(dt.ToString("yyyy/MM/dd HH:mm:ss:ffff")); return dt.ToString("yyyy/MM/dd HH:mm:ss:ffff"); } #endregion }
所有代码的package:
文件目录:
积分不足的同学,请扫描主页左侧二维码或者V信搜索“开发同学留步”,回复关键字“工具类”即可获得。
转载地址:https://czhenya.blog.csdn.net/article/details/114388895 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!