Unity 3D-爬坡脚本无法正常工作? C#

时间:2018-12-15 17:40:26

标签: c# unity3d

在这里,我正在尝试制作一个简单的2D平台游戏。我为此尝试了这个YouTube频道(https://www.youtube.com/watch?v=cwcC2tIKObU)系列教程。在视频中进行同样的操作后,我无法将播放器移到斜坡上。这是我的脚本,如果有人可以帮助我,那么请..

问题: 有时玩家会进入斜坡的一半,但我不能顺利地爬上斜坡。如下图所示。有时玩家与斜坡的接触很少而倒下。

Image show player can not climb on slop.

Controller2D.cs `

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

public class Controller2D : MonoBehaviour {

    /// <summary>
    /// -------------------------------------------------------------------------------------
    /// Declaring all variables here
    /// -------------------------------------------------------------------------------------
    /// </summary>

    public LayerMask collisionMask; //rays collide with this layer
    const float skinWidth = 0.015f;
    public int horizontalRayCount = 4, verticalRayCount = 4; //int for determine how many rays are being fire in horizontally and vertically
    float horizontalRaySpacing, verticalRaySpacing; //calculate space between horizontal and verticall rays.
    private BoxCollider2D collider;
    private RaycastOrigins raycastOrigins;//Making reference of method RaycastOrigins
    public CollisionInfo collisions;//Making reference of method collsioninfo
    float maxClimbAngle = 80f; // Max climb angle between player and surface

    /// <summary>
    /// /// -------------------------------------------------------------------------------------
    /// Starting game 2D controller coding from here.
    /// /// -------------------------------------------------------------------------------------
    /// </summary>


    void Start()
    {
        collider = GetComponent<BoxCollider2D> ();
        CalculateRaySpacing ();
    }

    void Update()
    {       
    }

    public void Move(Vector3 velocity)
    {
        UpdateRaycastOrirgins ();

        //Resetting all bool of collisionInfo method
        collisions.Reset();

        //Updatting rays that collision with player horizontally using referrence
        if (velocity.x != 0)
            HorizontalCollisions (ref velocity);

        //Updatting rays that collision with player vertically using referrence
        if (velocity.y != 0)
            VerticalCollisions (ref velocity);

        transform.Translate (velocity);
    }


    /// <summary>
    /// -------------------------------------------------------------------------------------
    /// We are detectin here a horizontal collsition of rays with player and surface
    /// //In this function player move horizontally, so We need to use only horizontal direction
    /// If player move forward then We can calculate the distance between player and surface and also can calculate distance
    /// between player and other object like obstacles.
    /// -------------------------------------------------------------------------------------
    /// </summary>
    /// <param name="velocity">Velocity.</param>

    void HorizontalCollisions(ref Vector3 velocity)
    {
        //Setting velocity using Mathf.Sign()
        float directionX = Mathf.Sign(velocity.x);

        //Calculating ray length with adding skinwidth of player
        float raylength = Mathf.Abs (velocity.x) + skinWidth;

        //THis is for drawing rays in horizontal and vertical direction
        for (int i = 0; i < horizontalRayCount; i++) 
        {

            // Making ray from origin (bottomLeft, bottomRight, topLeft, topRight)
            //If directionY is equals to -1 then raycast origin is bottom left otherwise top left is origin
            //Only bottomLeft or topLeft is because of negative value of Mathf.Sign()

            Vector2 rayOrigin = (directionX == -1)?raycastOrigins.bottomLeft : raycastOrigins.bottomRight;
            rayOrigin += Vector2.up * (horizontalRaySpacing * i);
            RaycastHit2D hit = Physics2D.Raycast (rayOrigin, Vector2.right * directionX, raylength, collisionMask);


            Debug.DrawRay (rayOrigin, Vector2.right * directionX * raylength, Color.red);

            //Adding vertical velocity after deducting player skin width
            if (hit) {

                //Calculating slopeANgle here
                float slopeAngle = Vector2.Angle(hit.normal, Vector2.up);
                if (i == 0 && slopeAngle <= maxClimbAngle) {
                    print ("Slope angle : " + slopeAngle);
                    climbSlope(ref velocity, slopeAngle);
                }


                velocity.x = (hit.distance - skinWidth) * directionX;
                raylength = hit.distance;

                //First checking direction of player movement, Horizontally  positive or negative and then change bool to true
                // of CollisionInfo method
                collisions.left = directionX == -1;
                collisions.right = directionX == 1;
            }


        }
    }


    /// <summary>
    /// /// -------------------------------------------------------------------------------------
    /// We are detectin here a vertical collsition of rays from player to surface
    /// If player make any jump then ve can calculate the distance between player and surface and also can calculate distance
    /// between player other object like obstacles.
    /// -------------------------------------------------------------------------------------
    /// </summary>
    /// <param name="velocity">Velocity.</param>
    void VerticalCollisions(ref Vector3 velocity)
    {
        //Setting vertical velocity using Mathf.Sign()
        float directionY = Mathf.Sign(velocity.y);


        //Calculating ray length with adding skinwidth of player
        float raylength = Mathf.Abs (velocity.y) + skinWidth;


        //THis is for drawing rays in horizontal and vertical direction
        for (int i = 0; i < verticalRayCount; i++) 
        {

            // Making ray from origin (bottomLeft, bottomRight, topLeft, topRight)
            //If directionY is equals to -1 then raycast origin is bottom left otherwise top left is origin
            //Only bottomLeft or topLeft is because of negative value of Mathf.Sign()

            Vector2 rayOrigin = (directionY == -1)?raycastOrigins.bottomLeft : raycastOrigins.topLeft;

            rayOrigin += Vector2.right * (verticalRaySpacing * i * velocity.x);

            RaycastHit2D hit = Physics2D.Raycast (rayOrigin, Vector2.up * directionY, raylength, collisionMask);


            Debug.DrawRay (rayOrigin, Vector2.up * directionY * raylength, Color.red);

            //Adding vertical velocity after deducting player skin width
            if (hit) {
                velocity.y = (hit.distance - skinWidth) * directionY;
                raylength = hit.distance;

                //First checking direction of player movement, vertically  positive or negative and then change bool to true
                // of CollisionInfo method
                collisions.below = directionY == -1;
                collisions.above = directionY == 1;
            }


        }
    }

    /// <summary>
    /// This method is use to make player able to climb on slope
    /// slope calculation done by using trianble formula like y = moveDistance * sin() and x = moveDistance * cos()
    /// </summary>
    /// <param name="velocity">Velocity.</param>
    /// <param name="slopeAngle">Slope angle.</param>


    void climbSlope(ref Vector3 velocity, float slopeAngle)
    {
        float moveDistance = Mathf.Abs (velocity.x);
        float climbVelocityY = Mathf.Sin (slopeAngle * Mathf.Deg2Rad) * moveDistance;

        if (velocity.y <= climbVelocityY) {

            velocity.y = climbVelocityY;
            velocity.x = Mathf.Cos (slopeAngle * Mathf.Deg2Rad) * moveDistance * Mathf.Sign (velocity.x);
            collisions.below = true;
            collisions.climbingslope = true;
        }
    }


    void UpdateRaycastOrirgins()
    {
        Bounds bounds = collider.bounds;

        //Expand the bounds by increasing its size amound along each side.
        bounds.Expand (skinWidth * (-2));

        //Increasing size of bounds
        raycastOrigins.bottomLeft = new Vector2 (bounds.min.x, bounds.min.y);   
        raycastOrigins.bottomRight = new Vector2 (bounds.max.x, bounds.min.y);
        raycastOrigins.topLeft = new Vector2 (bounds.min.x, bounds.max.y);
        raycastOrigins.topRight = new Vector2 (bounds.max.x, bounds.max.y);
    }


    // -------------------------------------------------------------------------------------
    //Calculating the spacing between horizontal and verticall rays.
    //We will get the horizontal and vertical ray spacing by deviding clamped value respectively.
    /// -------------------------------------------------------------------------------------

    void CalculateRaySpacing()
    {
        Bounds bounds = collider.bounds;

        //Expand the bounds by increasing its size amound along each side.
        bounds.Expand (skinWidth * (-2));

        horizontalRayCount = Mathf.Clamp (horizontalRayCount, 2, int.MaxValue);
        verticalRayCount = Mathf.Clamp (verticalRayCount, 2, int.MaxValue);

        //We can get Horizontal/vertical ray spacing by dividing oposite direction bounds size minus 1 with totalraycounts.

        horizontalRaySpacing = bounds.size.y / (horizontalRayCount - 1);
        verticalRaySpacing = bounds.size.x / (verticalRayCount - 1);

    }


    //Create a raycast struct to get rays on player from every sides and corners.

    struct RaycastOrigins
    {
        public Vector2 topLeft, topRight;
        public Vector2 bottomLeft, bottomRight;
    }


    ///<summary>
    /// -------------------------------------------------------------------------------------
    /// Create a new struct for getting info of collision
    /// Getting collision info from above, below, left or right side collision of player
    /// -------------------------------------------------------------------------------------
    /// </summary>

    public struct CollisionInfo
    {
        public bool above, below;
        public bool left, right;
        public bool climbingslope;
        public float slopeangle, slopeangleOld;
        //Resetting all bools to false
        public void Reset()
        {
            above = below = false;
            left = right = false;
            climbingslope = false;

            slopeangleOld = slopeangle;
                slopeangle = 0;
        }
    }

}

Player.cs

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

[RequireComponent (typeof(Controller2D))]
public class Player : MonoBehaviour {

    public float jumpHeight = 4f; //  Vertical height of player jump
    public float timeToJumpAppex = 0.4f;  // Time to reach that jump height
    public float moveSpeed = 1f; 
    float gravity; //custom gravity for player
    Vector3 velocity; //storing velocity in variable
    float jumpVelocity; //Jump variable
    float velocityXsmooth; // For making smooth movement in horizontal direction
    Controller2D controller; // Reference of Controller2D script
    float accelerationTimeToAirborne = 0.2f;
    float accelerationTimetoGrounded = 0.1f;


    void Start()
    {
        controller = GetComponent<Controller2D> ();

        //-----------------------------------------------------------------
        //Currently we do not have gravity so,
        //Calculating gravity by using this equation                      2 * jumpHeight
        //                                              gravity = --------------------------------
        //                                                        (timeToJumpApex * timeToJumpApex)
        //-----------------------------------------------------------------

        gravity = -(2 * jumpHeight) / Mathf.Pow (timeToJumpAppex, 2);
        jumpVelocity = Mathf.Abs (gravity) * timeToJumpAppex;
        Debug.Log ("Gravity: " + gravity + " JumpVelocity: " + jumpVelocity);

    }

    void Update()
    {
        //Player Falling down slowlly after setting vertical velocity to zero
        if (controller.collisions.above || controller.collisions.below) {
            velocity.y = 0;
        }

        var input = new Vector2 (Input.GetAxisRaw("Horizontal"), Input.GetAxisRaw("Vertical"));

        //Making code for jump
        //Player jump by pressing space key

        if (Input.GetKeyDown (KeyCode.Space) && controller.collisions.below)
        {
            velocity.y = jumpVelocity;
        }


        //Getting and setting player velocity here for horizonal and vertical direction.
        //Smothing movement of player at end time.

        float targetVelocityX = input.x * moveSpeed * Time.deltaTime;
        velocity.x = Mathf.SmoothDamp (velocity.x, targetVelocityX, ref velocityXsmooth, (controller.collisions.below) ? accelerationTimetoGrounded : accelerationTimeToAirborne); // smooth movement in X direction

        velocity.y += gravity * Time.deltaTime; 
        controller.Move (velocity * Time.deltaTime);
    }
}

`

0 个答案:

没有答案