也談談Unity的transform使用

1、Transform和transform

咱們來詳談Unity的transform使用,這裏所說的tansform不是類UnityEngine命名空間下的Transform,而是transform. 
Transform 是Unity中最經常使用的類了。 
其類的代碼以下,代碼貼出來太長也不是要說的重點:
css

#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); } }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65


咱們所說的是經常使用的還有對象組件自身的transform,他裏面包含了位置,旋轉,縮放參數。 
在經常使用組件Compnent的代碼中:
緩存

// // 摘要: // /// // The Transform attached to this GameObject (null if there is none attached). // /// public Transform transform { get; }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

注意這個東西是屬性,有get,沒有set. 
固然命名空間仍舊爲UnityEngine。
app

2、transform用法及其緣由

咱們先來看看,這個WrapperlessIcall ,它是unity中一個屬性字段,他有什麼用呢? 
WrapperlessIcall 內部實現,非公開方法。 
你們來看看以下代碼:
less

private Transform myTransform; void Awake() { myTransform = transform; }
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4


看起來稀鬆日常,波瀾不驚,可是下面水仍是蠻深的。 
使用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; } } }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12


值得注意的是這個調用方法略慢,由於你須要調用外部的CIL(aka interop),花費了額外的性能。
性能

3、新的版本會不會作了優化呢?

我的以爲這個是以前的unity版本的東西,可能效率和性能沒有作優化測試

WrapperlessIcall] [MethodImpl(MethodImplOptions.InternalCall)]
  • 1
  • 2
  • 1
  • 2


就這些屬性來講,有的是直接調用C++代碼,有的則是調用.net的內部函數到Unity中。 
對於新的版本是否是有的優化處理呢,本身作了測試: 
先看看如今Compnent的代碼:
優化

// // 摘要: // /// // The Transform attached to this GameObject (null if there is none attached). // /// public Transform transform { get; }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6


而後是測試代碼:
this

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<Transform>(); } 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"); } } }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63


結果仍是同樣的。仍是須要作處理的。
spa

這裏寫圖片描述 
效率有手動cache (4ms)>>transform(20ms)>>this.tranform(22ms)>> GetComponent()(54ms) 
可是原來的測試結果爲:

1000000 次的Iterations ● GetComponent = 619ms ● Monobehaviour = 60ms ● CachedMB = 8ms ● Manual Cache = 3ms
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5


看來這其中仍是有奧祕的。 
我電腦配置目前還算能夠,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. }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

4、強制拔高啦!!

我還想努力一把!! 
讓別人能夠直接用,可是有不修改原有代碼: 
怎麼辦呢? 
既然你們都要繼承monobehaviour,那我就在他上面想辦法。

4.1 方法一,實現一個擴展方法:

public static class ExtendMono { public static Transform tranform(this MonoBehaviour tsf) { Transform _tsf; _tsf = tsf.transform; return _tsf; } }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9


可是這個擴展方法,必須靜態的,因此沒有辦法作一個靜態的臨時變量啊,這個不靠譜啊。 
若寫成上面的代碼效率並無太多提升。每次仍是須要賦值。 
因此這個路走不通啊!! 
來看方法二吧。

4.2 方法二,乾坤大挪移,從新命名類

public class MonoBehaviour : UnityMonoBehaviour { Transform _transform; public Transform transform { get { return _transform ?? (_transform = base.transform); } } }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8


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<Transform>(); } 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; // } //} }
相關文章
相關標籤/搜索