赞
踩
前言:最近做项目,每次新建一个项目都有重新去写一些工具类,有些东西写过了,就想这去之前的项目里面找,可是总是找了好一会才找到,实在是有些费劲;于是我总结了几个常用的工具类,以后做项目的时候直接导入工程使用就行了。
文末分享了一个UnityStriptsTools.unitypackage供大家使用。
挂载到游戏物体上的单例实现
using System.Collections; using System.Collections.Generic; using UnityEngine; /// <summary> /// 单例 /// </summary> public class Singleton<T> : MonoBehaviour where T: Singleton<T> { 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; /// <summary> /// 单例使用示例 /// 外部访问直接 --> SingletonTest.Ins.Show(); /// </summary> public class SingletonTest : Singleton<SingletonTest> { void Start() { //外部访问示例 //SingletonTest.Ins.Show(); } /// <summary> /// 外部单例访问测试 /// </summary> public void Show() { } }
不继承MonoBehaviour
的写法
public class Singleton<T> where T : new() { private static T instance; public static T Instance { get { if(instance == null) instance = Activator.CreateInstance<T>(); return Singleton<T>.instance; } } protected Singleton() { } }
通过一个公用脚本来统一管理需要动态加载的物体(如:子弹),这样用起来会方便很多,大量重复调用时也不有频繁生成销毁的销耗。
使用方法:将脚本挂载到一个空物体上,将其作为回收游戏对象的父物体,然后可以结合上面的单例一起使用,详情代码请看注释。
using System.Collections.Generic; using System.Reflection; using UnityEngine; /// <summary> /// 对象池 /// </summary> public class PoolManager : MonoBehaviour//Singleton<PoolManager> { //最大容量 --> 你需要根据实际情况来调整这个数值 private int maxSize = 50; private List<GameObject> objectPool; #region 1.使用单例工具类 --> 需要删除"MonoBehaviour"并打开注释 "Singleton<PoolManager>" //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 /// <summary> /// 初始化对象池 /// </summary> void InitPool() { objectPool = new List<GameObject>(); } /// <summary> /// 处理游戏体的所有子物体 -- 注意通过对象池生成的物体不要使用这个方法回收 /// </summary> /// <param name="tr"></param> 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(); } /// <summary> /// 加载预制体 /// 参数示例:(transform, "Prefabs/GameObject") /// </summary> /// <param name="parent">父物体</param> /// <param name="path">加载路径</param> /// <returns></returns> 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; } /// <summary> /// 加载预制体 /// </summary> /// <param name="parent">父物体</param> /// <param name="path">加载路径</param> /// <returns></returns> 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<GameObject>(path)); obj.name = name; } return obj; } /// <summary> /// 设置本地缩放 /// </summary> /// <param name="prefab"></param> private void SetLoaclScale(GameObject prefab) { RectTransform rect = prefab.GetComponent<RectTransform>(); 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; } } /// <summary> /// 删除游戏体到对象池 /// </summary> /// <param name="obj"></param> public void Dispose(GameObject obj) { obj.SetActive(false); obj.transform.SetParent(transform); objectPool.Add(obj); } /// <summary> /// 清空对象池 /// </summary> 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; /// <summary> /// 公共方法类 /// </summary> 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<string> 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<string, string> 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文件 /// <summary> /// 加载Json文件 --> 需要在工程中添加Litjson.dll文件,否则会报错 /// </summary> /// <param name="path"></param> /// <returns></returns> //public static JsonData LoadJson(string path) //{ // TextAsset asset = Resources.Load<TextAsset>(path); // if (!asset) // { // Debug.LogError("加载Json文件 错误,路径是:" + path); // return null; // } // // 将读取到的字符串转换为JsonData 返回去 // return JsonMapper.ToObject(asset.text); //} /// <summary> /// 加载XMl文件 /// </summary> /// <param name="path"></param> /// <returns></returns> 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 概率随机数 /// <summary> /// 指定概率随机数 /// 参数示例[10,20,30] -> 解释为数组索引0.1.2产生概率分别为 17%, 33%,50% /// </summary> /// <param name="rate">几率数组(%)</param> /// <returns></returns> 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资源 /// <summary> /// 加载Sprite /// </summary> /// <param name="path"></param> /// <returns></returns> public static Sprite LoadSprite(string path) { return Resources.Load<Sprite>(path); } /// <summary> /// 已加载图集记录 /// </summary> private static Dictionary<string, SpriteAtlas> m_UISpriteAtlasDic = new Dictionary<string, SpriteAtlas>(); /// <summary> /// 加载指定路径图集中的指定名称图片 /// </summary> /// <param name="_atlasPath"></param> /// <param name="_spriteName"></param> /// <returns></returns> 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; } /// <summary> /// 获取一个图集 /// </summary> /// <param name="atlasName"></param> /// <returns></returns> static SpriteAtlas GetSpriteAtlas(string atlasName) { if (m_UISpriteAtlasDic.ContainsKey(atlasName)) { if (m_UISpriteAtlasDic[atlasName] == null) m_UISpriteAtlasDic[atlasName] = Resources.Load<SpriteAtlas>(atlasName); } else { m_UISpriteAtlasDic.Add(atlasName, Resources.Load<SpriteAtlas>(atlasName)); } return m_UISpriteAtlasDic[atlasName]; } /// <summary> /// 加载材质球 /// </summary> /// <param name="path"></param> /// <returns></returns> public static Material LoadMaterial(string path) { return Resources.Load<Material>(path); } /// <summary> /// 加载贴图 /// </summary> /// <param name="path"></param> /// <returns></returns> public static Texture LoadTexture(string path) { return Resources.Load<Texture>(path); } #endregion }
使用方法:将脚本挂载到,切换场景时不销毁的物体上即可。
using UnityEngine;
/// <summary>
/// 加载时不销毁的对象
/// </summary>
public class DontDestroy : MonoBehaviour
{
private void Awake()
{
DontDestroyOnLoad(gameObject);
}
}
定时炸弹,挂载到不同游戏物体上,通过Inspector面板赋值Delay,经过Delay时间后自动销毁。
using UnityEngine; using System.Collections; /// <summary> /// 自我销毁 /// </summary> 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<Slider>(); // 记得修改要加载的场景名称 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,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<EventTriggerListener>(); if (listener == null) listener = go.AddComponent<EventTriggerListener>(); 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<EventTriggerListener>()); } 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; /// <summary> /// 时间工具类 /// </summary> public static class TimerTools { /// <summary> /// 获取当前的时间戳(秒) /// </summary> /// <returns></returns> public static long GetNowTime() { TimeSpan cha = (DateTime.Now - TimeZone.CurrentTimeZone.ToLocalTime(new DateTime(1970, 1, 1))); long t = (long)cha.TotalSeconds; return t; } /// <summary> /// 获取两个时间戳时间间隔(单位秒) /// </summary> /// <param name="timestapMax">时间戳1(10位)</param> /// <param name="timestapMin">时间戳2(10位)</param> /// <returns></returns> public static int GetSecondInterval(long timestapMax, long timestapMin) { //Debug.Log("时间戳间隔: " + timestapMax + " " + timestapMin); int resultTime = (int)Mathf.Round((float)((timestapMax - timestapMin))); return resultTime; } /// <summary> /// 计时时间转 00:00格式 /// </summary> /// <param name="time">转换时间</param> /// <param name="showHour">显示小时</param> /// <returns></returns> 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; } } /// <summary> /// 两个日期是否是同一天 /// </summary> /// <param name="t1"></param> /// <param name="t2"></param> /// <returns></returns> 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 相互转换 /// <summary> /// DateTime转换为Unix时间戳 /// </summary> /// <param name="dateTime"></param> /// <returns></returns> 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; } /// <summary> /// Unix时间戳转换为 DateTime /// </summary> /// <param name="unixTimeStamp"></param> /// <returns></returns> 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信搜索“开发同学留步”,回复关键字“工具类”即可获得。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。