一、Transform和transform

我们来详谈Unity的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);
}
}
  • 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。

二、transform用法及其原因

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

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),花费了额外的性能。

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

个人觉得这个是之前的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

然后是测试代码:

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

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

 
效率有手动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

四、强制拔高啦!!

我还想努力一把!! 
让别人可以直接用,但是有不修改原有代码: 
怎么办呢? 
既然大家都要继承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;
// }
//}
}

也谈谈Unity的transform使用的更多相关文章

  1. Unity使用transform.Rotate进行三维旋转角度出现偏差

    Unity使用transform.Rotate进行三维旋转角度出现偏差 情形 最开始遇到该问题的情况比较复杂,另写了一个例子.情形如下: 一个立方体上挂载脚本: transform.Rotate(25 ...

  2. Unity使用transform.Translate()移动子物体时遇到的小问题

    Unity使用transform.Translate()移动子物体时遇到的小问题 情况大概是这样:父物体A下有子物体B,希望使B在本地坐标系下移动1单位. B物体挂脚本代码如下: transform. ...

  3. Unity 之 transform

    transform.Translate 1.function Translate (translation : Vector3, relativeTo : Space = Space.Self) : ...

  4. 贝塞尔曲线在Unity中的应用

    前言:国庆放假后基本整个人的散掉了.加之种种原因,没时间没心情写博客.最近研究了一下3d的一些效果.其中有类似翻书撕纸的操作,可是一个panel怎么由平整的变成弯曲的呢? 两点可以确定一条直线,三点可 ...

  5. Unity 中 使用c#线程

    使用条件   天下没有免费的午餐,在我使用unity的那一刻,我就感觉到不自在,因为开源所以不知道底层实现,如果只是简单的做点简单游戏,那就无所谓的了,但真正用到实际地方的时候,就会发现一个挨着一个坑 ...

  6. Unity UI和引用的管理中心

    我们来谈谈Unity的UI, 通常会写一些UI页面,当A页面需要去操作B页面的时候. 至少要获取B页面的引用吧! 一般新人都会在组件的写一个public GameObject UIB页面的属性, 然后 ...

  7. 用好lua+unity,让性能飞起来——关于《Unity项目常见Lua解决方案性能比较》的一些补充

    <Unity项目常见Lua解决方案性能比较>,这篇文章对比了现在主流几个lua+unity的方案 http://blog.uwa4d.com/archives/lua_perf.html ...

  8. unity中camera摄像头控制详解

    目录 1. 缘起 2. 开发 2.1. 建立项目 2.2. 旋转 2.2.1. 四元数 2.3. 移动 2.3.1. 向量操作 2.4. 镜头拉伸 2.5. 复位 2.6. 优化 1 缘起 我们的产品 ...

  9. Unity官方实例教程 Roll-a-Ball

    与unity的transform组件相处的挺久了,最近项目不太忙,决定好好打下unity的基础.那么从Roll-a-Ball这个简单游戏开始吧! 1.先创建一个球体游戏对象,改名为Player,tra ...

随机推荐

  1. SVN回滚至某个版本

    今天新上传的版本出错了,需要回滚至之前的版本. 记录一下过程. 在项目文件夹下. 1.打开日志历史.右键单击,TortoiseSVN-->show log 2.要回滚至版本x.在版本x上右键单击 ...

  2. CentOS 修改系统语言的方法

    使用如下命令: export LANG="en_US.UTF-8" 可以修改环境变量LANG,修改之后立即生效,当时当系统重新启动时便会又变成原来的语言 另外两种修改语言的方法: ...

  3. u-boot 2016.05 添加自己的board 以及config.h

    拿到一个uboot 后,我都想添加一个属于自己的board文件以及include/configs/*.h 文件. 如何添加这个些文件,今天来记录一下. 复制一份你所参考的板级文件,比如说board/v ...

  4. rp2833 网卡以及串口与接插件位置关系

    P13     eth0  (电口--兼容光口,如果使用光口,请将去掉U31以及P13) p12     eth1 P9     /dev/ttyS3 调试口 P10-1  /dev/ttyS2  r ...

  5. hadoop上线和下线节点

    在运行中的ambari hadoop集中中动态添加或删除节点 1. 下线节点1) namenode节点上dfs.exclude文件,看配置文件怎么配置的,里每行添加一个服务器名,如我要下线server ...

  6. HDU 5289 Assignment(多校2015 RMQ 单调(双端)队列)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5289 Problem Description Tom owns a company and he is ...

  7. 单网卡绑定多个ip, 多个网卡绑定成一块虚拟网卡

    Linux网卡配置与绑定   Redhat Linux的网络配置,基本上是通过修改几个配置文件来实现的,虽然也可以用ifconfig来设置IP,用route来配置默认网关,用hostname来配置主机 ...

  8. 开源图形数据库Neo4j介绍与安装

    图形数据库是以图形结构形式存储数据的数据库. https://neo4j.com/ Java 编写 保存为节点以及节点之间的关系 Neo4j 的数据由下面几部分构成: 节点 边 属性 无论是顶点还是边 ...

  9. table获取checkbox是否选中的几种方法

    function test() { $(".table tbody tr").find("td:first input:checkbox").each(func ...

  10. 【转】【Java/Android】Toast使用方法大全

    Toast 是一个 View 视图,快速的为用户显示少量的信息. Toast 在应用程序上浮动显示信息给用户,它永远不会获得焦点,不影响用户的输入等操作,主要用于 一些帮助 / 提示.Toast 最常 ...