SlopeMovement

 avatar
unknown
plain_text
a year ago
3.2 kB
13
Indexable
using UnityEngine;

public class SlopeMovement : MonoBehaviour
{
    [Header("Slope Settings")]
    [SerializeField] private float slopeCheckDistance = 0.5f;
    [SerializeField] private float maxSlopeAngle = 45f;
    [SerializeField] private PhysicsMaterial2D noFriction;
    [SerializeField] private PhysicsMaterial2D fullFriction;
    [SerializeField] private LayerMask whatIsGround;

    private Rigidbody2D rb;
    private CapsuleCollider2D cc;

    private bool isOnSlope;
    private bool canWalkOnSlope;
    private float slopeDownAngle;
    private float slopeSideAngle;
    private float lastSlopeAngle;

    private Vector2 slopeNormalPerpendicular;
    private Vector2 capsuleColliderSize;

    void Start()
    {
        rb = GetComponent<Rigidbody2D>();
        cc = GetComponent<CapsuleCollider2D>();
        capsuleColliderSize = cc.size;
    }

    void FixedUpdate()
    {
        Vector2 checkPos = transform.position - new Vector3(0.0f, capsuleColliderSize.y / 2);

        SlopeCheckHorizontal(checkPos);
        SlopeCheckVertical(checkPos);
        ApplySlopeFriction();
    }

    private void SlopeCheckHorizontal(Vector2 checkPos)
    {
        RaycastHit2D slopeHitFront = Physics2D.Raycast(checkPos, transform.right, slopeCheckDistance, whatIsGround);
        RaycastHit2D slopeHitBack = Physics2D.Raycast(checkPos, -transform.right, slopeCheckDistance, whatIsGround);

        isOnSlope = slopeHitFront || slopeHitBack;

        if (slopeHitFront)
        {
            Debug.Log("slopeHitFront");
            slopeSideAngle = Vector2.Angle(slopeHitFront.normal, Vector2.up);
        }
        else if (slopeHitBack)
        {
            Debug.Log("slopeHitBack");
            slopeSideAngle = Vector2.Angle(slopeHitBack.normal, Vector2.up);
        }
        else
        {
            slopeSideAngle = 0f;
        }
    }

    private void SlopeCheckVertical(Vector2 checkPos)
    {
        RaycastHit2D hit = Physics2D.Raycast(checkPos, Vector2.down, slopeCheckDistance, whatIsGround);

        if (hit)
        {
            slopeNormalPerpendicular = Vector2.Perpendicular(hit.normal).normalized;
            slopeDownAngle = Vector2.Angle(hit.normal, Vector2.up);

            if (slopeDownAngle != lastSlopeAngle)
            {
                isOnSlope = true;
            }

            lastSlopeAngle = slopeDownAngle;

            canWalkOnSlope = slopeDownAngle <= maxSlopeAngle && slopeSideAngle <= maxSlopeAngle;
        }
    }

    private void ApplySlopeFriction()
    {
        if (isOnSlope && canWalkOnSlope && rb.velocity.x == 0)
        {
            rb.sharedMaterial = fullFriction;
        }
        else
        {
            rb.sharedMaterial = noFriction;
        }
    }

    private void OnDrawGizmos()
    {
        Vector2 checkPos = transform.position - new Vector3(0.0f, capsuleColliderSize.y / 2);

        Gizmos.color = Color.blue;
        Gizmos.DrawLine(checkPos, checkPos + Vector2.right * slopeCheckDistance);
        Gizmos.DrawLine(checkPos, checkPos + Vector2.left * slopeCheckDistance);
        Gizmos.DrawLine(checkPos, checkPos + Vector2.down * slopeCheckDistance);
    }
}
Editor is loading...
Leave a Comment