Unity transform使用详解

您所在的位置:网站首页 mytransform Unity transform使用详解

Unity transform使用详解

2024-01-13 02:32| 来源: 网络整理| 查看: 265

一、Transform和transform

我们来详谈Unity的transform使用,为了让大家不混淆Transform和transform的使用,所以这里所说的tansform不是类UnityEngine命名空间下的Transform,而是transform。Transform 是Unity中最常用的类了。 其类的代码如下,代码贴出来太长也不是要说的重点

#region 程序集 UnityEngine, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null // H:\Unity\Project\VRThemePark_03\Library\UnityAssemblies\UnityEngine.dll #endregion using System; using System.Collections; using UnityEngine.Internal; namespace UnityEngine { // // 摘要: // /// // Position, rotation and scale of an object. // /// public class Transform : Component, IEnumerable { protected Transform(); // // 摘要: // /// // The number of children the Transform has. // /// public int childCount { get; } // // 摘要: // /// // The rotation as Euler angles in degrees. // /// public Vector3 eulerAngles { get; set; } // // 摘要: // /// // The blue axis of the transform in world space. // /// public Vector3 forward { get; set; } // // 摘要: // /// // Has the transform changed since the last time the flag was set to 'false'? // /// public bool hasChanged { get; set; } // // 摘要: // /// // The transform capacity of the transform's hierarchy data structure. // /// public int hierarchyCapacity { get; set; } // // 摘要: // /// // The number of transforms in the transform's hierarchy data structure. // /// public int hierarchyCount { get; } // // 摘要: // /// // The rotation as Euler angles in degrees relative to the parent transform's rotation. // /// public Vector3 localEulerAngles { get; set; } ..... public void Translate(float x, float y, float z, Transform relativeTo); } }

我们所说的是常用的还有对象组件自身的transform,他里面包含了位置,旋转,缩放参数。 在常用组件Compnent的代码中:

// // 摘要: // /// // The Transform attached to this GameObject (null if there is none attached). // /// public Transform transform { get; }

注意这个东西是属性,有get,没有set. 当然命名空间仍旧为UnityEngine。

二、transform用法及其原因

我们先来看看,这个WrapperlessIcall ,它是unity中一个属性字段,他有什么用呢? WrapperlessIcall 内部实现,非公开方法。 

大家来看看如下代码:

private Transform myTransform; void Awake() { myTransform = transform; }

看起来稀松平常,波澜不惊,但是下面水还是蛮深的。 使用myTransform替代this.transform。如果你不知道u3d内部实现获取方式你肯定会以为这人脑抽水了,有直接的不用,还自己保存起来。 this.transform并不是变量,而是一个get/set属性(property) 他是一个C++写的代码,在Mono中被调用。调用是intenal method的调用,其效率本身不是高。 比如,transform 经常需要保存在本地,然后在使用。

namespace UnityEngine { public class Component : Object { public extern Transform transform { [WrapperlessIcall] [MethodImpl(MethodImplOptions.InternalCall)] get; } } }

值得注意的是这个调用方法略慢,因为你需要调用外部的CIL(aka interop),花费了额外的性能。

三、新的版本会不会做了优化呢?

个人觉得这个是之前的unity版本的东西,可能效率和性能没有做优化。

WrapperlessIcall] [MethodImpl(MethodImplOptions.InternalCall)]

就这些属性来说,有的是直接调用C++代码,有的则是调用.net的内部函数到Unity中。 对于新的版本是不是有的优化处理呢,自己做了测试: 先看看现在Compnent的代码:

// // 摘要: // /// // The Transform attached to this GameObject (null if there is none attached). // /// public Transform transform { get; }

然后是测试代码:

using UnityEngine; using System.Collections; using System.Diagnostics; using System.Reflection; using System; public class CacheTest : MonoBehaviour { const int ITERATIONS = 1000000; // Use this for initialization Transform cached; IEnumerator Start() { cached = transform; UnityEngine.Debug.Log("test........."); while(true) { yield return null; if (Input.GetKeyDown(KeyCode.T)) break; var sw1 = Stopwatch.StartNew(); { Transform trans1; for (int i = 0; i < ITERATIONS; i++) trans1 = GetComponent(); } sw1.Stop(); var sw2 = Stopwatch.StartNew(); { Transform trans2; for (int i = 0; i < ITERATIONS; i++) trans2 = transform; } sw2.Stop(); var sw3 = Stopwatch.StartNew(); { Transform trans3; for (int i = 0; i < ITERATIONS; i++) trans3 = cached; } sw3.Stop(); var sw4 = Stopwatch.StartNew(); { Transform trans4; for (int i = 0; i < ITERATIONS; i++) trans4 = this.transform; } sw4.Stop(); UnityEngine.Debug.Log(ITERATIONS + " iterations"); UnityEngine.Debug.Log("GetComponent " + sw1.ElapsedMilliseconds + "ms"); UnityEngine.Debug.Log("this.transform" + sw4.ElapsedMilliseconds + "ms"); UnityEngine.Debug.Log("CachedMB " + sw2.ElapsedMilliseconds + "ms"); UnityEngine.Debug.Log("Manual Cache " + sw3.ElapsedMilliseconds + "ms"); } } }

结果还是一样的。还是需要做处理的。

 效率有手动cache (4ms)>>transform(20ms)>>this.tranform(22ms)>> GetComponent()(54ms) 但是原来的测试结果为:

1000000 次的Iterations ● GetComponent = 619ms ● Monobehaviour = 60ms ● CachedMB = 8ms ● Manual Cache = 3ms

看来这其中还是有奥秘的。 我电脑配置目前还算可以,win7 64 位,I7-3770 + 960显卡+ 16G内存。 结果对比,相对与之前2012年Unity版本,可能mono做了很大的优化,当然我们的电脑可能还是不一样,没有办法直接做对比,也只能猜测而已。 但是结论还是一样的: 在以后的使用中,若大量使用,还是需把transform给手动保存下来吧。 说明: 代码做了修改: 原来的代码中有这些:

1. Transform _transform; 2. public Transform transform 3. { 4. get { return _transform ?? (_transform = base.transform); } 5. } 6. 7. 8. //for testing 9. public Transform 10. { 11. get { return base.transform; } 12. } 四、强制拔高啦!!

我还想努力一把!! 让别人可以直接用,但是有不修改原有代码: 怎么办呢? 既然大家都要继承monobehaviour,那我就在他上面想办法。

4.1 方法一,实现一个扩展方法: public static class ExtendMono { public static Transform tranform(this MonoBehaviour tsf) { Transform _tsf; _tsf = tsf.transform; return _tsf; } }

但是这个扩展方法,必须静态的,所以没有办法做一个静态的临时变量啊,这个不靠谱啊。 若写成上面的代码效率并没有太多提高。每次还是需要赋值。 所以这个路走不通啊!! 来看方法二吧。

4.2 方法二,乾坤大挪移,重新命名类 public class MonoBehaviour : UnityMonoBehaviour { Transform _transform; public Transform transform { get { return _transform ?? (_transform = base.transform); } } }

UnityMonoBehaviour 这个是啥呢?哈哈 看using UnityMonoBehaviour = UnityEngine.MonoBehaviour; 我们来看看结果:  直接使用tranform 和this.tranform花费时间为9ms,比上面的20多ms,那是降低了很多。 但是,这个是结论啊,还是没有手动缓存的效果高啊,依旧为4ms。 放出所有代码:

using UnityMonoBehaviour = UnityEngine.MonoBehaviour; using UnityEngine; using System.Collections; using System.Diagnostics; using System.Reflection; using System; namespace aa { public class CacheTest : MonoBehaviour { const int ITERATIONS = 1000000; // Use this for initialization Transform cached; IEnumerator Start() { cached = transform; UnityEngine.Debug.Log("test........."); while (true) { yield return null; if (Input.GetKeyDown(KeyCode.T)) break; var sw1 = Stopwatch.StartNew(); { Transform trans1; for (int i = 0; i < ITERATIONS; i++) trans1 = GetComponent(); } sw1.Stop(); var sw2 = Stopwatch.StartNew(); { Transform trans2; for (int i = 0; i < ITERATIONS; i++) trans2 = transform; } sw2.Stop(); var sw3 = Stopwatch.StartNew(); { Transform trans3; for (int i = 0; i < ITERATIONS; i++) trans3 = cached; } sw3.Stop(); var sw4 = Stopwatch.StartNew(); { Transform trans4; for (int i = 0; i < ITERATIONS; i++) trans4 = this.transform; } sw4.Stop(); UnityEngine.Debug.Log(ITERATIONS + " iterations"); UnityEngine.Debug.Log("GetComponent " + sw1.ElapsedMilliseconds + "ms"); UnityEngine.Debug.Log("this.transform " + sw4.ElapsedMilliseconds + "ms"); UnityEngine.Debug.Log("CachedMB " + sw2.ElapsedMilliseconds + "ms"); UnityEngine.Debug.Log("Manual Cache " + sw3.ElapsedMilliseconds + "ms"); } } } public class MonoBehaviour : UnityMonoBehaviour { Transform _transform; public Transform transform { get { return _transform ?? (_transform = base.transform); } } } //public static class ExtendMono //{ // public static Transform tranform(this MonoBehaviour tsf) // { // Transform _tsf; // _tsf = tsf.transform; // return _tsf; // } //} }


【本文地址】


今日新闻


推荐新闻


    CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3