Unity2D中關於rigidbody2d+collider碰撞另一個collider發生的抖動問題


原文:https://blog.csdn.net/jk_chen_acmer/article/details/106945419

Player增加組件:rigidbody2D+circlecollider2D

樹增加組件:boxcollider2D

我發現如果使用常規的方法去更新transform.positon的值,當Player和樹發生碰撞時,會抖動,有點兒像抽搐觸電的感覺。

這是因為如果我們使用修改transform.position來實現的話,因為unity在第一時間更新了GameObject的position值,而這時,其實rigidbody2D的position還沒有被更新。

那么當下一次更行rigidbody2D的position時,組件rigidbody2D久會發現,欸?我怎么在碰撞體里面了??於是會發生一個位移,就是把Player從碰撞體中擠出去。

這個問題的主要矛盾,其實就是游戲對象的position先於rigidbody的檢測更新了,導致游戲對象的碰撞體和另一個碰撞體產生了交集。

那么我們可以得出的結論就是,只要讓rigidbody的檢測發生在position更新之前,就行了。即:我先判斷前方有沒有碰撞體?有,則position不能更新;無,則更新position

那么我們就不能在代碼中直接去更改transform.position的值,且,不能直接更改rigidbody2D.position的值。我們必須通過一個接口,告訴rigidbody,我要移動到這個位置!rigidbody組件收到消息后,他知道,哦,我要移動到這個位置,但是他同時也要兼具一個責任——仿真物理效果(即,不能讓collider1和collider2產生交集)。那么rigidbody2D組件內部久會自行運轉,他會先判斷會不會有collider交集的發生,然后才是移動行為。

如果我們這樣去實現,就不會出現有一個物體突然出現在另一個物體的內部,從而被rigidbody給擠出去的情形。你想象一下,如果說現實中,你的手去拿水杯,突然你的手進入了水杯的內部!這河里嗎?這布河里!

所以根本的邏輯是,你要移動這個對象,可以!但是不能直接去更改他的position,而是通過物理引擎實現移動,是你告訴物理引擎,我要移動到這里,而不是直接把這個物體瞬移過去。

那么解決方法就簡單了,調用Rigidbody2D的接口函數MovePosition

一個例子(這是Player腳本,掛載在Player對象身上):

public class Player : MonoBehaviour
{

  // Player的剛體組件
  private Rigidbody2D Rigidbody2D;

  // Player的移動速度
  public float Speed;

  // Player的移動協程 它必須保證在進程中唯一存在,不允許同一時間存在多個
  private Coroutine MoveCoroutine;
  private void Awake()
  {

    // 數據初始化

    Rigidbody2D = GetComponent<Rigidbody2D>();
    Speed = 2;
  }
  private void FixedUpdate()
  {

    // 如果按下鼠標左鍵
    if (Input.GetMouseButton(0))
    {

      // 獲得一個從屏幕鼠標位置垂直於游戲畫面的射線 ray
      Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
      RaycastHit raycastHit;

      // 在Plane(地面)上得到一個交點 raycastHit
      Physics.Raycast(ray, out raycastHit, 100.0f, 1 << LayerMask.NameToLayer("Plane"));

      // 讓Player移動到鼠標位置
      IMove(new Vector2(raycastHit.point.x, raycastHit.point.y));
    }
  }

  // 移動接口 保證移動協程只能存在一個,如果有第二個移動指令,則立馬終止上一個移動協程,開啟新的移動協程

  private void IMove(Vector2 position)
  {
    if (MoveCoroutine != null)
    {
      StopCoroutine(MoveCoroutine);
      MoveCoroutine = StartCoroutine(IEMove(position));
    }
    else
    {
    MoveCoroutine = StartCoroutine(IEMove(position));
    }
  }

   // 移動協程
  private IEnumerator IEMove(Vector2 position)
  {
    while (Vector2.Distance(Rigidbody2D.position, position) > 0.05f)
    {
      Vector2 currentPos = Rigidbody2D.position;
      Vector2 direction = position - currentPos;
      RaycastHit2D raycastHit2D = Physics2D.CircleCast(Rigidbody2D.position, 0.01f, direction, 0.01f, 1 << LayerMask.NameToLayer("Tree"));
      if (raycastHit2D.collider != null)
      {
        break;
      }
      Vector2 destination = new Vector2(currentPos.x + direction.x * Time.fixedDeltaTime * Speed, currentPos.y + direction.y * Time.fixedDeltaTime * Speed);
      Rigidbody2D.MovePosition(destination);
      yield return null;
    }
  }
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM