Unity 通用功能记录贴

本文汇总了Unity开发中常用的功能实现方法,包括日志记录、程序退出监听、UGUI窗口变化监听、坐标旋转、内存清理、鼠标UI识别、模型中心点获取等实用技巧。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

记录下开发中会使用的一些通用api,避免之后每次都去查看过去工程的代码。
1.记录运行日志:

/// <summary>
    /// 保持的日志文件名称
    /// </summary>
    public const string saveLogFileName = "runLog.txt";
    private void Awake()
    {
        Application.logMessageReceived += SaveLog;
    }

    private string tempBeforeLog;
    /// <summary>
    /// 保存日志
    /// </summary>
    /// <param name="condition"></param>
    /// <param name="stackTrace"></param>
    /// <param name="type"></param>
    private void SaveLog(string condition, string stackTrace, LogType type)
    {
        if (condition.Equals(tempBeforeLog))//如果是相同的信息就不再写入
        {
            return;
        }
        string path = GetSaveLogPath();
        using (FileStream fs = new FileStream(path, FileMode.OpenOrCreate, FileAccess.ReadWrite))
        {
            using (StreamWriter sw = new StreamWriter(fs))
            {
                fs.Seek(0, SeekOrigin.End);
                sw.WriteLine(DateTime.Now.ToString("G") + " " + type.ToString() + ":" + condition + "{" + stackTrace + "}");
            }
        }
        tempBeforeLog = condition;
    }

2.监听程序退出和编辑器下的停止运行:

     	Application.wantsToQuit += OnQuitEvent;
     	#if UNITY_EDITOR
        EditorApplication.wantsToQuit += OnQuitEvent;
		#endif
 		//返回false回阻止发布后的程序关闭
 		private bool OnQuitEvent()
 		{
       		 return true;
 		}

3.监听UGUI窗口变化:

 	public void OnRectTransformDimensionsChange()
    {
       Debug.Log("窗口大小发生改变");
    }

4.在Awake之前执行

[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
    static void AwakeBefore()
    {
 		Debug.Log("在Awake之前调用");
    }

5.隐藏标题栏

 	[DllImport("user32.dll")]
    public static extern IntPtr GetForegroundWindow();
    [DllImport("user32.dll")]
    public static extern long GetWindowLong(IntPtr hwd, int nIndex);
    [DllImport("user32.dll")]
    public static extern void SetWindowLong(IntPtr hwd, int nIndex, long dwNewLong);
 	[DllImport("user32")]
    static extern int EnumWindows(EnumWindowsCallBack lpEnumFunc, IntPtr lParam);
    [DllImport("user32")]
    static extern uint GetWindowThreadProcessId(IntPtr hWnd, ref IntPtr lpdwProcessId);
    [DllImport("user32.dll", EntryPoint = "FindWindow")]
    public static extern System.IntPtr FindWindow(System.String className, System.String windowName);
    
    /// <summary>
    /// 窗口风格
    /// </summary>
    const int GWL_STYLE = -16;
    /// <summary>
    /// 标题栏
    /// </summary>
    const int WS_CAPTION = 0x00c00000;
    /// <summary>
    /// 外边框显示隐藏
    /// </summary>
    const uint WS_VISIBLE = 0x10000000;
	 private void Awake()
    {
#if !UNITY_EDITOR && UNITY_STANDALONE_WIN
		HideTitle();
        Screen.SetResolution(defaultWindowWidth,defaultWindowHeight,false);
#endif
    }
 	 private static void HideTitle()
    {
        GetSelfWindows();
        IntPtr window = myWindowHandle;//GetForegroundWindow();
        //GetForegroundWindow是获取的当前焦点程序窗口,在启动的一瞬间如果选中别的窗口,则会出现将选中的窗口标题栏隐藏的问题。
        var wl = GetWindowLong(window, GWL_STYLE);
        wl &= ~WS_CAPTION & WS_VISIBLE;
        SetWindowLong(window, GWL_STYLE, wl);
    }
    private static IntPtr myWindowHandle;
    /// <summary>
    /// 获取程序自身窗口
    /// </summary>
    public static void GetSelfWindows()
    {
        IntPtr handle = (IntPtr)System.Diagnostics.Process.GetCurrentProcess().Id;  //获取进程ID
        EnumWindows(new EnumWindowsCallBack(EnumWindCallback), handle);     //枚举查找本窗口
        //打包时的ProductName
        //myWindowHandle = FindWindow(null, "WindowTitleChange");
    }

隐藏后,会出现UGUI鼠标点击位置识别偏差问题,应该是差了一个标题栏的高度,在awake手动设置一下分辨率即可。

6.坐标旋转

/// <summary>
    /// 围绕某点旋转指定角度
    /// </summary>
    /// <param name="position">自身坐标</param>
    /// <param name="center">旋转中心</param>
    /// <param name="axis">围绕旋转轴</param>
    /// <param name="angle">旋转角度</param>
    /// <returns></returns>
    public static Vector3 RotateRound(Vector3 position, Vector3 center, Vector3 axis, float angle)
    {
        return Quaternion.AngleAxis(angle, axis) * (position - center) + center;
    }

7 清理所有进程内存

[DllImport("psapi.dll")]
    private static extern int EmptyWorkingSet(IntPtr hwProc);
    public static void ClearMemory()
    {
        GC.Collect();
        GC.WaitForPendingFinalizers();
        Process[] processes = Process.GetProcesses();

        foreach (Process process in processes)
        {
            try
            {
                EmptyWorkingSet(process.Handle);
            }
            catch (Exception ex)
            {
                Debug.Log(ex.Message);
            }
        }
    }

8 UGUI识别当前鼠标是否位于UI控件上

 public static bool GetOverUI()
    {
        bool isOver=false;
        EventSystem uiEventSystem = EventSystem.current;
        if (uiEventSystem != null)
        {
            PointerEventData uiPointerEventData = new PointerEventData(uiEventSystem);
            uiPointerEventData.position = Input.mousePosition;

            List<RaycastResult> uiRaycastResultCache = new List<RaycastResult>();

            uiEventSystem.RaycastAll(uiPointerEventData, uiRaycastResultCache);
            if (uiRaycastResultCache.Count > 0)
            {
                Transform obj = uiRaycastResultCache[0].gameObject.transform;
                isOver = obj is RectTransform;
            }
        }

        return isOver;
    }

9 Inspector 面板显示按钮,调用方法

#if UNITY_EDITOR
    [UnityEditor.CustomEditor(typeof(TestClass))]
    public class ViveInputAdapterManagerEditor : UnityEditor.Editor
    {
        public override void OnInspectorGUI()
        {
            base.OnInspectorGUI();
            if (!Application.isPlaying)
            {
                var targetNode = target as TestClass;
                if (targetNode == null)
                {
                    return;
                }
                GUILayout.BeginHorizontal();
                if (GUILayout.Button("自定义按钮"))
                {
                    targetNode.Init();
                }
                GUILayout.EndHorizontal();
            }
        }
    }
#endif

10.获取模型中心点坐标

   public static Vector3 GetModelsCenter(GameObject go)
    {
        Vector3 center = Vector3.zero;
        MeshRenderer mr = go.GetComponent<MeshRenderer>();
        if (mr != null)
        {
            center = mr.bounds.center;
        }
        else
        {
            MeshRenderer[] mrs = go.GetComponentsInChildren<MeshRenderer>();
            for (int i = 0; i < mrs.Length; i++)
            {
                center += mrs[i].bounds.center;
            }
            if (mrs.Length > 0)
            {
                center /= mrs.Length;
            }

        }
        return center;
    }

11.计算相对坐标

	/// <summary>
    /// 获取position相对origin的坐标
    /// </summary>
    /// <param name="origin"></param>
    /// <param name="position"></param>
    /// <returns></returns>
    private Vector3 GetRelativePosition(Vector3 origin, Vector3 position)
    {
        if (origin == Vector3.zero)
        {
            return position;
        }
        Vector3 distance = position - origin;
        Vector3 relativePosition = Vector3.zero;
        relativePosition.x = Vector3.Dot(distance, new Vector3(origin.x, 0, 0).normalized);
        relativePosition.y = Vector3.Dot(distance, new Vector3(0, origin.y, 0).normalized);
        relativePosition.z = Vector3.Dot(distance, new Vector3(0, 0, origin.z).normalized);
        return relativePosition;
    }

12.动态给UI添加事件

 public static void SetUIComponentEvent(GameObject go, EventTriggerType type, UnityAction<BaseEventData> call)
    {
        EventTrigger trigger = go.GetComponent<EventTrigger>();
        if (trigger == null)
        {
            trigger = go.AddComponent<EventTrigger>();
        }
        EventTrigger.Entry entry = new EventTrigger.Entry();
        entry.eventID = type;
        entry.callback.AddListener(call);
        trigger.triggers.Add(entry);
    }

13.解析URL参数

 	/// <summary>
    /// 解析url参数
    /// </summary>
    /// <param name="urlArguments"></param>
    /// <param name="key"></param>
    /// <returns></returns>
    public static string GetURLArguments(string urlArguments, string key,string defaultValue)
    {
        if (!string.IsNullOrEmpty(urlArguments)&&urlArguments.Contains("?"))
        {
            urlArguments = urlArguments.Substring(1, urlArguments.Length - 1);
            string[] argRoot = urlArguments.Split('&');
            if (string.IsNullOrEmpty(key))
            {
                return urlArguments;
            }
            for (int i = 0; i < argRoot.Length; i++)
            {
                string[] arguments = argRoot[i].Split('=');
                if (arguments.Length >= 2)
                {
                    if (arguments[0].Equals(key))
                    {
                        return arguments[1];
                    }
                }
            }

        }
        return defaultValue;
    }

14.获取指定模型顶点

	/// <summary>
    /// 获取指定物体的顶点,如果没有递归查询子物体,返回第一个顶点数大于0的物体顶点
    /// </summary>
    /// <param name="go"></param>
    /// <returns></returns>
    public static List<Vector3> GetModelVertices(GameObject go)
    {
        MeshFilter mf = go.GetComponent<MeshFilter>();
        if (mf != null)
        {
            return new List<Vector3>(mf.mesh.vertices);
        }
        else
        {
            for (int i = 0; i < go.transform.childCount; i++)
            {
                List<Vector3> vertices = GetModelVertices(go.transform.GetChild(i).gameObject);
                if (vertices.Count > 0)
                {
                    return vertices;
                }
            }
        }

        return new List<Vector3>();
    }

15.获取鼠标相对点击UI上的坐标和相对中心点的角度。

	/// <summary>
    /// 获取鼠标点击UI上范围的相对坐标,0~1
    /// </summary>
    /// <param name="eventData"></param>
    /// <returns></returns>
    public static Vector2 GetMouseClickPointByUI(RectTransform rectTf, PointerEventData eventData)
    {
        Vector2 localPoint;
        Vector2 normalizedPoint = Vector2.zero;
        //将屏幕空间的点转换成RectTransform指定的本地空间点
        if (RectTransformUtility.ScreenPointToLocalPointInRectangle(rectTf, eventData.position, eventData.pressEventCamera, out localPoint))
        {
            // localPoint 是相对于轴点的本地坐标,和轴点有关
            //转换成归一化的坐标,范围是0到1,和轴点无关,ugui左下角为(0, 0),右上角为(1, 1)
            normalizedPoint = Rect.PointToNormalized(rectTf.rect, localPoint);

            //Debug.Log("normalizedPoint=" + normalizedPoint.ToString());

            //计算相对中心的角度
            Vector2 formV2 = normalizedPoint - new Vector2(0.5f, 0.5f);
            Vector2 toV2 = new Vector2(0.5f, 0) - new Vector2(0.5f, 0.5f);

            float angle = Vector2.Angle(formV2, toV2);
            if (normalizedPoint.x < 0.5f)
            {
                angle = 360 - angle;
            }
        }

        return normalizedPoint;
    }

16.将传入数据,扩容或压缩到指定个数(最简单方式)

	/// <summary>
    /// 将传入数据,扩容或压缩到指定个数(最简单方式)
    /// </summary>
    /// <param name="inputList"></param>
    /// <param name="targetCount"></param>
    /// <returns></returns>
    public static List<float> ScaleV2List(List<float> inputList, int targetCount)
    {
        List<float> result = new List<float>();
        int unit = 0;
        if (inputList.Count > targetCount)
        {
            unit = Mathf.CeilToInt(inputList.Count / (float)targetCount);
            for (int i = 0; i < inputList.Count; i++)
            {
                if (i % unit == 0)
                {
                    result.Add(inputList[i]);
                }
            }
        }
        else if (inputList.Count < targetCount)
        {
            unit = targetCount / inputList.Count;
            for (int i = 0; i < inputList.Count - 1; i++)
            {
                for (int j = 0; j < unit; j++)
                {
                    float rate = (float)j / unit;
                    float f = Mathf.Lerp(inputList[i], inputList[i + 1], rate);
                    result.Add(f);
                }
            }
        }
        else
        {
            result = inputList;
        }

        int replenishCount = result.Count - targetCount;
        if (replenishCount > 0)
        {
            for (int i = 0; i < replenishCount; i++)
            {
                int tempIndex = Random.Range(0, result.Count);
                result.RemoveAt(tempIndex);
            }
        }
        else if (replenishCount < 0)
        {
            int count = Mathf.Abs(replenishCount);
            for (int i = 0; i < count; i++)
            {
                result.Add(result[result.Count - 1]);
            }
        }
        return result;
    }

17.使用位移和按位与操作来检查指定位

    private bool GetBit(int n, int position)
    {
        // 使用位移和按位与操作来检查指定位
        int result = n & (1 << position);
        //result = 0或非0的数字
        return result != 0;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值