unity2D学习(9)爬墙、跳跃修改、组织Inspector中的属性显示

1 准备工作

我把cling错看成了climb,所以做了个爬墙的功能。这里把cling动画就加入到动态切换里面,然后添加一个参数Wall(Boolean)控制。

参数判断:

  • jump->cling:wall为true,在墙上。
  • cling->jump:wall为false,不在墙上;ground为false,不在地上。
  • idle->cling:wall为true,在墙上。
  • cling->idle:wall为false,不在墙上。
  • run->cling:wall为true,在墙上。

unity2D学习(9)爬墙、跳跃修改、组织Inspector中的属性显示_第1张图片

 

2 爬墙

总代码的思路:把角色分为在地上、在墙上、空中三种状态。在地上的时候,可以移动、爬墙、跳跃;在空中的时候,可以爬墙、二段跳;在墙上的时候,可以上下爬、跳跃。至于爬墙的思路,只需要修改y轴的坐标就好了。(总代码会在本文最后给出)

遇到的问题:

  • 判断左右碰撞,且要和下面碰撞做区分:搜了很多资料,最终决定采用Physics2D.OverlapCircle来判断碰撞的方向。

Physics2D.OverlapCircle介绍

作用:检查对撞机是否落在圆形区域内(用来设置检测碰撞点,检测碰撞可以更详细)。

public static Collider2D OverlapCircle(Vector2 point, float radius, int layerMask = DefaultRaycastLayers, float minDepth = -Mathf.Infinity, float maxDepth = Mathf.Infinity);

point 圆心
radius 半径
layerMask 检测的特定Layer的对象
minDepth z轴大于或等于此值的对象
maxDepth z轴小于或等于此值的对象

Gizmos类介绍

Gizmos类:Gizmos用于Scene中给出一个可视化的调试或辅助设置。

作用:为了让设置碰撞点范围可见,方便可视化调整。

注意:

  • Gizmos绘制必须在OnDrawGizmos或OnDrawGizmosSelected函数中完成。
  • OnDrawGizmos随程序启动运行,会在每一帖被调用;OnDrawGizmosSelected当鼠标点击时候运行

这次代码要用到的绘制函数:

  • Gizmos.color = Color.red;//设置颜色
  • Gizmos.DrawWireSphere((Vector2)向量, 半径);//设置圆形

碰撞点绘制代码

    public Vector2 bottomOffset, rightOffset, leftOffset;//下左右相对于角色中心的二维向量坐标
    void OnDrawGizmos()//绘制辅助线
    {
        Gizmos.color = Color.red;//辅助线颜色
        //绘制圆形辅助线
        Gizmos.DrawWireSphere((Vector2)transform.position + bottomOffset, collisionRadius);
        Gizmos.DrawWireSphere((Vector2)transform.position + rightOffset, collisionRadius);
        Gizmos.DrawWireSphere((Vector2)transform.position + leftOffset, collisionRadius);
    }

上面的坐标参数设置成了public,这样就可以在inspector里面可以观察到参数,根据效果来修改。

unity2D学习(9)爬墙、跳跃修改、组织Inspector中的属性显示_第2张图片

判断碰撞方向代码

    bool isGround()//判断是否碰地
    {
        return Physics2D.OverlapCircle((Vector2)transform.position + bottomOffset, collisionRadius, groundLayer);//判断是否碰到地面
    }
    bool touchWall()//判断是否碰到墙
    {
        return Physics2D.OverlapCircle((Vector2)transform.position + rightOffset, collisionRadius, groundLayer)
            || Physics2D.OverlapCircle((Vector2)transform.position + leftOffset, collisionRadius, groundLayer); 
    }

3 跳跃修改

问题:

  • 跳跃后横向速度不固定:之前写的跳跃,跳跃起来之后还能够左右移动,就算不能去掉左右移动,也还是会收到初始跳跃的横向速度影响。
  • 爬墙时跳跃后方向要修改:爬墙的方向如果是向右,那么跳跃的话方向就会向左。

代码思路:

  • 跳跃后横向速度固定:x方向的速度修改,按照之前跳跃y的速度修改方法就好了。
  • 爬墙跳跃方向修改:用一个face参数(1表示右边,-1表示左边)记录当前的角色朝向,然后如果跳跃就用face来改变角色朝向,速度=数值*face相反数值。至于face参数的获取,在每次按下左右按键的时候获取。

跳跃的速度变化核心代码

rig.velocity = new Vector2(face*moveForce*Time.deltaTime, jumpForce * Time.deltaTime);

爬墙跳跃方向核心代码

    参数face
    private float face=1;//记录角色朝向,初始为向右
    参数face修改
    float faceDirection = Input.GetAxisRaw("Horizontal");
    if (faceDirection != 0)//按下按键,左边为-1,右边为1,不按就是0
    {
        face = faceDirection;//face参数的获取,在每次按下左右按键的时候获取
    }
    爬墙跳跃时候,进行的方向修改
    face = (face == 1) ? -1 : 1;//在墙上跳出的话,动画要和原来相反
    transform.localScale = new Vector2(face, 1);

4 组织Inspector中的属性显示

涉及到的参数越来越多,需要来组织一下这些参数在Inspector上的显示。

通过 “Header”、“Tooltip”、“Space”、“HideInInspector” 、“SerializeField”和属性来组织Inspector中的属性显示。

[Header("hello")]:会出现一行字符串“hello”

[Tooltip("hello")]Tooltip:写在某个变量上方,就可以在instpector面板上点击到对应的变量后,提示注释字符串"hello"

[Space]:会在Inspector上的显示显示空行

[HideInInspector]:公有变量可以在Inspector上的显示,所以在定义变量前面加上就可以隐藏显示了

[SerializeField]:私有变量不能在Inspector上的显示,所以在定义变量前面加上就可以显示了

5 最终完整代码

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerController : MonoBehaviour
{
    private Rigidbody2D rig;//刚体
    private Animator Anim;//角色的Animator

    [Header("Layers")]
    public LayerMask groundLayer;//用来开启layer

    [Space]
    [Header("Speed")]
    [SerializeField] private float moveSpeed=360f;//移动速度
    private float climbSpeed=100f;//爬行速度

    [Space]
    [Header("Force")]
    private float moveForce=100f;//移动力
    private float jumpForce=575f;//跳跃力

    [Space]
    [Header("Frequency")]
    private int jumpMax=2;//跳跃次数的上线
    [SerializeField] private int jumpNum=0;//当前跳跃的次数

    [Space]
    [Header("Booleans")]
    [SerializeField] private bool falling = false;//用来标记是否是下落状态
    [SerializeField] private bool onWall;//是否在墙上
    [SerializeField] private bool onJumping;//是否正在跳跃中
    [SerializeField] private bool onGround;//是否正在地上

    [Space]
    [Header("Collision")]
    private float collisionRadius = 0.15f;//碰撞半径
    public Vector2 bottomOffset, rightOffset, leftOffset;//下左右相对于角色中心的二维向量
    private Collider2D coll;//角色的碰撞器

    [Space]
    private float face;//记录角色朝向
    

    //初始化
    void Start()
    {
        rig = GetComponent();//获取主角刚体组件
        Anim = GetComponent();//获取主角动画组件
        coll = GetComponent();//获取角色碰撞器
        groundLayer = 1 << 8;//开启Ground的layer层,Ground在layer8
        onWall = false;//初始不在墙上
        onJumping = false;//初始不正在跳跃
        onGround = true;//初始在地上
        face = 1;//初始朝向向右边
        moveSpeed = 360f;//移动速度
    }

    void FixedUpdate()
    {
        Movement();
        changeAnimator();
    }

    //控制移动
    void Movement()
    {
        float moveMultiple = Input.GetAxis("Horizontal");
        float faceDirection = Input.GetAxisRaw("Horizontal");
        //获取纵轴
        float verticalMove = Input.GetAxis("Vertical");
        if (onGround)//在地上
        {
            move(moveMultiple, faceDirection);//左右移动
            if (touchWall())//是否可爬墙,碰到墙
            {
                if (verticalMove>0)//是否有爬墙的行为,按向上键
                {
                    onGround = false;
                    onWall = true;
                    Climb(verticalMove);
                }
            }
            if (Input.GetButtonDown("Jump"))
            {
                onGround = false;
                onJumping = true;
                Jump();
            }
        }
        else if (onJumping)//在空中跳跃
        {
            if (touchWall())//可以爬墙
            {
                onJumping = false;//关闭现在状态
                onWall = true;//开启下一个状态
                Climb(verticalMove);//爬行
                jumpNum = 0;//跳跃次数清零
            }
            else if (Input.GetButtonDown("Jump"))//二段跳
            {
                Jump();
            }
        }
        else if (onWall)//在墙上
        {
            if(Input.GetButtonDown("Jump"))
            {
                onWall = false;
                onJumping = true;
                face = (face == 1) ? -1 : 1;//在墙上跳出的话,动画要和原来相反
                transform.localScale = new Vector2(face, 1);
                Jump();
                
            }
            else if (touchWall())//如果碰到墙,就说明还在爬
            {
                Climb(verticalMove);
            }
            else//如果说爬到了末端,就可以有跳跃行为,不然的话难爬到地面
            {
                onWall = false;
                onJumping = true;
                Jump();
            }
        }
    }
    bool isGround()//判断是否碰地
    {
        return Physics2D.OverlapCircle((Vector2)transform.position + bottomOffset, collisionRadius, groundLayer);//判断是否碰到地面
    }
    bool touchWall()//判断是否碰到墙
    {
        return Physics2D.OverlapCircle((Vector2)transform.position + rightOffset, collisionRadius, groundLayer)
            || Physics2D.OverlapCircle((Vector2)transform.position + leftOffset, collisionRadius, groundLayer); 
    }
    void move(float moveMultiple,float faceDirection)//移动代码
    {
        //角色左右移动
        if (moveMultiple != 0)
        {
            //velocity表示速度,Vector表示向量
            rig.velocity = new Vector2(moveMultiple * moveSpeed * Time.deltaTime, rig.velocity.y);//输入x,y向量,数值*方向
        }
        //角色朝向修改
        if (faceDirection != 0)
        {
            //Scale,代表缩放,Localscale代表的是当前物体相对于父物体的缩放,通过正负不修改大小来实现左右朝向修改
            transform.localScale = new Vector2(faceDirection, 1);
            face = faceDirection;
        }
    }
    void Jump()//跳跃代码
    {
        if(jumpNum < jumpMax)
        {
            rig.velocity = new Vector2(face*moveForce*Time.deltaTime, jumpForce * Time.deltaTime);
            jumpNum++;
        }   
    }
    void Climb(float verticalMove)//爬墙代码
    {
        rig.velocity = new Vector2(rig.velocity.x,climbSpeed * verticalMove* Time.deltaTime);//输入x,y向量,数值*方向
    }
    void changeAnimator()//动画切换
    {
        if (onGround)//如果在地上
        {
            Anim.SetFloat("speed", Mathf.Abs(rig.velocity.x));//速度是向量
        }
        if (onWall)//如果在墙上
        {
            Anim.SetBool("wall", true);//肯定是碰到墙
            if (Anim.GetBool("ground") == false)//如果是跳跃状态下碰到墙,就把碰到地面设为真,方便转换到idle状态
            {
                Anim.SetBool("ground", true);
            }
        }
        else
        {
            Anim.SetBool("wall", false);
        }
        if (onJumping)//如果在跳跃中
        {
            if (Anim.GetBool("ground"))//第一次跳
            {
                falling = true;
                Anim.SetBool("ground", false);
            }
            else 
            {
                if (falling&&isGround())//如果下落碰地,意为要转变到落地状态
                {
                    Anim.SetBool("ground", true);
                    jumpNum = 0;//落地的话,当前跳跃次数清零
                    falling = false;
                    onJumping = false;
                    onGround = true;
                }
                else if(rig.velocity.y < 0)//如果速度为下落,则设置下落状态为true
                {
                    falling = true;
                }
            }

        }
    }
    void OnDrawGizmos()//绘制辅助线
    {
        Gizmos.color = Color.red;//辅助线颜色
        //绘制圆形辅助线
        Gizmos.DrawWireSphere((Vector2)transform.position + bottomOffset, collisionRadius);
        Gizmos.DrawWireSphere((Vector2)transform.position + rightOffset, collisionRadius);
        Gizmos.DrawWireSphere((Vector2)transform.position + leftOffset, collisionRadius);
    }
}

 

你可能感兴趣的:(unity学习)