Unity 橫版2D移動跳躍問題——關於一段跳與二段跳


1.初始條件:

1.角色只綁定一個碰撞體,移動時施加力或給予速度,用跳躍次數JumpTimes或者bool值OnGround判斷是否在地面。

2.只用一個tilemap搭建2D場景,因此所有tilemap的圖塊都是同一個tag,用於判斷是否落回地面。


2.出現的問題:

  1. 當角色跳起來接觸左右牆壁時按住左右移動鍵,會出現卡牆現象,就是角色不會因為重力掉下來,而接觸牆壁停止在半空(不符合客觀規律)
  2. 不知道碰撞體是碰到牆壁還是地面或天花板,因為所有圖塊都是同一個tag,導致如果直接在OnCollisionEnter2D方法函數里通過判斷碰撞體的tag是否為地面Ground,是就重置跳躍次數或者OnGround變為true(碰到牆也可以重置跳躍,導致可以不斷卡牆無限跳)

3.解決方案

1.通過添加空子物體並給予trigger於角色上,來檢測四個方向的碰撞,從而區分是哪邊碰到

缺點:每個prefab都要重復相同的綁定,且如果角色為不規則圖形,可能出現bug,例如:

如果角色快要從高處移動到要掉落時,剛好trigger沒接觸地,判斷已經離開地面,又不能跳躍和左右移動

2.通過采用四個tilemap搭建地圖,從而各綁定一個tag區分上天花板,地面,左牆和右牆

 if (Input.GetKey(JumpButton) && JumpTimes > 0)   //跳躍
        {
            rg.velocity = new Vector2(rg.velocity.x, JumpForce);
            JumpTimes -= Time.deltaTime;
        }
        if (Input.GetKey(MoveRightButton))
        {
            if (isRightWall == false)//判斷是否碰到右牆
            {
                if (FaceToRight == false)
                {
                    rg.transform.localScale = new Vector3(-Mathf.Abs(transform.localScale.x), transform.localScale.y, transform.localScale.z);//轉向
                }
                rg.velocity = new Vector2(MoveSpeed, rg.velocity.y);//移動
            }
            FaceToRight = true;
        }

    if (Input.GetKey(MoveLeftButton))
   {
       if (isLeftWall == false)
       {
          if (FaceToRight == true)
          {
               rg.transform.localScale = new Vector3(Mathf.Abs(transform.localScale.x), transform.localScale.y, transform.localScale.z);//轉向
          }
          rg.velocity = new Vector2(-MoveSpeed, rg.velocity.y);//移動
       }
       FaceToRight = false;
  }

3.通過添加射線檢測於角色身上,檢測角色是否離開地面,如果離開。將物理材質摩擦力變為0,這樣就不會卡牆了

  private Ray2D ray;
  public Transform tf;   //射線終結點,用空物體綁到角色作為子物體,移動位置到角色下方接觸地面
  [SerializeField] private bool onGround = false;
  
  void FixedUpdate()
    {
        
        ray = new Ray2D(transform.position, Vector2.down);
        Vector2 direction = new Vector2(tf.position.x, tf.position.y) - ray.origin;//從角色中心點到終結點的方向向量
        Vector2 target = direction + new Vector2(transform.position.x,transform.position.y);   //將子空物體的相對坐標轉換為世界坐標,求出真正射線終結點坐標
       
        Debug.DrawLine(ray.origin, target, Color.red);   //畫射線,測試用,實際可去掉
        RaycastHit2D info = Physics2D.Raycast(ray.origin, direction,Mathf.Sqrt(direction.x*direction.x+direction.y*direction.y));
      
        if (info.collider != null)
        {
            if (info.transform.gameObject.CompareTag("Ground"))
            {
                Debug.Log("碰到地板");
                onGround = true;
                JumpTimes = 0.5f;
                rg.sharedMaterial = p1;   //碰到地板就轉換成有摩擦力的
            }
            else
            {
                Debug.Log("else");
            }
        }
        Move();
    }

(但實際運行時物理材質屬性是無法改變的,但可以新建兩個物理材質,一個摩擦力friction為正常的,另一個為friction=0,運行時再用代碼改變)

private Rigidbody2D rg;
public PhysicsMaterial2D p1;  //有摩擦力的
public PhysicsMaterial2D p2;  //無摩擦力的
。。。
void Awake()
{
	rg.sharedMaterial = p1;//改變物理材質,物理材質綁在Rigidbody2D
	。。。
}
	
 public void Move()
    {

        
        if (Input.GetKey(JumpButton) && onGround)   //跳躍條件:1.按下跳躍鍵 2.射線檢測接觸地面
        {
            rg.velocity = new Vector2(rg.velocity.x, JumpForce);
            JumpTimes -= Time.deltaTime;
            onGround = false;
            rg.sharedMaterial = p2;
        }
        if (Input.GetKey(MoveRightButton))
        {
            
            if (FaceToRight == false)//用bool變量FaceToRight判斷轉向
            {
                rg.transform.localScale = new Vector3(-Mathf.Abs(transform.localScale.x), transform.localScale.y, transform.localScale.z);//左右轉向時讓圖片翻轉
            }
            rg.velocity = new Vector2(MoveSpeed, rg.velocity.y);//給予速度,移動
            FaceToRight = true;
        }
        if (Input.GetKey(MoveLeftButton))
        {
           
            if (FaceToRight == true)
           {
                rg.transform.localScale = new Vector3(Mathf.Abs(transform.localScale.x), transform.localScale.y, transform.localScale.z);//轉向
            }
            rg.velocity = new Vector2(-MoveSpeed, rg.velocity.y);//移動
            FaceToRight = false;
        }

    }

二段跳咕了(其實知曉一段跳后,二段跳就不難實現了)
轉載標明出處:作者AMzz 博客: https://www.cnblogs.com/AMzz/


免責聲明!

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



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