刨根问底U3D---Vector3 你到底是蔬菜呢还是水果呢?

刨根问底U3D---Vector3 你到底是蔬菜呢还是水果呢?

事情的起因还是因为一段代码,因为在做一个2D TileBase的游戏 所以需要有一个简单的 Tile坐标到世界坐标的变换

复制代码
public static Vector3 GetTileWorldPosByTileIndex(int _tileIndexX, int _tileIndexY , Vector3 _result)
{
    if(_result == null)
    {
        _result = new Vector3();
    }
    _result.x = TileConst.TILE_WIDTH * _tileIndexX;
    _result.y = TileConst.TILE_HEIGHT * _tileIndexY;
    _result.z = 0;
    return _result;
}
复制代码

代码逻辑很简单,特殊的地方就是后面传入的Vector3,因为函数会被经常调用 所以不想每次都New出来一个新的Vector3. OK 运行..

Warning CS0472: The result of comparing value type `UnityEngine.Vector3' with null is `false'
Unreachable code detected

WTF?! 哪里错了? Vector3 居然不能和null 判等? 嘿经过我一通测试 果真发现一些问题

来看如下的代码

复制代码
public class Test01 : MonoBehaviour
{

    void Start ()
    {
        int inputInt = 500;
        int outputInt = SetIntWithRandom (inputInt);
        Debug.Log (inputInt);
    }
    
    public  int SetIntWithRandom(int _input)
    {
        _input = Random.Range(-300,300);
        return _input;
    }

}
复制代码

这段应该很简单,弄出来一个int 类型然后传入函数内部, 然后在Log出来 看看是否有发生改变。 Ok 运行

Log结果 500,

说明没有发生任何改变。 也就是说 int 类型的变量是 传值不是传址的

再换下一组

复制代码
public class Test01 : MonoBehaviour
{

    void Start ()
    {
        int[] inputIntArray = new int[2];
        inputIntArray [0] = 500;
        int[] outputIntArray = SetIntArrayWithRandom (inputIntArray);
        Debug.Log (inputIntArray [0]);
    }
    
    public int[] SetIntArrayWithRandom(int[] _inputIntArray)
    {
        _inputIntArray[0] = Random.Range(-300,300);
        return _inputIntArray;
    }

}
复制代码

Log结果 -89 发生改变. 对于Array来说 是传址不是传值的.

Ok 来看 Vector3

复制代码
public class Test01 : MonoBehaviour
{

    void Start ()
    {
        Vector3 inputV3 = new Vector3 ();
        inputV3.x = 500;
        Vector3 outputV3 =SetV3ValueWithRandom (inputV3);
        Debug.Log (inputV3.x);
    }
    
    public Vector3 SetV3ValueWithRandom (Vector3 _result)
    {
        _result.x = Random.Range (-300, 300);
        return _result;
    }

}
复制代码

Log结果 500.

也就是说呢, 虽然Vector3 初始化时候 需要用New 操作符, 但是Vector3 却是一个基础类型 和 float,int 一样

之前有很多类似的地方都是想节约内存不每次进行new操作,于是类中做了一个引用,然后函数时候将引用传过去。

Vector3 inputV3 = new Vector3 ();
inputV3 =SetV3ValueWithRandom (inputV3)

现在看来,其实一点都没有省...

这个也解释了 为什么再给 transfrom的position赋值时候不能

transform.position.x = 100; 这样去做 会报错说

Error CS1612: Cannot modify a value type return value of `UnityEngine.Transform.position'. Consider storing the value in a temporary variable (CS1612)

我又做了几个相关的测试,实在懒得写了 :) 就把相关结果说一下吧(有兴趣可以私聊哈)

 

1· 每次去New Vector3 对性能开销大么?

我Profile了一下, 在一个Update里面 循环去new 10w个 Vector3, CPU和内存都没有任何的波动.

复制代码
vod Update()
{
    Vector3 tmp;
    for(int i=0 ; i<100000;i++)
    {
        Vector3 tmp = new Vector3();
        tmp.x = Random.Range (-300, 300);
    }
    transform.position = tmp
}
复制代码

也就是完全把它当int来看就好了,虽然使用的是New操作符 总感觉 要有很大动静似的...

复制代码
vod Update()
{
    int tmp;
    for(int i=0 ; i<100000;i++)
    {
        tmp = Random.Range (-300, 300);
    }
}
复制代码

 

2· 虽然开销很小 但是我还是想类中保留一个引用,然后不用每次去New出来 应该怎么做?

直接在函数的参数中改为ref即可, 感觉ref是C# 中很变态的东西 int啊 float啊什么的 都能ref (之前接触到得As3,Java是不行的 从C++上面继承来的特性吧 这个应该是)

public static void GetTileWorldPosByTileIndex(int _tileIndexX, int _tileIndexY , ref Vector3 _result)
{
    _result.x = TileConst.TILE_WIDTH * _tileIndexX;
    _result.y = TileConst.TILE_HEIGHT * _tileIndexY;
    _result.z = 0;
}

 

3· 注意一下 Nullable Type

可以看下这篇文章 http://unitypatterns.com/nullable-types/

两个问题,一个是说

Vector3 tmp;
Debug.Log(tmp.x) //  这里会有结果,结果是0

也就是说 Vector3 在没有new操作时候 是有默认值的 和 布尔默认值是false, int默认值是0 一个道理

第二个 如果不希望这样的话 那就要使用 牛逼操作符 问号..

Vector3? tmp;
if(tmp.HasValue)
{
    Debug.Log(tmp.Value);
}

在Vector3后面加一个问号 将其转变为Nullable Type 然后就可以用HasValue判断是否有值 然后用 xxx.Value获得这个值了

 

OK 继续搞游戏去了..

 

Best

Eran 

 

PS: 写完以后被各种大神教育了一下,Struct问题 呵呵

其实Vector3是一个Struct 所以才有这种特性,如果有兴趣可以看下MSDN

https://msdn.microsoft.com/en-us/library/aa288471%28v=vs.71%29.aspx

摘录一段:

 

Structs vs. Classes

 

Structs may seem similar to classes, but there are important differences that you should be aware of. First of all, classes are reference types and structs are value types. By using structs, you can create objects that behave like the built-in types and enjoy their benefits as well.

 

Heap or Stack?

 

When you call the New operator on a class, it will be allocated on the heap. However, when you instantiate a struct, it gets created on the stack. This will yield performance gains. Also, you will not be dealing with references to an instance of a struct as you would with classes. You will be working directly with the struct instance. Because of this, when passing a struct to a method, it's passed by value instead of as a reference.

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值