Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice

Character Controller movement on inverted/upside down slopes.

Discussion in 'Scripting' started by TheDuples, Jun 14, 2022.

  1. TheDuples

    TheDuples

    Joined:
    Nov 13, 2018
    Posts:
    39
    So basically I'm trying to implement a gravity switching mechanic into a 3D Platformer. When my character controller moves on a slope while affected by regular y gravity, I have no issue. The character stays attached to the slope and doesn't bounce or slide when moving downhill. When I move down a slope in the inverted y gravity however, the character moves very fast, and when I remain still, it slowly slides down the slope. I don't understand why it's doing this, since gravity, jumping, gliding, ground checks and everything else works perfectly fine with the inverted gravity. Moving up a slope also doesn't behave weirdly, just moving down.

    This is my code I use to detect a slope. When gravity is inverted, I am raycasting up because the Unity character controller cannot rotate, so I visually rotate the player model but not the collider itself:
    Code (CSharp):
    1. private bool OnSlope()
    2.     {
    3.         RaycastHit hit;
    4.         if(yGravity)
    5.         {
    6.             if (Physics.Raycast(transform.position, Vector3.down, out hit, myController.height / 2 * slopeForceRayLength))
    7.             {
    8.  
    9.                 if (hit.normal != Vector3.up)
    10.                 {
    11.                     onSlope = true;
    12.                     return true;
    13.                 }
    14.             }
    15.         }
    16.         if(yGravityInverted)
    17.         {
    18.             if (Physics.Raycast(transform.position, Vector3.up, out hit, myController.height / 2 * slopeForceRayLength))
    19.             {
    20.  
    21.                 if (hit.normal != Vector3.down)
    22.                 {
    23.                     onSlope = true;
    24.                     return true;
    25.                 }
    26.             }
    27.         }
    28.         onSlope = false;
    29.         return false;
    30.     }
    This is the movement code I use when on a slope to add a downwards force to stop bouncing:
    Code (CSharp):
    1. //yGravity slope
    2.         if((vertInput != 0 || horizInput != 0) && OnSlope() && grounded && yGravity)
    3.         {
    4.             myController.Move(Vector3.down * myController.height / 2 * slopeForce * Time.deltaTime);
    5.         }
    6.         //yGravityInverted slope
    7.         if((vertInput != 0 || horizInput != 0) && OnSlope() && grounded && yGravityInverted)
    8.         {
    9.             UnityEngine.Debug.Log("On Inverted Slope");
    10.             myController.Move(Vector3.up * myController.height / 2 * slopeForce * Time.deltaTime);
    11.         }
    This is the gravity code I am using. The if statements on playerVelocity are simply there to check if the player is moving up in their jump or moving down, where I then adjust the gravity scale depending on which is occurring.
    Code (CSharp):
    1. if(yGravity)
    2.         {
    3.             if(playerVelocity.y >= 0f)
    4.             {
    5.                 playerVelocity.y += gravity*upwardVelocityGravityScale * Time.deltaTime;
    6.             }
    7.             if(playerVelocity.y < 0f)
    8.             {
    9.                 playerVelocity.y += gravity*downwardVelocityGravityScale * Time.deltaTime;
    10.             }
    11.         }
    12.        
    13. else
    14.         {
    15.             if(playerVelocity.y <= 0f)
    16.             {
    17.                 playerVelocity.y -= gravity*upwardVelocityGravityScale * Time.deltaTime;
    18.             }
    19.             if(playerVelocity.y > 0f)
    20.             {
    21.                 playerVelocity.y -= gravity*downwardVelocityGravityScale * Time.deltaTime;
    22.             }
    23.  
    24.         }
    25.  
    Can someone please assist me in understanding why my character is behaving so strangely on upside down slopes?
     
  2. spiney199

    spiney199

    Joined:
    Feb 11, 2021
    Posts:
    6,003
    So the first thing I can suggest is that you don't need to re-write nearly portions of code for normal and inverted gravity. I would put the gravity direction behind a property that returns a value based on whether gravity is inverted or not, like so:
    Code (CSharp):
    1. public Vector3 GravityDirection
    2. {
    3.     return invertedGravity == false ? Vector3.up : Vector3.down;
    4. }
    Next... are you using both a rigid body and a character controller component? You should really only be using one or the other; otherwise they will interfere.
     
  3. TheDuples

    TheDuples

    Joined:
    Nov 13, 2018
    Posts:
    39
    I am only using a character controller component.
     
  4. spiney199

    spiney199

    Joined:
    Feb 11, 2021
    Posts:
    6,003
    Yeah misread your code; my bad. Nonetheless first thing would be to consolidate your code to not be doubled up, to remove the possibility of an error there.

    Then next I would check you aren't calling CharacterController.Move() more than once per frame, which it looks like you may be if you're moving the character based on the slope of the ground and then again for the player movement.

    Build a direction based on gravity, inputs, etc, and pass that into .Move() all at the end.
     
  5. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,947
    The reason Spiney points this out is as follows:

    I wrote about this before: the Unity example code in the API no longer jumps reliably (because it calls Move() twice per frame).

    I reported it to Unity via their docs feedback in October 2020. Apparently it is still broken:

    https://docs.unity3d.com/ScriptReference/CharacterController.Move.html

    Here is a work-around:

    https://forum.unity.com/threads/how...racter-movement-in-unity.981939/#post-6379746

    I recommend you also go to that same documentation page and ALSO report that the code is broken.

    When you report it, you are welcome to link the above workaround. One day the docs might get fixed.