Unity通用帮助类(干货大集合)

文章目录


先是通用的Helper类,用于处理一些各种游戏都通用的功能。配合通用的GameManager,实现游戏内部逻辑功能。

Helper

/* 
 *  Author : Jk_Chen
 */

using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Runtime.Serialization.Formatters.Binary;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

/// <summary>
/// 通用帮助类
/// </summary>
public class Helper
{
    // ———————————————————— 纯C#

    /// <summary>
    /// 随机打乱List
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="L"></param>
    public static void RandomShuffle<T>(List<T> L)
    {
        System.Random rd = new System.Random();
        for (int i = 0; i < L.Count; i++)
        {
            int j = rd.Next(0, L.Count - 1);
            T tmp = L[i];
            L[i] = L[j];
            L[j] = tmp;
        }
    }

    /// <summary>
    /// 获取当前时间的字符串
    /// </summary>
    /// <returns></returns>
    public static string NowTime()
    {
        int hour = System.DateTime.Now.Hour;
        int minute = System.DateTime.Now.Minute;
        int second = System.DateTime.Now.Second;
        int year = System.DateTime.Now.Year;
        int month = System.DateTime.Now.Month;
        int day = System.DateTime.Now.Day;
        return string.Format("{0}/{1:D2}/{2:D2} {3:D2}:{4:D2}:{5:D2}", year, month, day, hour, minute, second);
    }

    /// <summary>
    /// 通过类名创建一个实例
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="name"></param>
    /// <returns></returns>
    public static T CreateObjectInstanceByClassName<T>(string name)
    {
        Assembly assembly = Assembly.GetExecutingAssembly();
        object o = assembly.CreateInstance(name);
        return (T)o;
    }

    /// <summary>
    /// 浅拷贝
    /// </summary>
    /// <param name="origin"></param>
    /// <param name="target"></param>
    public static void CopyValue(object origin, object target)
    {
        System.Reflection.PropertyInfo[] properties = (target.GetType()).GetProperties();
        System.Reflection.FieldInfo[] fields = (origin.GetType()).GetFields();
        for (int i = 0; i < fields.Length; i++)
        {
            for (int j = 0; j < properties.Length; j++)
            {
                if (fields[i].Name == properties[j].Name && properties[j].CanWrite)
                {
                    properties[j].SetValue(target, fields[i].GetValue(origin), null);
                }
            }
        }
    }

    /// <summary>
    /// 深拷贝
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="obj"></param>
    /// <returns></returns>
    public static T DeepCopy<T>(T obj)
    {
        object retval;
        using (MemoryStream ms = new MemoryStream())
        {
            BinaryFormatter bf = new BinaryFormatter();
            //序列化成流
            bf.Serialize(ms, obj);
            ms.Seek(0, SeekOrigin.Begin);
            //反序列化成对象
            retval = bf.Deserialize(ms);
            ms.Close();
        }
        return (T)retval;
    }

    /// <summary>
    /// 弧度转角度
    /// </summary>
    /// <param name="angle"></param>
    /// <returns></returns>
    public static float GetAngle(float angle)
    {
        return angle / Mathf.PI * 180;
    }


    // ———————————————————— Unity系统
    
    /// <summary>
    /// 退出游戏
    /// </summary>
    void _Quit()
    {
#if UNITY_EDITOR
        UnityEditor.EditorApplication.isPlaying = false;
#else
        Application.Quit();
#endif
    }
    
    /// <summary>
    /// 获取流文件夹路径
    /// </summary>
    /// <param name="path"></param>
    /// <returns></returns>
    public static string GetStreamingAssetsPath(string path)
    {
        string streamingAssetsPath =
#if UNITY_ANDROID && !UNITY_EDITOR
		Application.streamingAssetsPath; //安卓的Application.streamingAssetsPath已默认有"file://"
#elif UNITY_IOS && !UNITY_EDITOR
		"file://" + Application.streamingAssetsPath;
#elif UNITY_STANDLONE_WIN || UNITY_EDITOR
        "file://" + Application.streamingAssetsPath;
#else
		string.Empty;
#endif
        streamingAssetsPath = System.IO.Path.Combine(streamingAssetsPath, path);
        return streamingAssetsPath;
    }

    /// <summary>
    /// 每隔second秒时间执行1次(大致意思、不精确):返回true
    /// 需要精确的需要用协程
    /// </summary>
    /// <param name="second"></param>
    /// <returns></returns>
    public static bool DealInterval(float second)
    {
        int frame = Mathf.RoundToInt(Application.targetFrameRate * second);
        if (frame < 1) frame = 1;
        return Time.frameCount % frame == 0;
    }

    /// <summary>
    /// 获取持久化文件夹路径
    /// </summary>
    /// <param name="path"></param>
    /// <returns></returns>
    public static string GetPersistentDataPath(string path)
    {
        return System.IO.Path.Combine(Application.persistentDataPath, path);
    }

    /// <summary>
    /// 随机颜色
    /// </summary>
    /// <returns></returns>
    public static Color RandomColor()
    {
        float red = UnityEngine.Random.Range(0.0f, 1.0f);
        float green = UnityEngine.Random.Range(0.0f, 1.0f);
        float blue = UnityEngine.Random.Range(0.0f, 1.0f);

        return new Color(red, green, blue);
    }

    /// <summary>
    /// 随机方向向量
    /// </summary>
    /// <returns></returns>
    public static Vector2 RandomDirection()
    {
        float x = Random.Range(-1f, 1f);
        float y = Mathf.Sqrt(1 - x * x);
        if (Random.Range(0f, 1f) > 0.5f)
        {
            y *= -1;
        }
        return new Vector2(x, y);
    }

    /// <summary>
    /// 判断Animator是否结束
    /// </summary>
    /// <param name="animator"></param>
    /// <returns></returns>
    public static bool JudgeAnimatorIsOver(Animator animator)
    {
        AnimatorStateInfo info = animator.GetCurrentAnimatorStateInfo(0);
        if (info.normalizedTime >= 1.0f) return true;
        else return false;
    }

    /// <summary>
    /// PlayerPrefs设置参数
    /// </summary>
    /// <param name="key"></param>
    /// <param name="value"></param>
    public static void SetInt(string key, int value)
    {
        if (!PlayerPrefs.HasKey(key))
        {
            PlayerPrefs.SetInt(key, value);
        }
    }
    public static void SetFloat(string key, float value)
    {
        if (!PlayerPrefs.HasKey(key))
        {
            PlayerPrefs.SetFloat(key, value);
        }
    }
    public static void SetString(string key, string value)
    {
        if (!PlayerPrefs.HasKey(key))
        {
            PlayerPrefs.SetString(key, value);
        }
    }

    /// <summary>
    /// 返回多边形碰撞器的外接矩形的大小
    /// </summary>
    /// <param name="pc"></param>
    /// <returns></returns>
    public static Vector2 GetSizeOfPolygon(PolygonCollider2D pc)
    {
        float mxy = -1e9f, mxx = -1e9f, miy = 1e9f, mix = 1e9f;
        foreach (var p in pc.points)
        {
            if (mxy < p.y) { mxy = p.y; }
            if (mxx < p.x) { mxx = p.x; }
            if (miy > p.y) { miy = p.y; }
            if (mix > p.x) { mix = p.x; }
        }
        return new Vector2(mxx - mix, mxy - miy);
    }

    // ———————————————————— Unity协程相关

    /// <summary>
    /// 存已经加载的资源
    /// </summary>
    public static Dictionary<string, Object> LoadedResources = new Dictionary<string, Object>();
    /// <summary>
    /// 读取资源
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="path"></param>
    /// <returns></returns>
    public static T GetResource<T>(string path) where T : Object
    {
        if (LoadedResources.ContainsKey(path))
        {
            return (T)LoadedResources[path];
        }
        else
        {
            T rs = Resources.Load<T>(path);
            LoadedResources[path] = rs;
            return rs;
        }
    }

    /// <summary>
    /// 开始协程
    /// </summary>
    /// <param name="action"></param>
    public static void _StartCoroutine(IEnumerator action)
    {
        ObjectLibrary.gameManager.StartCoroutine(action);
    }

    /// <summary>
    /// 延时启动
    /// </summary>
    /// <param name="action">函数</param>
    /// <param name="second">延时秒数</param>
    /// <param name="affectedByTimeScale">是否需要受函数影响</param>
    /// <returns></returns>
    public static void Timer(System.Action action, float second, bool affectedByTimeScale = true)
    {
        _StartCoroutine(Timer_(action, second, affectedByTimeScale));
    }
    public static IEnumerator Timer_(System.Action action, float second, bool affectedByTimeScale = true)
    {
        if (affectedByTimeScale)
        {
            yield return new WaitForSeconds(second);
        }
        else
        {
            yield return new WaitForSecondsRealtime(second);
        }
        action();
        yield break;
    }

    /// <summary>
    /// 存已经读入的包文件
    /// </summary>
    public static Dictionary<string, AssetBundle> asset = new Dictionary<string, AssetBundle>();
    /// <summary>
    /// 存已经加载的Prefab
    /// </summary>
    public static Dictionary<string, GameObject> Asset_Prefab = new Dictionary<string, GameObject>();
    /// <summary>
    /// 载入AssetBundle
    /// </summary>
    /// <param name="package">包名(后缀)</param>
    /// <param name="name">资源名数组</param>
    public static void LoadAssetBundle_Memory_Perfabs(string package, string name)
    {
        _StartCoroutine(LoadAssetBundle_Memory_Perfabs_(package, name, () => { }));
    }
    public static void LoadAssetBundle_Memory_Perfabs(string package, string name, System.Action callback)
    {
        _StartCoroutine(LoadAssetBundle_Memory_Perfabs_(package, name, callback));
    }
    static IEnumerator LoadAssetBundle_Memory_Perfabs_(string package, string name, System.Action callback)
    {
        string path = Path.Combine(GameConfig.AssetBundlePath, package);
        //byte[] bytes = File.ReadAllBytes(path);
        //AssetBundle asset = AssetBundle.LoadFromMemory(bytes);
        string pname = package + "." + name;
        if (!Asset_Prefab.ContainsKey(pname))
        {
            if (!asset.ContainsKey(package))
            {
                asset[package] = AssetBundle.LoadFromFile(path);
            }
            Asset_Prefab[pname] = asset[package].LoadAsset(name) as GameObject;
            if (Asset_Prefab[pname] != null)
            {
                Debug.Log("Loaded " + pname);
            }
            else
            {
                Debug.Log("想要加载的资源不存在:" + pname);
            }
        }
        callback();
        yield break;
    }

    /// <summary>
    /// 准备载入的场景
    /// </summary>
    static string sceneToLoad;
    /// <summary>
    /// 场景载入进度
    /// </summary>
    static float LoadingProcessValue;
    /// <summary>
    /// 载入场景(先跳转至Loading界面)
    /// </summary>
    /// <param name="scene"></param>
    public static void LoadScene(string scene)
    {
        sceneToLoad = scene;
        SceneManager.LoadScene("Loading");
        _StartCoroutine(LoadingScene_());
    }
    /// <summary>
    /// 载入场景协程
    /// </summary>
    /// <returns></returns>
    static IEnumerator LoadingScene_()
    {
        LoadingProcessValue = 0;
        float maxSpeed = 0.03f;
        AsyncOperation op = SceneManager.LoadSceneAsync(sceneToLoad);

        // 禁止载入后自己切换
        op.allowSceneActivation = false;
        // isDone后再加载最后的10%
        while (op.progress < 0.9f)
        {
            // 连续加载
            while (LoadingProcessValue < op.progress)
            {
                LoadingProcessValue += maxSpeed;
                yield return new WaitForEndOfFrame();
            }
        }
        while (LoadingProcessValue < 1)
        {
            LoadingProcessValue += maxSpeed;
            yield return new WaitForEndOfFrame();
        }
        op.allowSceneActivation = true;
    }

    // ———————————————————— Unity游戏坐标、对象


    /// <summary>
    /// 调整GameObject obj的不透明度为a
    /// </summary>
    /// <param name="obj"></param>
    /// <param name="a"></param>
    public static void SetOpaquenessOfGameObject(GameObject obj, float a)
    {
        Color c = obj.GetComponent<SpriteRenderer>().material.color;
        c.a = a;
        obj.GetComponent<SpriteRenderer>().material.color = c;
    }

    /// <summary>
    /// 实例化UI对象
    /// 注意实例化后接上的代码在Awake和Start之间(Awake后Start前)
    /// </summary>
    /// <param name="gameObject">预置物</param>
    /// <param name="parent">父亲的transform</param>
    /// <param name="position">位置</param>
    /// <param name="name">对象名称</param>
    /// <returns>生成的对象</returns>
    public static GameObject InstantiateUIObject(GameObject gameObject, Transform parent, Vector2 position, string name)
    {
        GameObject obj = Object.Instantiate(gameObject, new Vector2(0, 0), Quaternion.identity);
        obj.transform.SetParent(parent);
        obj.GetComponent<RectTransform>().anchoredPosition = position;
        obj.GetComponent<RectTransform>().transform.localScale = Vector2.one;
        obj.name = name;
        return obj;
    }

    /// <summary>
    /// 获取以center为中心radius范围内的所有标签为tag的对象
    /// </summary>
    /// <param name="center"></param>
    /// <param name="radius"></param>
    /// <param name="tag"></param>
    /// <returns></returns>
    public static GameObject[] GetAllObjectsInRangeByTag(Vector2 center, float radius, string tag)
    {
        Collider2D[] objs = Physics2D.OverlapCircleAll(center, radius);
        List<GameObject> res = new List<GameObject>();
        for (int i = 0; i < objs.Length; i++)
        {
            if (objs[i].gameObject.tag == tag)
            {
                res.Add(objs[i].gameObject);
            }
        }
        return res.ToArray();
    }

    /// <summary>
    /// 检测canvas内鼠标停留位置的UI对象
    /// </summary>
    /// <param name="canvas"></param>
    /// <returns></returns>
    public static GameObject MouseUIObject(GameObject canvas)
    {
        if (canvas.GetComponent<GraphicRaycaster>() == null) return null;
        PointerEventData pointerEventData = new PointerEventData(EventSystem.current);
        pointerEventData.position = Input.mousePosition;
        GraphicRaycaster gr = canvas.GetComponent<GraphicRaycaster>();
        List<RaycastResult> results = new List<RaycastResult>();
        gr.Raycast(pointerEventData, results);
        if (results.Count != 0)
        {
            return results[0].gameObject;
        }
        return null;
    }

    /// <summary>
    /// 获取3D鼠标下的游戏对象
    /// </summary>
    /// <returns></returns>
    public static GameObject MouseGameObject()
    {
        GameObject res = null;
        Ray rays = Camera.main.ScreenPointToRay(Input.mousePosition);
        //Debug.DrawRay(rays.origin, rays.direction * 100, Color.yellow);
        RaycastHit hit;
        if (Physics.Raycast(rays, out hit)) { res = hit.transform.gameObject; }
        return res;
    }

    /// <summary>
    /// 获取鼠标下的3D游戏对象,若鼠标落在UI对象上返回null
    /// </summary>
    /// <returns></returns>
    public static GameObject MouseGameObjectUp(GameObject canvas)
    {
        GameObject ui = MouseUIObject(canvas);
        if (ui != null) return null;
        return MouseGameObject();
    }

    /// <summary>
    /// 获取鼠标下的2D游戏对象
    /// </summary>
    /// <returns></returns>
    public static GameObject MouseGameObject2D(int layer = ~0)
    {
        float len = 0.001f;
        GameObject res = null;
        //Ray2D rays = new Ray2D(MousePosInWorld(), Vector2.up);
        //Debug.DrawRay(rays.origin, rays.direction, Color.yellow);
        RaycastHit2D hit;
        hit = Physics2D.Raycast(MousePosInWorld(), Vector2.up, len, layer);
        if (hit.collider != null)
        {
            res = hit.transform.gameObject;
        }
        return res;
    }

    /// <summary>
    /// 获取鼠标下的2D游戏对象,若鼠标落在UI对象上返回null
    /// </summary>
    /// <returns></returns>
    public static GameObject MouseGameObjectUp2D(GameObject canvas, int layer = ~0)
    {
        GameObject ui = MouseUIObject(canvas);
        if (ui != null) return null;
        return MouseGameObject2D(layer);
    }

    /// <summary>
    /// 检测是否可以感知(2维空间的两个对象是否直线连接无障碍) 需要2维Collider
    /// </summary>
    /// <param name="a"></param>
    /// <param name="b"></param>
    /// <param name="maxDis"></param>
    /// <param name="layer"></param>
    /// <returns></returns>
    public static bool PerceiveObject(Vector2 a, GameObject b, float maxDis, int layer = ~0)
    {
        Ray2D ray = new Ray2D(a, ((Vector2)b.transform.position - a).normalized);
        //Debug.DrawRay(ray.origin, ray.direction * 100, Color.yellow);
        RaycastHit2D hit = Physics2D.Raycast(ray.origin, ray.direction, maxDis, layer);
        if (hit == false)
        {
            return false;
        }
        //Debug.Log(hit.collider.gameObject);
        return hit.collider.gameObject == b;
    }

    /// <summary>
    /// 判断鼠标下是否存在UI对象或者游戏物体
    /// </summary>
    /// <param name="canvas"></param>
    /// <returns></returns>
    public static bool MouseEmpty(GameObject canvas)
    {
        return MouseGameObject2D() == null && MouseUIObject(canvas) == null;
    }

    /// <summary>
    /// 获取鼠标在当前canvas上的位置
    /// 相对于canvas中心,可与UI的RectTransform.anchoredPosition联动
    /// </summary>
    /// <param name="canvas"></param>
    /// <returns></returns>
    public static Vector2 MousePosInCanvas(GameObject canvas)
    {
        Vector2 uisize = canvas.GetComponent<RectTransform>().sizeDelta;//得到画布的尺寸
        Vector2 screenpos = Input.mousePosition;
        Vector2 screenpos2;
        screenpos2.x = screenpos.x - (Screen.width / 2);//转换为以屏幕中心为原点的屏幕坐标
        screenpos2.y = screenpos.y - (Screen.height / 2);
        Vector2 uipos;//UI坐标
        uipos.x = screenpos2.x * (uisize.x / Screen.width);//转换后的屏幕坐标*画布与屏幕宽高比
        uipos.y = screenpos2.y * (uisize.y / Screen.height);
        return uipos;
    }

    /// <summary>
    /// 鼠标的世界坐标
    /// </summary>
    /// <returns></returns>
    public static Vector2 MousePosInWorld()
    {
        return Camera.main.ScreenToWorldPoint(Input.mousePosition);
    }

    /// <summary>
    /// 返回WorldPos的屏幕坐标
    /// 用于Anchor在屏幕中心的RectTransform.anchoredPosition
    /// </summary>
    /// <param name="WorldPos"></param>
    /// <returns></returns>
    public static Vector2 WorldToRectPosition(Vector2 WorldPos)
    {
        Vector3 screenPos = Camera.main.WorldToScreenPoint(WorldPos);

        Vector2 uiPos = Vector2.zero;
        RectTransformUtility.ScreenPointToLocalPointInRectangle(ObjectLibrary.gameUI.transform as RectTransform, screenPos, null, out uiPos);
        return uiPos;
    }
}


GameManager

/* 
 *  Author : Jk_Chen
 */

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

/// <summary>
/// 通用游戏管理类
/// </summary>
public class GameManager : MonoBehaviour
{
    private void Awake()
    {
        Application.targetFrameRate = GameConfig.fps;
        ObjectLibrary.gameManager = this;
        ObjectLibrary.game = transform.Find("Game").gameObject;
        ObjectLibrary.gameUI = transform.Find("UI").gameObject;
        ObjectLibrary.player = transform.Find("Game/Player").gameObject;
        ObjectLibrary.item = transform.Find("Game/Item").gameObject;
        ObjectLibrary.enemy = transform.Find("Game/Enemy").gameObject;
    }
    void Start()
    {
        Init_Audio();
    }

    void Update()
    {
        if (Helper.DealInterval(.2f))
        {
            UpdateObjUnderMouse();
        }
    }

    // ————————————————————内容管理

    /// <summary>
    /// 鼠标下的对象
    /// </summary>
    public GameObject GameObj, UIObj;
    void UpdateObjUnderMouse()
    {
        GameObj = Helper.MouseGameObjectUp2D(ObjectLibrary.gameUI, 1 << LayerMask.NameToLayer("ObjImage"));
        if (GameObj != null)
        {
            if (GameObj.GetComponent<Rigidbody2D>() == null)
            {
                if(GameObj.GetComponent<SpriteRenderer>() != null)
                {
                    GameObj = GameObj.transform.parent.gameObject;
                }
                else
                {
                    throw new System.Exception("检测到除Image以及Obj以外的其它对象");
                }
            }
        }
        UIObj = Helper.MouseUIObject(ObjectLibrary.gameUI);
    }

    // ————————————————————音乐管理

    AudioSource audioSource = null;
    AudioSource audioOneShot = null;
    void Init_Audio()
    {
        audioSource = transform.Find("AudioSource").GetComponent<AudioSource>();
        audioOneShot = transform.Find("AudioOneShot").GetComponent<AudioSource>();
        audioSource.loop = true;
        SetAudioVolume(0.5f);
        PlayAudio(Helper.GetResource<AudioClip>("Audio/Music/Rainbow"));
    }

    /// <summary>
    /// 播放音效
    /// </summary>
    /// <param name="audioClip"></param>
    public void PlayAudioOneShot(AudioClip audioClip)
    {
        audioOneShot.PlayOneShot(audioClip);
    }
    /// <summary>
    /// 播放背景音乐
    /// </summary>
    /// <param name="audioClip"></param>
    public void PlayAudio(AudioClip audioClip)
    {
        audioSource.clip = audioClip;
        audioSource.Play();
    }
    // 设置音量
    public void SetAudioVolume(float volume)
    {
        audioSource.volume = volume;
        audioOneShot.volume = volume;
    }
    // 设置静音
    public void SetAudioMute(bool ifMute)
    {
        audioSource.mute = ifMute;
        audioOneShot.mute = ifMute;
    }

    // ————————————————————进程管理

    /// <summary>
    /// 时间流速设置(0,1)
    /// </summary>
    /// <param name="scale"></param>
    public void TimeManager(float scale)
    {
        Time.timeScale = scale;

        if (scale == 0)
        {
            if (audioSource.isPlaying)
                audioSource.Pause();
        }
        else
        {
            if (!audioSource.isPlaying)
                audioSource.UnPause();
        }
    }
}



评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值