Search Unity

Collision issues following Unity's platformer controls tutorials

Discussion in 'Physics' started by EstragonHelmer, Aug 16, 2019.

  1. EstragonHelmer

    EstragonHelmer

    Joined:
    Oct 26, 2017
    Posts:
    12
    I've been building a pretty simple platformer, and followed these tutorials for my player controls - https://learn.unity.com/tutorial/live-session-2d-platformer-character-controller

    I've noticed a bug that I can't pin down because it happens so rarely I can't figure out the cause. It also happens so rarely, I haven't managed to capture a recording of it, so I'll try to describe it.

    Sometimes it happens when the player is standing near a wall, and jumps up against it. The player then passes diagonally up and through the wall very slowly until they're standing on top of the block.

    Sometimes it happens when they're jumping alongside a wall. So, if they're stood with the end of a platform above them, and to one side, they should be able to jump up past it, as they don't actually hit it. But sometimes, they sort of hit it, and stop going up, but also don't fall down. So they just sort of hover for the length of a full jump before falling back down.

    It was a long time ago in the development that I followed the tutorial, so I can't remember every minor change, but I think all I changed was to add in my pause system.

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class PhysicsObject : MonoBehaviour {
    6.  
    7.     //gravity
    8.     public float gravityModifier = 1f;
    9.     protected bool grounded;
    10.     protected Vector2 groundNormal;
    11.     public float minGroundNormalY = 0.65f;
    12.  
    13.     //movement
    14.     protected Rigidbody2D myRigidbody;
    15.     protected Vector2 targetVelocity;
    16.     protected Vector2 velocity;
    17.     protected const float minMoveDistance = 0.001f;
    18.     protected float moveVelocity = 0f;
    19.  
    20.     //speed up slow down
    21.     protected float SpeedUp = 0.1f;
    22.     protected float groundSlowDown = 0.05f;
    23.     protected float airSlowDown = 0.2f;
    24.  
    25.     //collisions
    26.     protected ContactFilter2D contactFilter;
    27.     protected RaycastHit2D[] hitBuffer = new RaycastHit2D[16];
    28.     protected List<RaycastHit2D> hitBufferList = new List<RaycastHit2D> (16);
    29.     protected const float shellRadius = 0.01f;
    30.  
    31.     //pause system
    32.     protected PauseSystem pauseSystem;
    33.  
    34.     void OnEnable ()
    35.     {
    36.         //get rigidbody
    37.         myRigidbody = GetComponent<Rigidbody2D> ();
    38.     }
    39.  
    40.     protected void Start ()
    41.     {
    42.         //set up contact filter
    43.         contactFilter.useTriggers = false;
    44.         contactFilter.SetLayerMask (Physics2D.GetLayerCollisionMask (gameObject.layer));
    45.         contactFilter.useLayerMask = true;
    46.  
    47.         //get pause system
    48.         pauseSystem = FindObjectOfType<PauseSystem> ();
    49.     }
    50.  
    51.     protected void Update ()
    52.     {
    53.         targetVelocity = Vector2.zero;
    54.         ComputeVelocity ();
    55.     }
    56.  
    57.     protected virtual void ComputeVelocity ()
    58.     {
    59.        
    60.     }
    61.  
    62.     protected void FixedUpdate ()
    63.     {
    64.         if (!pauseSystem.isPaused || pauseSystem.gameEnd)
    65.         {
    66.             //movement
    67.             velocity += gravityModifier * Physics2D.gravity * Time.deltaTime;
    68.             if (targetVelocity.x != 0)
    69.                 velocity.x = Mathf.SmoothDamp (velocity.x, targetVelocity.x, ref moveVelocity, SpeedUp);
    70.             else
    71.                 velocity.x = Mathf.SmoothDamp (velocity.x, targetVelocity.x, ref moveVelocity, grounded ? groundSlowDown : airSlowDown);
    72.  
    73.             grounded = false;
    74.  
    75.             Vector2 deltaPosition = velocity * Time.deltaTime;
    76.             Vector2 moveAlongGround = new Vector2 (groundNormal.y, -groundNormal.x);
    77.  
    78.             //horizontal
    79.             Vector2 move = moveAlongGround * deltaPosition.x;
    80.             Movement (move, false);
    81.  
    82.             //vertical
    83.             move = Vector2.up * deltaPosition.y;
    84.             Movement (move, true);
    85.         }
    86.     }
    87.  
    88.     void Movement (Vector2 move, bool yMovement)
    89.     {
    90.         //get movement distance
    91.         float distance = move.magnitude;
    92.  
    93.         //collision check
    94.         if (distance > minMoveDistance)
    95.         {
    96.             int count = myRigidbody.Cast (move, contactFilter, hitBuffer, distance + shellRadius);
    97.  
    98.             hitBufferList.Clear ();
    99.             for (int i = 0; i < count; i++)
    100.                 hitBufferList.Add (hitBuffer [i]);
    101.  
    102.             for (int i = 0; i < hitBufferList.Count; i++)
    103.             {
    104.                 Vector2 currentNormal = hitBufferList [i].normal;
    105.  
    106.                 //grounded
    107.                 if (currentNormal.y > minGroundNormalY)
    108.                 {
    109.                     grounded = true;
    110.                     if (yMovement)
    111.                     {
    112.                         groundNormal = currentNormal;
    113.                         currentNormal.x = 0f;
    114.                     }
    115.                 }
    116.  
    117.                 //collision
    118.                 float projection = Vector2.Dot (velocity, currentNormal);
    119.                 if (projection < 0f)
    120.                 {
    121.                     velocity = velocity - projection * currentNormal;
    122.                 }
    123.  
    124.                 float modifiedDistance = hitBufferList [i].distance - shellRadius;
    125.                 distance = modifiedDistance < distance ? modifiedDistance : distance;
    126.             }
    127.         }
    128.  
    129.         //move rigidbody
    130.         myRigidbody.position = myRigidbody.position + move.normalized * distance;
    131.     }
    132. }
    133.