栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 游戏开发 > 其他

Unity小技巧收集总结--自用(二)

其他 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Unity小技巧收集总结--自用(二)

目录

 1、加载场景,显示进度

2、Image渐变色

3、获取物体所有的材质,并且改变这些材质的Shader

4、检查tag列表中是否有tag,没有该tag添加此tag

5、Dotween对数值进行递增或递减

6、鼠标双击

7、获取模型Bound中心点

8、绘制相机视野

9、编辑器扩展,复制物体的Position和Roation

 10、鼠标拖动物体移动

11、逐渐注视目标方向旋转

12、对象池


 1、加载场景,显示进度
using System.Collections;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

public class SceneLoadTool : MonoBehaviour
{
    /// 
    /// 要加载场景的名称
    /// 
    public string SceneName;

    /// 
    /// 加载进度显示界面
    /// 
    public GameObject LoadingPanel;

    /// 
    /// 加载进度条
    /// 
    public Slider LoadSlider;

    /// 
    /// 加载进度文字
    /// 
    public Text txt_LoadProcess;

    /// 
    /// 进度条速度
    /// 
    private float loadSpeed = 1;

    /// 
    /// 进度条最终进度值
    /// 
    private float loadTargetValue = 0;

    public void StartLoadScene()
    {
        LoadSlider.value = 0;
        StartCoroutine(LoadScene(SceneName));
    }

    IEnumerator LoadScene(string sceneName)
    {
        LoadingPanel.SetActive(true);
        AsyncOperation operation = SceneManager.LoadSceneAsync(sceneName);
        operation.allowSceneActivation = false;
        while (!operation.isDone)
        {
            loadTargetValue = operation.progress;
            if (operation.progress >= 0.9f)
            {
                loadTargetValue = 1;
            }

            if (!loadTargetValue.Equals(LoadSlider.value))
            {
                LoadSlider.value = Mathf.Lerp(LoadSlider.value, loadTargetValue,Time.deltaTime * loadSpeed); //插值,让进度条流畅
                if (Mathf.Abs(LoadSlider.value - loadTargetValue) < 0.01f)
                {
                    LoadSlider.value = loadTargetValue;
                }
            }

            txt_LoadProcess.text =(int)(LoadSlider.value * 100) + "%";
            if ((int)(LoadSlider.value * 100) == 100)
            {
                operation.allowSceneActivation = true; //允许异步加载完毕后自动切换场景 
            }

            yield return null;
        }
    }
}

2、Image渐变色
using UnityEngine;
using UnityEngine.UI;

/// 
/// 挂Image组件上
/// 
[AddComponentMenu("UI/Effects/Gradient")]
public class GradientColor : BaseMeshEffect
{
    public Color Color1 = Color.white;
    public Color Color2 = Color.white;

    [Range(-180f, 180f)] public float Angle = -90.0f;

    public override void ModifyMesh(VertexHelper vh)
    {
        if (enabled)
        {
            var rect = graphic.rectTransform.rect;
            var dir = RotationDir(Angle);

            var localPositionMatrix = LocalPositionMatrix(rect, dir);

            var vertex = default(UIVertex);
            for (var i = 0; i < vh.currentVertCount; i++)
            {
                vh.PopulateUIVertex(ref vertex, i);
                var localPosition = localPositionMatrix * vertex.position;
                vertex.color *= Color.Lerp(Color2, Color1, localPosition.y);
                vh.SetUIVertex(vertex, i);
            }
        }
    }

    public struct Matrix2x3
    {
        public float m00, m01, m02, m10, m11, m12;

        public Matrix2x3(float m00, float m01, float m02, float m10, float m11, float m12)
        {
            this.m00 = m00;
            this.m01 = m01;
            this.m02 = m02;
            this.m10 = m10;
            this.m11 = m11;
            this.m12 = m12;
        }

        public static Vector2 operator *(Matrix2x3 m, Vector2 v)
        {
            float x = (m.m00 * v.x) - (m.m01 * v.y) + m.m02;
            float y = (m.m10 * v.x) + (m.m11 * v.y) + m.m12;
            return new Vector2(x, y);
        }
    }

    private Matrix2x3 LocalPositionMatrix(Rect rect, Vector2 dir)
    {
        float cos = dir.x;
        float sin = dir.y;
        Vector2 rectMin = rect.min;
        Vector2 rectSize = rect.size;
        float c = 0.5f;
        float ax = rectMin.x / rectSize.x + c;
        float ay = rectMin.y / rectSize.y + c;
        float m00 = cos / rectSize.x;
        float m01 = sin / rectSize.y;
        float m02 = -(ax * cos - ay * sin - c);
        float m10 = sin / rectSize.x;
        float m11 = cos / rectSize.y;
        float m12 = -(ax * sin + ay * cos - c);
        return new Matrix2x3(m00, m01, m02, m10, m11, m12);
    }

    private Vector2 RotationDir(float angle)
    {
        float angleRad = angle * Mathf.Deg2Rad;
        float cos = Mathf.Cos(angleRad);
        float sin = Mathf.Sin(angleRad);
        return new Vector2(cos, sin);
    }
}

3、获取物体所有的材质,并且改变这些材质的Shader
 #region 获取物体所有的材质,并且改变这些材质的Shader

    private Renderer[] rendArray;
    private List materials = new List();

    /// 
    /// 获取物体上所有的材质,并改变这些材质的Shader
    /// 
    private void GetModelAllMaterialsAndChange(GameObject gameObject, Shader targetShader)
    {
        materials.Clear();
        rendArray = gameObject.transform.GetComponentsInChildren(true);
        for (int i = 0; i < rendArray.Length; i++)
        {
            Material[] mats = rendArray[i].materials;
            for (int j = 0; j < mats.Length; j++)
            {
                materials.Add(mats[j]);
            }
        }

        for (int i = 0; i < materials.Count; i++)
        {
            materials[i].shader = targetShader;
        }
    }

    #endregion

4、检查tag列表中是否有tag,没有该tag添加此tag
    /// 
    /// 检查tag列表中是否有tag,没有该tag添加此tag
    /// 
    /// 所要设设置的tag
    public static void SetGameObjectTag(GameObject gameObject, string tag)
    {
        if (!UnityEditorInternal.InternalEditorUtility.tags.Equals(tag)) //如果tag列表中没有这个tag
        {
            UnityEditorInternal.InternalEditorUtility.AddTag(tag); //在tag列表中添加这个tag
        }

        gameObject.tag = tag;
    }

5、Dotween对数值进行递增或递减
    float startNum = 0f;
    float targetNum = 1f;
    public void DOTweenNum(Action  cb)
    {
        DOTween.To(() => startNum, x => startNum = x, targetNum, 10).
            SetEase(Ease.Linear).OnComplete(() => {
                cb?.Invoke();
            });
    }

    void Update()
    {

        if (Input.GetKeyDown(KeyCode.F8))
        {
            DOTweenNum(()=> { Debug.Log($"******{startNum}*****"); });
        }
    }

6、鼠标双击
using System;
using UnityEngine;

public class DoubleClickMouseButton : MonoBehaviour
{
    /// 
    /// 鼠标双击的间隔
    /// 
    private float doubleClickTime = 0.2f;

    /// 
    /// 上一次点击鼠标抬起的时间
    /// 
    private double lastClickTime;

    void Start()
    {
        lastClickTime = Time.realtimeSinceStartup;
    }

    private void Update()
    {
        DoubleClickMouseButtonEvent(0, () =>
        {
            //ToDo 双击所要执行的事件
        });
    }

    /// 
    /// 鼠标双击执行的事件
    /// 
    /// 鼠标按键
    /// 双击需要执行的事件
    private void DoubleClickMouseButtonEvent(int mouseBtnIndex, Action action)
    {
        if (Input.GetMouseButtonDown(mouseBtnIndex)) //双击鼠标右键聚焦
        {
            if (Time.realtimeSinceStartup - lastClickTime < doubleClickTime)
            {
                action();
            }

            lastClickTime = Time.realtimeSinceStartup;
        }
    }
}

7、获取模型Bound中心点
using UnityEngine;

namespace MT_Exterensions
{
    public static class GameObjectExtensions
    {
        public static Bounds CalculatePreciseBounds(this GameObject gameObject)
        {
            Bounds bounds = new Bounds();
            bool flag = false;
            MeshFilter[] componentsInChildren1 = gameObject.GetComponentsInChildren();
            if (componentsInChildren1.Length != 0)
            {
                bounds = GetMeshBounds(componentsInChildren1[0].gameObject, componentsInChildren1[0].sharedMesh);
                flag = true;
                for (int index = 1; index < componentsInChildren1.Length; ++index)
                    bounds.Encapsulate(GetMeshBounds(componentsInChildren1[index].gameObject,
                        componentsInChildren1[index].sharedMesh));
            }

            SkinnedMeshRenderer[] componentsInChildren2 = gameObject.GetComponentsInChildren();
            if (componentsInChildren2.Length != 0)
            {
                Mesh mesh = new Mesh();
                if (!flag)
                {
                    componentsInChildren2[0].BakeMesh(mesh);
                    bounds = GetMeshBounds(componentsInChildren2[0].gameObject, mesh);
                }

                for (int index = 1; index < componentsInChildren2.Length; ++index)
                {
                    componentsInChildren2[index].BakeMesh(mesh);
                    bounds = GetMeshBounds(componentsInChildren2[index].gameObject, mesh);
                }

                Object.Destroy(mesh);
            }

            return bounds;
        }

        private static Bounds GetMeshBounds(GameObject gameObject, Mesh mesh)
        {
            Bounds bounds = new Bounds();
            Vector3[] vertices = mesh.vertices;
            if (vertices.Length != 0)
            {
                bounds = new Bounds(gameObject.transform.TransformPoint(vertices[0]), Vector3.zero);
                for (int index = 1; index < vertices.Length; ++index)
                    bounds.Encapsulate(gameObject.transform.TransformPoint(vertices[index]));
            }

            return bounds;
        }

        public static Bounds CalculateBounds(this GameObject gameObject, bool localSpace = false)
        {
            Vector3 position = gameObject.transform.position;
            Quaternion rotation = gameObject.transform.rotation;
            Vector3 localScale = gameObject.transform.localScale;
            if (localSpace)
            {
                gameObject.transform.position = Vector3.zero;
                gameObject.transform.rotation = Quaternion.identity;
                gameObject.transform.localScale = Vector3.one;
            }

            Bounds bounds1 = new Bounds();
            Renderer[] componentsInChildren = gameObject.GetComponentsInChildren();
            if (componentsInChildren.Length != 0)
            {
                Bounds bounds2 = componentsInChildren[0].bounds;
                bounds1.center = bounds2.center;
                bounds1.extents = bounds2.extents;
                for (int index = 1; index < componentsInChildren.Length; ++index)
                {
                    Bounds bounds3 = componentsInChildren[index].bounds;
                    bounds1.Encapsulate(bounds3);
                }
            }

            if (localSpace)
            {
                gameObject.transform.position = position;
                gameObject.transform.rotation = rotation;
                gameObject.transform.localScale = localScale;
            }

            return bounds1;
        }

        /// 
        /// 获取模型的Bounds
        /// 
        /// 
        /// 
        public static Bounds CalculateModelBounds(GameObject gameObject)
        {
            Bounds bounds = gameObject.CalculateBounds(false);
            return bounds;
        }
    }
}

8、绘制相机视野
using UnityEngine;

/// 
/// 绘制相机视野范围
/// 
public class ShowCameraFieldOfView : MonoBehaviour
{
    private Camera mainCamera;
    private void OnDrawGizmos()
    {
        if (mainCamera == null)
            mainCamera = Camera.main;
        Gizmos.color = Color.green;
        //设置gizmos的矩阵   
        Gizmos.matrix = Matrix4x4.TRS(mainCamera.transform.position, mainCamera.transform.rotation, Vector3.one);
        Gizmos.DrawFrustum(Vector3.zero, mainCamera.fieldOfView, mainCamera.farClipPlane, mainCamera.nearClipPlane, mainCamera.aspect);
    }
}

9、编辑器扩展,复制物体的Position和Roation
using UnityEditor;
using UnityEngine;

/// 
/// 放在Editor目录下
/// 选中物体之后,在扩展窗口选择复制的选项,就可以将选中的物体的transform信息位置复制下来,然后在要复制的地方Ctrl+V就可以复制出来
/// 
public class CopyObjTransformData : Editor
{
    /// 
    /// 复制Position
    /// 
    [UnityEditor.MenuItem("复制节点Transform信息/复制坐标")]
    static void CopyXYZ()
    {
        GameObject obj = UnityEditor.Selection.activeGameObject;
        if (obj != null)
        {
            string ret = obj.transform.localPosition.x + "f,"
                                                       + obj.transform.localPosition.y + "f,"
                                                       + obj.transform.localPosition.z + "f";
            GUIUtility.systemCopyBuffer = ret;
        }
    }

    /// 
    /// 复制Rotation
    /// 
    [UnityEditor.MenuItem("复制节点Transform信息/复制旋转")]
    static void CopyObjRotation()
    {
        GameObject obj = UnityEditor.Selection.activeGameObject;
        if (obj != null)
        {
            string ret = obj.transform.localEulerAngles.x + "f," + obj.transform.localEulerAngles.y + "f," +
                         obj.transform.localEulerAngles.z + "f";
            GUIUtility.systemCopyBuffer = ret;
        }
    }
}

 10、鼠标拖动物体移动
using System.Collections;
using UnityEngine;

/// 
/// 完成两个步骤:
//  1.由于鼠标的坐标系是2维,需要转换成3维的世界坐标系  
//  2.只有3维坐标情况下才能来计算鼠标位置与物理的距离,offset即是距离
//将鼠标屏幕坐标转为三维坐标,再算出物体位置与鼠标之间的距离
/// 
public class DragObjMove : MonoBehaviour
{
    void Start()
    {
        StartCoroutine(OnMouseDown());
    }

    IEnumerator OnMouseDown()
    {
        //将物体由世界坐标系转换为屏幕坐标系
        Vector3 screenSpace = Camera.main.WorldToScreenPoint(transform.position);//三维物体坐标转屏幕坐标
 
        Vector3 offset = transform.position - Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, screenSpace.z));
        while (Input.GetMouseButton(0))
        {
            //得到现在鼠标的2维坐标系位置
            Vector3 curScreenSpace = new Vector3(Input.mousePosition.x, Input.mousePosition.y, screenSpace.z);
            //将当前鼠标的2维位置转换成3维位置,再加上鼠标的移动量
            Vector3 curPosition = Camera.main.ScreenToWorldPoint(curScreenSpace) + offset;
            //curPosition就是物体应该的移动向量赋给transform的position属性
            transform.position = curPosition;
            yield return new WaitForFixedUpdate(); //这个很重要,循环执行
        }

    }
}

11、逐渐注视目标方向旋转
    /// 
    /// 逐渐注视目标点旋转
    /// 
    /// 变换组件
    /// 目标点
    /// 旋转速度
    public static void LookPostion(Transform targetTF, Vector3 targetPos, float rotateSpeed)
    {
        Vector3 dir = targetPos - targetTF.position;
        LookDirection(targetTF, dir, rotateSpeed);
    }

    /// 
    /// 逐渐注视目标方向旋转
    /// 
    /// 变换组件
    /// 目标方向
    /// 旋转速度
    public static void LookDirection(Transform targetTF, Vector3 targetDir, float rotateSpeed)
    {
        //如果需要注视零方向
        if (targetDir == Vector3.zero) return;
        //transform.LookAt(目标点);      一帧旋转到位
        Quaternion dir = Quaternion.LookRotation(targetDir);
        targetTF.rotation = Quaternion.Lerp(targetTF.rotation, dir, Time.deltaTime * rotateSpeed);
    }

12、对象池
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System;
 
/// 
/// 对象池
/// 
public class GameObjectPool : MonoSingleton
{ 
    //1.对象池
    private Dictionary> cache;
    //private Dictionary> obj = new Dictionary>();
    //初始化:在对象创建时执行一次
    protected override void Init()
    {
        base.Init();
        cache = new Dictionary>();
    }
 
    //2.创建对象
    /// 
    /// 通过对象池创建对象
    /// 
    /// 需要创建的对象种类
    /// 需要创建的预制件
    /// 创建的位置
    /// 创建的旋转
    /// 
    public GameObject CreateObject(string key, GameObject prefab, Vector3 pos, Quaternion dir)
    {   
        //在池中查找 
        GameObject tempGo = FindUsableObject(key);
        //如果没有找到
        if (tempGo == null)
        {
            //创建物体 
            tempGo = Instantiate(prefab);
            //加入池中
            Add(key, tempGo);
            //将通过对象池创建的物体,存入对象池子物体列表中。
            tempGo.transform.SetParent(transform);
        }
        //使用
        UseObject(tempGo, pos, dir);
        return tempGo;
    }
 
    private void UseObject(GameObject go,Vector3 pos, Quaternion dir)
    {  
        //先设置位置
        go.transform.position = pos;
        go.transform.rotation = dir;
        //再启用物体
        go.SetActive(true);  
        //重置通过对象池创建物体的所有脚本对象
        foreach (var item in go.GetComponentsInChildren())
        {
            item.OnReset();
        }
    }
 
    private void Add(string key, GameObject tempGo)
    {
        //如果池中没有键  则 添加键
        if (!cache.ContainsKey(key)) cache.Add(key, new List());
        //将物体加入池中
        cache[key].Add(tempGo);
    }
 
    private GameObject FindUsableObject(string key)
    {
        if (cache.ContainsKey(key))
        {
            //  public delegate bool Predicate(T obj);
            //查找池中禁用的物体
            return cache[key].Find(o => !o.activeInHierarchy);
        }
        return null;
    }
 
    //3.即时回收
    public void CollectObject(GameObject go)
    {
        go.SetActive(false);
    }
 
    //4.延迟回收
    public void CollectObject(GameObject go, float delay)
    {
        StartCoroutine(DelayCollect(go, delay));
    }
 
    private IEnumerator DelayCollect(GameObject go, float delay)
    {
        yield return new WaitForSeconds(delay);
        CollectObject(go);
    }
 
    //5.清空
    public void ClearAll()
    { 
        //将字典中所有键存入集合
        List listKey =new List(cache.Keys);
        foreach (var item in listKey)
        {
            //遍历集合元素 删除字典记录
            Clear(item);
        }
    }
 
    public void Clear(string key)
    { 
        //倒序删除
        for (int i = cache[key].Count -1; i>=0 ; i--)
        {
            Destroy(cache[key][i]);
        }
 
        //在字典集合中清空当前记录(集合列表)
        cache.Remove(key);
    }
}
13、将角度限制在360
private float Clamp0360(float eulerAngles)
{
float result=eulerAngles-Mathf.CeilToInt(eulerAngles/360f)*360f;
if        (result<0)
{
result+=360f;
}
return result;
}
 14、获取动画状态机animator的动画clip的播放持续时长
    /// 
    /// 获取动画状态机animator的动画clip的播放持续时长
    /// 
    /// 
    /// 
    /// 
    public float GetClipLength(Animator animator, string clipName)
    {
        if (null == animator || string.IsNullOrEmpty(clipName) || null == animator.runtimeAnimatorController)
            return 0;
        // 获取所有的clips	
        var clips = animator.runtimeAnimatorController.animationClips;
        if (null == clips || clips.Length <= 0) return 0;
        AnimationClip clip;
        for (int i = 0, len = clips.Length; i < len; ++i)
        {
            clip = clips[i];
            if (null != clip && clip.name == clipName)
                return clip.length;
        }
        return 0f;
    }

 

end

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/901694.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号