首页 > 代码库 > Unity3D 在Update中不要过多地修改Transform 信息

Unity3D 在Update中不要过多地修改Transform 信息

前文说到碰撞检测时候,不要在Update内部尝试移动GameObject 来检查碰撞检测,这样是徒劳无功。但是 说到

因为你移动的过程中其实并没有将实际的移动位置更新到物理引擎,只是做了个缓存而已,

只有在调用FixedUpdate的内部函数(物理引擎处理)时,才会将最新的位置设置到物理引擎上,甚至是渲染引擎也使用最新的位置。

其实是有问题的,因为我发现每次移动都会导致 碰撞器不断更新

技术分享

下面是测试代码:

技术分享
    int TEST = 0;

    // Returns true if you were able to move, false if you collided.
    // 人物不断尝试往‘下‘走到 Y+amount
    //  如果 中途碰撞到物体 则 人物站在 物体上 并return false
    //  否则返回true,代表人物已成功移动到yVel 的位置
    bool TryMoveY(float amount)
    {
        //optimize

        var sign = Mathf.Sign(amount);
        var increment = 0.001f;
        var progress = 0f;

        //var DEBUG = 0;
        TEST = 0;
        while (true)
        {
            //DEBUG++;
            ++TEST;
            var rest = Mathf.Abs(amount) - Mathf.Abs(progress);
            if (rest <= 0)
                break;
            increment = Mathf.Min(increment, rest);

            Y += increment * sign;
            progress += increment * sign;
            if (Colliding())
            {
                Y -= increment * sign;
                //print(DEBUG);
                return false;
            }

        }
        //print(TEST);
        TEST = 0;

        //print(DEBUG);
        return true;


        //var increment = amount > 0 ? 0.01f : -0.01f;
        //var progress = 0f;

        //while(Mathf.Abs(progress) < Mathf.Abs(amount))
        //{
        //    // progress 远远 小于 amount - increment
        //    // 步伐依然为 increment = 0.01
        //    if (Mathf.Abs(progress) < Mathf.Abs(amount) - Mathf.Abs(increment))
        //    {
                // NOTHING
        //    }
        //    else // 缩小步伐(最后一步了)
        //    {
        //        increment = amount - progress;
        //    }

        //    Y += increment;
        //    progress += increment;

        //    if (Colliding())
        //    {
        //        Y -= increment;
        //        return false;
        //    }
        //}

        //return true;

    }

    private void OnTriggerEnter2D(Collider2D collision)
    {
            print("ENTER: " + collision + " " + name + "  " + TEST);
        
    }

    private void OnTriggerExit2D(Collider2D collision)
    {
            print("EXIT: " + collision + " " + name + "  " + TEST);
    }
View Code

这里顺便测试了到底 在Update中修改Transform(.Position)而更新 BoxCollider 是否会激发OnTriggerEnter2D、OnTriggerExit2D。如果 此两个函数输出时 TEST 的值不为0,则是在Update中会导致物理引擎的更新。这里输出的结果为0,所以我的猜测是对的。物理引擎并不是和脚本逻辑并行的(不是多线程) 

技术分享

但是更新了Transform 而立即导致物理碰撞器的更新,而不是暂时将Transform做缓存,等到物理引擎更新时才读取最新的Transform来更新碰撞器,为什么Unity3D这样做呢?

实际原因我当然是不得而知了,但是我猜测吧,应该是 物理引擎提供了一些基本的函数给脚本逻辑使用,例如Physics.Raycast / RaycastHit2D Linecast(Vector2 start, Vector2 end);等,如果没有及时更新 BoxCollider2D的信息,有可能会导致使用碰撞检测等API时会出现BUG。

Unity3D 在Update中不要过多地修改Transform 信息