Search Unity

Resolved Unity 3d Rigidbody going up stairs

Discussion in 'Editor & General Support' started by MinhocaNice, May 30, 2021.

  1. MinhocaNice

    MinhocaNice

    Joined:
    May 3, 2020
    Posts:
    249
    I followed this tutorial to make so that my character in my FPS game can go up stairs using Rigidbody instead of CharacterController due to it's limitations (namely not being able to change the shape of it's collider), and uh... It didn't work :p.



    I made another thread earlier trying to make so the player can go up stairs in all directions:

    https://forum.unity.com/threads/physics-checksquare-unity-3d.1113988/#post-7182724

    I modified the video's solution by using a Physics.CheckBox instead of Physics.Raycast, but it just... Didn't work. The raycast solution wasn't working properly either.

    Basically, no matter what value I put for the size of the check box, it is very glitchy and can't really detect well the stairs, even if they are right in front of the player. I checked the code and couldn't find any issues with it, and indeed when I make the box insanely long it does detect the stairs from afar (the player sort of keeps bumping upwards), it just can't make the player properly climb them. I was able to go through one of the stairs I used to test in a very specific direction though.

    I don't know what the issue is so I will just put the code here and say what I know is not the issue because I tested:

    Code (CSharp):
    1.     [Header("Steps and slopes")]
    2.     public Transform StepCheckHigher; //If the step is taller than this object, it should not be climbed automatically//
    3.     public Transform StepCheckLower; //Checks for obstacles//
    4.     public Vector3 StepCheckHigherSize; //How far the lower step ray checks for an obstacle//
    5.     public Vector3 StepCheckLowerSize; //How far the lower step ray checks for an obstacle//
    6.     public float StepHeight = 0.4f; //How tall an obstacle can be so the player can step up automatically//
    7.     public float StepAmount = 0.1f; //How much the player climbs up steps//
    Inside of
    void Start()
    :
    Code (CSharp):
    1.         StepCheckHigher.position = new Vector3(StepCheckLower.position.x, StepCheckLower.position.y + StepHeight, StepCheckLower.position.z);
    Inside of
    void FixedUpdate()
    :
    Code (CSharp):
    1.         if (Player.PlayerMovementStatus != PlayerStats.PlayerState.Standing)
    2.         {
    3.             StepClimb();
    4.         }
    Code (CSharp):
    1.     void StepClimb()
    2.     {
    3.         if (Physics.CheckBox(StepCheckLower.position, StepCheckLowerSize, StepCheckLower.rotation, SolidLayer))
    4.         {
    5.             if (!Physics.CheckBox(StepCheckHigher.position, StepCheckHigherSize, StepCheckHigher.rotation, SolidLayer))
    6.             {
    7.                 PlayerRigidbody.position += new Vector3(0f, StepAmount * Time.deltaTime, 0f);
    8.             }
    9.         }
    10.     }
    - It can't be due to the
    if
    inside of
    void FixedUpdate()
    checking if the player is standing or not because it glitches out even while the player is clearly moving;
    - It can't be due to the size of the check box, because even with different sizes the same issue appears;
    - It can't be due to the player's own collider interacting with the check box because the player moves just fine around outside of stairs;
    - It can't be due to the
    StepAmount
    value being too low, because I already tested with different values and it still doesn't work properly;
    - It can't be due to the stairs themselves because I tested stairs of different sizes and shapes and they all have the same issue;

    So how do I fix that?
     
  2. MinhocaNice

    MinhocaNice

    Joined:
    May 3, 2020
    Posts:
    249
    Any ideas?
     
  3. MinhocaNice

    MinhocaNice

    Joined:
    May 3, 2020
    Posts:
    249
    How do I make the rigidbodies go upstairs in FP perspective?
     
  4. MinhocaNice

    MinhocaNice

    Joined:
    May 3, 2020
    Posts:
    249
    Does anyone know what to do?
     
  5. MinhocaNice

    MinhocaNice

    Joined:
    May 3, 2020
    Posts:
    249
    I gave up on this.
     
  6. AshwinTheGammer

    AshwinTheGammer

    Joined:
    Sep 23, 2016
    Posts:
    69
    Update? Did u find any solution?
     
  7. Kreshi

    Kreshi

    Joined:
    Jan 12, 2015
    Posts:
    446
    In general I recommend to use Physics.SphereCast and choose as your sphercast position:
    yourPlayerPositionOnGround + yourMovingDirectionNormalizd * (yourPlayerRadius + lookAheadOffset + sphereCastRadius) + yourPlayerUpVector * yourStepHeight + sphereCastRadius.

    For your spherecast distance you use: yourStepHeight.

    Please take into consideration that I didn't test the above recommendation and that it is from the top of my head :).

    While the approach of modifying the position of your rigidbody directly may work well enough, my personal taste is to calculate a force based on the distance that the spherecast/raycast detects to the ground and apply the correct force accordingly.
     
    AshwinTheGammer likes this.
  8. AshwinTheGammer

    AshwinTheGammer

    Joined:
    Sep 23, 2016
    Posts:
    69
    I'm coding it right now. Would this work even if the stairs height isn't same? should sphereCastRadius and yourStepHeight be big or small?
    actually, never worked with it before... :p...

    Did you mean the origin is gonna be this: yourPlayerPositionOnGround + yourMovingDirectionNormalizd * (yourPlayerRadius + lookAheadOffset + sphereCastRadius) + yourPlayerUpVector * yourStepHeight + sphereCastRadius. ? whole?
     
  9. Kreshi

    Kreshi

    Joined:
    Jan 12, 2015
    Posts:
    446
    It should work independently from stairs having different heights because you use the spherecast to measure the distance you have to step-up.

    Yes, this will be the origin of your SphereCast. Check out the image below explaining how you are using the SphereCast to measure the height of the stair that you want to step-up.

    upload_2023-1-12_11-28-17.jpeg

    You do the SphereCast to find "searched height to step up".

    Regarding sphereCastRadius, you can choose something like 0.15 * yourPlayerRadius.
    Regarding yourStepHeight, this is the maximum height the player will be able to step-up so if you want to climb 0.5m set this to 0.5.
     
    AshwinTheGammer likes this.
  10. AshwinTheGammer

    AshwinTheGammer

    Joined:
    Sep 23, 2016
    Posts:
    69
    So, basically my whole day wasted :p...will try again tomorrow...
    I understood the spherecast i guess, when the sphere hits the something it send info to 'RaycastHit hit' to store

    and this is what i understood so far...
    am i right?

    when i tried this yourPlayerPositionOnGround + yourMovingDirectionNormalizd * (yourPlayerRadius + lookAheadOffset + sphereCastRadius) + yourPlayerUpVector * yourStepHeight + sphereCastRadius
    it showed cant convert vector3 to float


    this is what my code looks now


    Code (CSharp):
    1.  
    2. Vector2 input = GetInput();
    3.  
    4.             if ((Mathf.Abs(input.x) > float.Epsilon || Mathf.Abs(input.y) > float.Epsilon))
    5.             {
    6.                 // Always move along the camera forward as it is the direction that it being aimed at
    7.                 Vector3 desiredMove = playerCamera.transform.forward * input.y + playerCamera.transform.right * input.x;
    8.                // Vector3 desiredMove = gameObject.transform.forward * input.y + gameObject.transform.right * input.x;
    9.                 desiredMove = Vector3.ProjectOnPlane(desiredMove, groundContactNormal).normalized;
    10.              
    11.             RaycastHit hit;
    12.             Vector3 sphereCastPos = transform.position + capsuleCol.center - new Vector3(0, capsuleCol.height / 2, 0) +
    13.                                 (desiredMove* (capsuleCol.radius + lookAheadOffset + sphereCastRadius)) +
    14.                                 (transform.up * stepHeight) + Vector3.up * sphereCastRadius;
    15.             if (Physics.SphereCast(sphereCastPos, sphereCastRadius, Vector3.down, out hit, 10f))
    16.             {
    17.             // Check if the sphere hit a stair
    18.             if (hit.collider.CompareTag("Stair"))
    19.             {
    20.                 // Add upward force to the rigidbody to move it up the stair
    21.                 float distance = 10f - Vector3.Distance(sphereCastPos, hit.point);
    22.                 rigidBody.AddForce(Vector3.up * (distance + stepHeight) * 2f, ForceMode.Acceleration);
    23.                 rigidBody.drag = 0f;
    24.                 //rigidBody.velocity = new Vector3(rigidBody.velocity.x, 0f, rigidBody.velocity.z);
    25.                 //transform.position += new Vector3(0,Vector3.up * (distance + stepHeight) * 2f, 0)* Time.deltaTime * currentSpeed;
    26.             }
    27.  
     

    Attached Files:

  11. Kreshi

    Kreshi

    Joined:
    Jan 12, 2015
    Posts:
    446
    use it like that: yourPlayerPositionOnGround + yourMovingDirectionNormalizd * (yourPlayerRadius + lookAheadOffset + sphereCastRadius) + yourPlayerUpVector * (yourStepHeight + sphereCastRadius).

    I added the bracket^^.
    Also consider calculating your required step-height with distanceOfRayToCast - hit.distance.
    This is the simpler version. In case you want to use the more precise hit.point, you have to use this formula:

    Vector3 distVecToHitPoint = hit.point - sphereCastPos;
    Vector3 projDistVecToHitPoint = Vector3.Project(projDistVecToHitPoint, Vector3.down); // you used Vector3.down as your cast-direction
    float distanceTraveledFromSphereTip = projDistVecToHitPoint.magnitude - sphereCastRadius;
    float distanceToStepUp = sphereCastDistance - distanceTraveledFromSphereTip; // you used 10.0f as sphereCastDistance which is way too much for normal sized characters. 0.5f is about the average you can step-up

    Using a Raycast instead of a SphereCast to solve this problem is by the way also a valid approach :).
     
    AshwinTheGammer likes this.
  12. MinhocaNice

    MinhocaNice

    Joined:
    May 3, 2020
    Posts:
    249
    No, I remade the movement of my game using CharacterController instead.
     
  13. cafeho

    cafeho

    Joined:
    Jun 4, 2022
    Posts:
    2
    Hey, for me I found that following the video at the top of the post was generally correct, but there were some bugs.

    1. In the Awake function, I changed the y component of the new Vector3 to stepRayLower.transform.position.y + stepHeight. This ensures the upper ray cast is always above the lower ray cast.

    2. Make sure the raycast rotates with the player object. I have a hierarchy set up where I seperate my player logic (rigidbody) from my model. I childed the raycast gameobjects under my model.

    3. This generally fixes the problem, but I also found that increasing the Max Distance of the 6 raycasts helps. I set up a common variable for the lower raycast and the upper raycast to easily adjust.

    3. Finally, I wanted to walk up the stairs by player input, so I replaced the direction of each raycast with a Vector3(horizontalMoveInput,0,verticalMoveInput). For the 45 degree raycasts, I multipied the vector3 with Quaternion.Euler(0,45,0) or Quaternion.Euler(0,-45,0).

    After that, it should be all good. Just play around with the values until you get something you like. I hope that this helps anyone struggling on this problem, as I have for 2 days