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); }
这里顺便测试了到底 在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。