Bootstrap

Unity常用静态方法

using System;
using System.Collections;
using System.Collections.Generic;
using System.Net.NetworkInformation;
using UnityEngine;
using UnityEngine.AI;
using UnityEngine.EventSystems;
using System.Reflection;
using System.Linq;

public class Ywa_StaticFuns
{

    /// <summary>
    /// list转化为字符串
    /// </summary>
    public static string ListToSting<T>(List<T> list,string arg="")
    {
        var listStr = "";
        if (list == null)
        {
            listStr = null;
        } else
        {
            for (int i = 0; i < list.Count; i++)
            {
                listStr += list[i].ToString();
                if (i + 1 < list.Count)
                {
                    listStr += arg;
                }
            } 
        }
        

        return listStr;
    }

//添加添加子物体,位置,旋转复位
    public static GameObject AddChild(GameObject parent, GameObject prefab)
    {
        GameObject go = GameObject.Instantiate(prefab) as GameObject;
        if (go != null && parent != null)
        {
            Transform t = go.transform;
            t.parent = parent.transform;
            t.localPosition = Vector3.zero;
            t.localRotation = Quaternion.identity;
            t.localScale = Vector3.one;
            go.layer = parent.layer;
        }
        return go;
    }

    // 获取所有子物体组件
    public static List<T> GetInner<T>(GameObject obj)
    {
        Transform selfTran = obj.transform;
        List<T> m_List = new List<T>();
        for (int i = 0; i < selfTran.childCount; i++)
        {
            Transform tran = selfTran.GetChild(i);
            T t = tran.GetComponent<T>();
            if (t != null)
            {
                m_List.Add(t);
            }
        }
        return m_List;
    }

    public static List<GameObject> FindAllChilds(GameObject obj)
    {
        List<GameObject> m_List = new List<GameObject>();
        for (int i = 0; i < obj.transform.childCount; i++)
        {
            if (obj.transform.GetChild(i).childCount > 0)
            {
                FindAllChilds(obj.transform.GetChild(i).gameObject);
            }
            GameObject m_Obj = obj.transform.GetChild(i).gameObject;
            m_List.Add(m_Obj);

        }
        return m_List;
   
}

    //设置gameobject父物体
    public static void SetParent(GameObject parent, GameObject childobj)
    {
        if (childobj != null && parent != null)
        {
            Transform t = childobj.transform;
            t.parent = parent.transform;
            t.localPosition = Vector3.zero;
            t.localRotation = Quaternion.identity;
        }
    }

//获取多平台streamasset目录
    public static string GetStreamAssetPath() => Application.streamingAssetsPath;

    //处理表格负号用#代替的问题
    public static float ReverseNum(string sNum)
    {
        if (sNum.Contains("#"))
        {
            sNum = sNum.Replace("#", "");
            return -float.Parse(sNum);
        } else
        {
            return float.Parse(sNum);
        }
    }

public static T FindInChild<T>(GameObject parent, string findname, bool containDeactiveobj = true) where T : Component
    {
        if (string.IsNullOrEmpty(findname)) { return default(T); }

        string[] nameArr = findname.Split('/');
        for (int i = 0; parent != null && i < nameArr.Length; i++)
        {
             if (i == nameArr.Length - 1)
            {
                T[] arr = parent.GetComponentsInChildren<T>(containDeactiveobj);
                foreach (T t in arr)
                {
                    if (t.name.Equals(nameArr[i])) { return t; }
                }
            }
            else
            {
                parent = FindInChild(parent, nameArr[i], containDeactiveobj);
            }
        }

        return default(T);
    }

//根据名字查找子物体
    public static GameObject FindInChild(GameObject parent, string findname, bool containDeactiveobj = true) => FindInChild<Transform>(parent, findname, containDeactiveobj)?.gameObject;

//根据名字查找所有子物体
    public static GameObject[] FindAllInChild(GameObject parent, string findname, bool containDeactiveobj)
    {
        if (null == parent)
            return null;
 List<GameObject> result = new List<GameObject>();
        Transform[] trs = parent.GetComponentsInChildren<Transform>(containDeactiveobj);
        int len = trs.Length;
        for (int i = 0; i < len; ++i)
        {
            GameObject Tar = trs[i].gameObject;
            if (findname == Tar.name)
            {
                result.Add(Tar);
            }
        }
        return result.ToArray();
    }

 //根据Navmesh获取坐标信息
    public static Vector3 GetRandomPos(Vector3 vOriginePos, float range)
    {
        Vector3 tPos = new Vector3(vOriginePos.x + (UnityEngine.Random.Range(-1.0f, 1.0f) * range), vOriginePos.y, vOriginePos.z + (UnityEngine.Random.Range(-1.0f, 1.0f) * range));
NavMeshPath path = new NavMeshPath();
        NavMesh.CalculatePath(vOriginePos, tPos, -1, path);
        if (path.corners.Length > 0)
        {
            tPos = path.corners[path.corners.Length - 1];
            return tPos;
        }else
        {
            NavMeshHit hit;
            if (NavMesh.Raycast(vOriginePos, tPos, out hit, -1))
            {
                if (NavMesh.CalculatePath(vOriginePos, hit.position, -1, path))
                {
                    tPos = path.corners[path.corners.Length - 1];
                    return tPos;
                }
            }
            NavMeshHit Nvhit;
            if (NavMesh.FindClosestEdge(vOriginePos, out Nvhit, -1))
            {
                tPos = Nvhit.position;
                return tPos;
            }

 else
            {
                if (NavMesh.SamplePosition(vOriginePos, out Nvhit, range, -1))
                {
                    tPos = Nvhit.position;
                    return tPos;
                }
            }


        }

        return vOriginePos;
    }

//修正正朝向
    private static Vector3 vForwad;
    public static void FixForward(GameObject obj)
    {
        if (null != obj)
        {
            vForwad = obj.transform.eulerAngles;
            vForwad.x = 0;
            obj.transform.eulerAngles = vForwad;
        }
    }

//点投影到平面
    public static Vector3 ProjectPointOnPlane(Vector3 planeNormal, Vector3 planePoint, Vector3 point)
    {
        float distance = Vector3.Dot(planeNormal, (point - planePoint));
        distance = -distance;
        Vector3 translationVector = planeNormal * distance;
        return point + translationVector;
    }

//模型渲染器控制
    public static void SetMeshRenderVisible(GameObject parent, bool visible)
    {
        MeshRenderer[] rrs = parent.GetComponentsInChildren<MeshRenderer>(true);
        for (int i = 0; i < rrs.Length; i++)
        {
            rrs[i].enabled = visible;
        }
        SkinnedMeshRenderer[] srs = parent.GetComponentsInChildren<SkinnedMeshRenderer>(true);
        for (int i = 0; i < srs.Length; i++)
        {
            srs[i].enabled = visible;
        }
    }

    //设置物理碰撞器状态
    public static void SetColliderVisible(GameObject parent, bool visible)
    {
        Collider[] rrs = parent.GetComponentsInChildren<Collider>(true);
        for (int i = 0; i < rrs.Length; i++)
        {
            rrs[i].enabled = visible;
        }
    }

    //TODO
    public static IEnumerator CorsValue(float time,float starValue,float endValue)
    {
        float start = Time.realtimeSinceStartup;
        while (Time.realtimeSinceStartup < start + time)
        {
            yield return null;
        }
    }

    //等待秒数
    public static IEnumerator WaitForRealSeconds(float time,Action action)
    {
        float start = Time.realtimeSinceStartup;
        while (Time.realtimeSinceStartup < start + time)
        {
            yield return null;
        }
        action?.Invoke();
    }

    //等待秒数
    public static Coroutine WaitForSeconds(float time,Action action)
    {
      return  MonoBehaviourHelper.StartCoroutine(WaitForRealSeconds(time,action));
    }
//通过名字在父物体中查找object
    public static GameObject FindInParent(GameObject startobj, string findname, bool containDeactiveobj)
    {
        if (null == startobj)
        {
            return null;
        }
Transform[] trs = startobj.GetComponentsInParent<Transform>(containDeactiveobj);
        int len = trs.Length;
        for (int i = 0; i < len; ++i)
        {
            GameObject Tar = trs[i].gameObject;
            if (findname == Tar.name)
            {
                return Tar;
            }
        }
 return null;
    }

 public static T FindInScene<T>(string value) where T : Component
    {
        GameObject obj = FindInScene(value);
        return obj?.GetComponent<T>();
    }
    public static GameObject FindInScene(string path)
    {
        if (string.IsNullOrEmpty(path))
        {
            return null;
        }
var strPath = path.Split('/');
        var objName = strPath[strPath.Length - 1];//需要查找的物体名称
        //获取场景中的所有物体
        var _allResourceObj = Resources.FindObjectsOfTypeAll(typeof(GameObject)) as GameObject[];
        var allResourceObj = _allResourceObj.ToList();
        var allObj = allResourceObj.FindAll(x => x.scene.isLoaded);
if (strPath.Length==1)
        {
            var nameReObJ= allObj.Find(x=>x.name==objName);
            return nameReObJ;
        }
 else
        {
            //查找场景中物体名称和需要查找的物体名称一样的物体
            var nameReObJ= allObj.FindAll(x=>x.name==objName);
            //遍历物体名称重复的物体,查找根目录
            for (int i = 0; i < nameReObJ.Count; i++)
            {
                var obj = nameReObJ[i];
                string rootPath = obj.name;
                Transform parent = obj.transform.parent;
                while (parent!=null)
                {
                    var arg = parent.gameObject.name;
                    rootPath = arg + "/" + rootPath;
                    if (rootPath == path)
                    {
                        return nameReObJ[i];
                    } else
                    {
                        parent = parent.transform.parent;
                    }
                }
            }
        }
        
        return null;
    }

  //隐藏数字
    public static string HidePhoneNumber(string phone)
    {
        System.Text.StringBuilder builder = new System.Text.StringBuilder(phone, 0, 3, 11);
        builder.Append("****");
        builder.Append(phone.Substring(7));
        return builder.ToString();
    }

//MD5加密
    public static string MD5Encrypt(string text)
    {
        byte[] bytes = System.Text.Encoding.UTF8.GetBytes(text);
        return MD5(bytes);
    }

 public static string MD5(byte[] value)
    {
        byte[] result = System.Security.Cryptography.MD5.Create().ComputeHash(value);
        System.Text.StringBuilder builder = new System.Text.StringBuilder();
        for (int i = 0; i < result.Length; ++i)
        {
            builder.Append(result[i].ToString("x2"));
        }
        return builder.ToString().ToUpper();
    }

public static string SHA1(byte[] value)
    {
        byte[] result = System.Security.Cryptography.SHA1.Create().ComputeHash(value);
        var builder = new System.Text.StringBuilder();
        for (int i = 0; i < result.Length; i++)
        {
            builder.Append(result[i].ToString("x2"));
        }
        return builder.ToString().ToUpper();
    }

public static string EnterReplace(string stext)
    {
        return stext.Replace("\\n", "\n");
    }

 public static void BillBoard(GameObject obj)
    {
        if (null != Camera.main && obj)
        {
            Vector3 vtar = Camera.main.transform.TransformVector(Vector3.forward);
            Vector3 vpoint = obj.transform.position + vtar;
            obj.transform.LookAt(vpoint);
        }
    }

 public static void BoxToTriger(GameObject gt)
    {
        if (null != gt)
        {
            if (null == gt.GetComponent<Rigidbody>())
            {
                gt.AddComponent<Rigidbody>().isKinematic = true;
            }
            BoxCollider br = gt.GetComponent<BoxCollider>();
            if (null != br)
            {
                br.isTrigger = true;
            }
        }

    }

 public static GameObject CreateBoxTriger(string name, Transform parent, Vector3 center, Vector3 size)
    {
        GameObject go = new GameObject(name);
        go.AddComponent<Rigidbody>().isKinematic = true;
        go.transform.parent = parent;
        go.transform.localPosition = Vector3.zero;
        go.layer = LayerMask.NameToLayer("Ignore Raycast");
        go.transform.localScale = Vector3.one;//重新归0
        go.transform.localEulerAngles = Vector3.zero;//重新归0
BoxCollider col = go.AddComponent<BoxCollider>();
        col.isTrigger = true;
        col.center = center;
        col.size = size;
        return go;
    }

public static bool IsNetConnect()
    {
        bool suc = false;
        try
        {
            System.Net.NetworkInformation.Ping ping = new System.Net.NetworkInformation.Ping();
            PingReply py = ping.Send("www.baidu.com", 1000);
            if (py.Status == IPStatus.Success)
            {
                suc = true;
            }
        }catch
        {
            suc = false;
        }

        return suc;
    }

public static object SuperParser(string value)
    {
        if (string.IsNullOrEmpty(value)) { return value; }

        if (value[0] == '<' && value[value.Length - 1] == '>')
        {
            string str = value.Substring(1, value.Length - 2);
            if (str.Equals("true"))
            {
                return true;
            }

else if (str.Equals("false"))
            {
                return false;
            }
            else if (str.EndsWith("I"))
            {
                return int.Parse(str.Substring(0, str.Length - 1));
            }
            else if (str.EndsWith("L"))
            {
                return long.Parse(str.Substring(0, str.Length - 1));
            }
else if (str.EndsWith("F"))
            {
                return float.Parse(str.Substring(0, str.Length - 1));
            }
            else if (str.EndsWith("D"))
            {
                return double.Parse(str.Substring(0, str.Length - 1));
            }
            else if (str.StartsWith("0x"))
            {
                return Convert.ToInt32(str.Substring(2), 16);
            }else if (str.StartsWith("0b"))
            {
                return Convert.ToInt32(str.Substring(2), 2);
            }
            else
            {
                return str.Substring(0, str.Length - 1);
            }
        }
else if (value[0] == '[' && value[value.Length - 1] == ']')
        {
            List<object> list = new List<object>();
            string str = value.Substring(1, value.Length - 2);
            string[] arr = str.Split('|');
            for (int i = 0; i < arr.Length; i++)
            {
                object obj = SuperParser(arr[i]);
                list.Add(obj);
            }
 return list;
        }
        else
        {
            return value.Replace("\\n", "\n");
        }
    }
/// <summary>
    /// 反射泛型属性
    /// </summary>
    /// <param name="target">目标对象</param>
    /// <param name="type">目标对象类型</param>
    /// <param name="name">属性名</param>
    /// <returns></returns>
    public static object ReflectionGenericProperty(object target, Type type, string name)
{
        PropertyInfo pInfo = null;
        while (pInfo == null && type != null)
        {
            pInfo = type.GetProperty(name);
            type = type.BaseType;
        }
        return pInfo?.GetValue(target);
    }

/// <summary>
    /// 反射获取对象 例: object value = SuperReflection("Game.Instance.strValue");
    /// </summary>
    public static object SuperReflection(object target, string path)
    {
        Queue<string> queue = new Queue<string>(path.Split('.'));
        Type type;
if (target == null)
        {
            type = ParserType(queue.Dequeue());
        }
        else
        {
            type = target.GetType();
        }string attName = queue.Dequeue();
        object value = null;
        if (value == null)
        {
            value = ReflectionGenericProperty(target, type, attName);
        }
        if (value == null)
        {
            FieldInfo fInfo = type.GetField(attName);
            value = fInfo?.GetValue(target);
        }
if (value == null)
        {
            MethodInfo mInfo = type.GetMethod(attName);
            value = mInfo?.Invoke(target, new object[] { });
        }

        if (value == null)
        {
            return null;
        }else if (queue.Count == 0)
        {
            return value;
        }
        else
        {
            return SuperReflection(value, string.Join(".", queue));
        }
    }

else if (queue.Count == 0)
        {
            return value;
        }
        else
        {
            return SuperReflection(value, string.Join(".", queue));
        }
    }

else if (queue.Count == 0)
        {
            return value;
        }
        else
        {
            return SuperReflection(value, string.Join(".", queue));
        }
    }else if (value is GameObject)
        {
            (value as GameObject).SetActive(active);
        }
        else if (value is IEnumerable)
        {
            foreach (object obj in (value as IEnumerable))
            {
                SuperActiveOrNot(active, obj);
            }
        }
    }

 public static void SuperActiveInner(object value, object indeicesObj)
    {
        if (value is string)
        {
            SuperActiveInner(FindInScene(value as string), indeicesObj);
        }
        else if (value is Component)
        {
            SuperActiveInner((value as Component).gameObject, indeicesObj);
        } else if (value is GameObject)
        {
            GameObject obj = value as GameObject;
            List<int> list = new List<int>();
            if (indeicesObj is string)
            {
                int index = int.Parse(indeicesObj.ToString());
                list.Add(index);
            }else if (indeicesObj is IEnumerable)
            {
                int index = int.Parse(indeicesObj.ToString());
                list.Add(index);
            }
            else
            {
                int index = int.Parse(indeicesObj.ToString());
                list.Add(index);
            }
            obj.ActiveInner(list.ToArray());
        }
    }

 public static void SuperActiveInnerHex(object value, object hexObj)
    {
        if (value is string)
        {
            SuperActiveInnerHex(FindInScene(value as string), hexObj);
        }
        else if (value is Component)
        {
            SuperActiveInnerHex((value as Component).gameObject, hexObj);
        }else if (value is GameObject)
        {
            int hex = int.Parse(hexObj.ToString());
            (value as GameObject).ActiveInnerHex(hex);
        }
    }

/// <summary>按位转化</summary>
    public static int GetHexInt(params int[] args)
    {
        int result = 0;
        foreach (int i in args)
        {
            result |= (1 << i);
        }
        return result;
    }

public static List<T> SelectHexInt<T>(int value, params T[] args)
    {
        List<T> list = new List<T>();
        for (int i = 0; i < args.Length; i++)
        {
            int iHex = 1 << i;
            if ((value & iHex) == iHex)
            {
                list.Add(args[i]);
            }
        }
        return list;
    }

  public static bool ParserVector3(string value, out Vector3 vec)
    {
        if (string.IsNullOrEmpty(value))
        {
            vec = Vector3.zero;
            return false;
        }
        if (value.Contains("|"))
        {
             string[] arr = value.Split('|');
            float.TryParse(arr[0], out vec.x);
            float.TryParse(arr[1], out vec.y);
            float.TryParse(arr[2], out vec.z);
        }
        else
        {
            vec = Vector3.one * float.Parse(value);
        }
        return true;
    }

 public static bool ParserQuration(string value, out Quaternion qua)
    {
        qua = Quaternion.identity;
        if (ParserVector3(value, out Vector3 vec))
        {
            qua = Quaternion.Euler(vec);
            return true;
        }
        else
        {
            return false;
        }
    }

  public static void SyncComponet(GameObject to, GameObject from, params string[] types)
    {
        List<Type> list = new List<Type>();
        foreach (string str in types)
        {
            Type type = ParserType(str);
            if (type != null)
            {
                list.Add(type);
            }
        }
        SyncComponet(to, from, list.ToArray());
    }

 public static void SyncComponet(GameObject to, GameObject from, params Type[] types)
    {
        for (int i = 0; i < types.Length; i++)
        {
            Type type = types[i];

            Component toCtr = to.GetComponent(type);
            Component fromCtr = from?.GetComponent(type);
 if (fromCtr == null || (fromCtr is Behaviour) && !(fromCtr as Behaviour).enabled)
            {
                if (toCtr != null)
                {
                    GameObject.Destroy(toCtr);
                }
                continue;
            }

            if (toCtr == null)
            {
                toCtr = to.AddComponent(type);
            }
FieldInfo[] fInfos = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
            foreach (FieldInfo fInfo in fInfos)
            {
                if (fInfo.IsPrivate && fInfo.GetCustomAttribute<SerializeField>() == null)
                {
                    continue;
                }
                object value = fInfo.GetValue(fromCtr);
                fInfo.SetValue(toCtr, value);
            }
        }
    }

 private static SystemLanguage mCurrentLanguage = Application.systemLanguage;
    public static SystemLanguage GetCurrentLanguage() => mCurrentLanguage;
    public static void SetCurrentLanguage(SystemLanguage value) => mCurrentLanguage = value;

    [Obsolete] public static string GetLocalizedString(int id) => Localize(id.ToString());
    [Obsolete] public static string Localize(int id, params object[] args) => Localize(id.ToString(), args);

   public static string Localize(string id, params object[] args) => string.Format(Localize(id), args);

    public static Color ParserColor(object value)
    {
        Color color = default(Color);
        if (value is Color)
        {
            color = (Color)value;
        }
        else if (value is string)
        {
            ColorUtility.TryParseHtmlString(value as string, out color);
        }
        return color;
    }

  public static List<Component> FindComponents(GameObject target, bool includeChildren, params string[] names)
    {
        List<Component> list = new List<Component>();
        for (int i = 0; i < names.Length; i++)
        {
            string name = names[i];
            Type type = ParserType(name);
            if (type != null)
            {
if (includeChildren)
                {
                    Component[] arr = target.GetComponentsInChildren(type);
                    list.AddRange(arr);
                }
                else
                {
                    Component[] arr = target.GetComponents(type);
                    list.AddRange(arr);
                }
            }
        }
        return list;
    }

 public static void SimulateClick(GameObject target)
    {
        if (target != null && target.activeSelf)
        {
            BaseEventData data = new PointerEventData(EventSystem.current);
            ExecuteEvents.Execute(target, data, ExecuteEvents.pointerClickHandler);
        }
    }

  public static void Quit()
    {
#if UNITY_EDITOR
        UnityEditor.EditorApplication.isPlaying = false;
#else  
        Application.Quit();
#endif
    }

 public static string GetPkgName()
    {
        if (Application.isMobilePlatform)
        {
            return Application.identifier;
        }
        else
        {
            return string.Format("com.{0}.{1}", Application.companyName, Application.productName).ToLower();
        }
    }

  private static DateTime ServerStartTime = TimeZone.CurrentTimeZone.ToLocalTime(new DateTime(1970, 1, 1));
    public static long ToServerTime(DateTime time)
    {
        return (long)(time - ServerStartTime).TotalMilliseconds;
    }

 public static string UrlJoin(string url, Dictionary<string, string> args)
    {
        bool isFirst = !url.Contains("?");
        if (args != null)
        {
            foreach (var kv in args)
            {
                url += string.Format("{0}{1}={2}", isFirst ? "?" : "&", kv.Key, kv.Value);
                isFirst = false;
            }
        }
        return url;
    }

  public static Dictionary<string, string> UrlSplit(string url)
    {
        Dictionary<string, string> map = new Dictionary<string, string>();
        string[] arr = url.Split(new char[] { '?', '&' });
        for (int i = 1; i < arr.Length; i++)
        {
            string kvStr = arr[i];
            int index = kvStr.IndexOf('=');
            string key = kvStr.Substring(0, index);
            string value = kvStr.Substring(index + 1);
            map[key] = value;
        }
 return map;
    }

 public static void CalculateCorners(RectTransform tran, out Vector2 min, out Vector2 max)
    {
        Vector2 center = tran.anchoredPosition;
        Vector2 half = tran.sizeDelta * 0.5f;
        min = center - half;
        max = center + half;

    if (Application.isEditor)
        {
            Vector3 v0 = tran.parent.TransformPoint(min);
            Vector3 v1 = tran.parent.TransformPoint(new Vector2(min.x, max.y));
            Vector3 v2 = tran.parent.TransformPoint(max);
            Vector3 v3 = tran.parent.TransformPoint(new Vector2(max.x, min.y));

            Debug.DrawLine(v0, v1, Color.red);
            Debug.DrawLine(v0, v3, Color.red);
            Debug.DrawLine(v2, v1, Color.red);
            Debug.DrawLine(v2, v3, Color.red);
        }
    }

 public static int ClosestOffset(RectTransform from, RectTransform to, out Vector2 offset)
    {
        CalculateCorners(from, out Vector2 fMin, out Vector2 fMax);
        CalculateCorners(to, out Vector2 tMin, out Vector2 tMax);
        float x1 = tMax.x - fMin.x;
        float x2 = tMin.x - fMax.x;
        float y1 = tMax.y - fMin.y;
        float y2 = tMin.y - fMax.y;

 float x = (Math.Abs(x1) < Math.Abs(x2)) ? x1 : x2;
        float y = (Math.Abs(y1) < Math.Abs(y2) ? y1 : y2);

        offset = Vector2.zero;
        if (x1 > 0 && x2 < 0 && y1 > 0 && y2 < 0)
        {
            if (Math.Abs(x) < Math.Abs(y))
            {
                offset.x = x;
            }
            else
            {
                offset.y = y;
            }
            return -1;
        }

 else
        {
            if (x1 < 0 || x2 > 0)
            {
                offset.x = x;
            }
            if (y1 < 0 || y2 > 0)
            {
                offset.y = y;
            }
            return offset.magnitude == 0 ? 0 : 1;
        }
    }

/// <summary>
    /// 设置位置
    /// </summary>
    /// <param name="tran"></param>
    /// <param name="positionValue"></param>
    /// <param name="scaleValue"></param>
    /// <param name="rotateValue"></param>
    public static Coroutine SetLocalTransform(Transform tran, string positionValue, string scaleValue, string rotateValue, float duration)
 {
        Ywa_Object behaviour = tran.gameObject.AddComponent<Ywa_Object>();
        return behaviour.StartCoroutine(DoSetLocalTransform(behaviour, tran, positionValue, scaleValue, rotateValue, duration));
    }

 private static IEnumerator DoSetLocalTransform(Ywa_Object ctl, Transform tran, string positionValue, string scaleValue, string rotateValue, float duration)
    {
        Vector3 positionStart = tran.localPosition;
        Vector3 scaleStart = tran.localScale;
        Quaternion rotateStart = tran.localRotation;

        if (!ParserVector3(positionValue, out Vector3 positionEnd))
        {
            positionEnd = tran.localPosition;
        }
if (!ParserVector3(scaleValue, out Vector3 scaleEnd))
        {
            scaleEnd = tran.localScale;
        }
        Quaternion rotateEnd;
        if (ParserVector3(rotateValue, out Vector3 euler))
        {
            rotateEnd = Quaternion.Euler(euler);
        }
        else
        {
            rotateEnd = tran.localRotation;
        }
float time = 0;
        float progress;
        while (time < duration)
        {
            progress = time / duration;
            tran.localPosition = Vector3.Lerp(positionStart, positionEnd, progress);
            tran.localScale = Vector3.Lerp(scaleStart, scaleEnd, progress);
            tran.localRotation = Quaternion.Lerp(rotateStart, rotateEnd, progress);
            yield return new WaitForEndOfFrame();
            time += Time.deltaTime;
        }
tran.localPosition = positionEnd;
        tran.localScale = scaleEnd;
        tran.localRotation = rotateEnd;
        GameObject.Destroy(ctl);
    }


}

;