Unity 之 实用工具类分享
发布日期:2021-06-29 19:10:15 浏览次数:3 分类:技术文章

本文共 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(List
list) {
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 Dictionary
m_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:

文件目录:

111

积分不足的同学,请扫描主页左侧二维码或者V信搜索“开发同学留步”,回复关键字“工具类”即可获得。


转载地址:https://czhenya.blog.csdn.net/article/details/114388895 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:C#设计模式 之 抽象工厂模式
下一篇:Unity 之 获取发布APK的SHA1值步骤详解

发表评论

最新留言

路过,博主的博客真漂亮。。
[***.116.15.85]2024年04月20日 18时45分40秒