• 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/

  • 相关阅读:
    调试 XPTable
    适合IT经理的编程语言
    请问我如何在一个webBrowser控件中加载一个 html格式的字符串 _NET技术 C#
    DotNetBar 教程
    思梅
    无家可归的苦
    思霞
    思兰
    十大因素——造就优秀的董事长
    思萍
  • 原文地址:https://www.cnblogs.com/AMzz/p/11802502.html
Copyright © 2020-2023  润新知