Search Unity

The character can hang on flat walls (it should not)

Discussion in '2D' started by joxthebest314, Mar 31, 2020.

  1. joxthebest314

    joxthebest314

    Joined:
    Mar 31, 2020
    Posts:
    95
    We have a problem : when the character in running in front of a wall, it is as if there is no gravity. In addition, the character is a cube with legs, so he can hang on with his chin. I desesparetly search a way to solve both these problems. I tried to make a weird collider to avoid these errors, but it didn't wokt out.

    I am asking for your help. Thanks in advance.






    Capture.PNG Capture2.PNG (second pic) : it should fall, but when running, the force counter the gravity.
     
  2. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,497
    You should post your code (with code-tags) to demonstrate how you're moving the character. It sounds like you're either stomping over gravity when you move by directly modifying velocity or that your move is based upon Rigidbody2D.MovePostiion and not taking grabity into account. There are other possibilities too.

    Can you say if this is something you want or don't want?

    Depending on how accurate you need the collider outline to follow the character, often using a CapsuleCollider2D provides the most optimal simple character collider.
     
    joxthebest314 likes this.
  3. joxthebest314

    joxthebest314

    Joined:
    Mar 31, 2020
    Posts:
    95
    I affirm I don't want the character to hang on walls like that, it should fall. Here is the method for the movements (it is a bit messy, I came up with it myself so it is probably the source of the problem)


    Code (CSharp):
    1.     void Update () {
    2.         if(Input.GetKeyDown("space") && isGrounded == true && isAllowedToMove ==true){
    3.             Jump();
    4.         }
    5. // right Movement
    6.     if(Input.GetKey("right") && isAlive == true && isAllowedToMove ==true){
    7.             vitesse = 7;      
    8.             SetVelocity(vitesse, 0);
    9.             animator.SetBool("isMoving", true);
    10.             animator.SetBool("isMovingBack", false);
    11.     }
    12.     if(Input.GetKeyUp("right")  && isAlive == true && isAllowedToMove ==true && isGrounded==true){
    13.             vitesse = 0;      
    14.             SetVelocity(vitesse, 0);
    15.             animator.SetBool("isMoving", false);
    16.             animator.SetBool("isMovingBack", false);
    17.     }
    18. //Sert à arrêter l'animation de course en vol
    19.     if(Input.GetKeyUp("right")  && isAlive == true && isAllowedToMove ==true && isGrounded==false){
    20.             animator.SetBool("isMoving", false);
    21.             animator.SetBool("isMovingBack", false);
    22.     }
    23.  
    24. // left Movement
    25.     if(Input.GetKey("left")  && isAlive == true && isAllowedToMove ==true){
    26.             vitesse = -7;      
    27.             SetVelocity(vitesse, 0);
    28.             animator.SetBool("isMovingBack", true);
    29.             animator.SetBool("isMoving", false);
    30.     }
    31.     if(Input.GetKeyUp("left")  && isAlive == true && isAllowedToMove ==true && isGrounded==true){
    32.             vitesse = 0;      
    33.             SetVelocity(vitesse, 0);
    34.             animator.SetBool("isMovingBack", false);
    35.             animator.SetBool("isMoving", false);
    36.         }
    37. //Sert à arrêter l'animation de course en vol
    38.     if(Input.GetKeyUp("left")  && isAlive == true && isAllowedToMove ==true && isGrounded==false){
    39.         animator.SetBool("isMovingBack", false);
    40.         animator.SetBool("isMoving", false);
    41.         }
    42.  
    43. }
    44.  
    45. //jump Movement
    46. void Jump(){
    47.         rb.velocity += new Vector2(0, maxJump);
    48.     }
    49.  
    50. void SetVelocity(float xVelocity, float yVelocity){
    51.     rb.velocity = new Vector2(0, rb.velocity.y);
    52.     rb.velocity += new Vector2(xVelocity, yVelocity);
    53. }
     
  4. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,497
    I maintain a 2D Physics repo here which contains many examples, one of which is a simple character controller that shows how to easily maintain the "IsGrounded" state which is very important in controlling when you shouldn't be allowing movement that can cause behaviour like this. In the example, the character can push/jump against walls but won't stick.

    You can find that scene here. The controller script can be found here.

    It might be worth taking a look at the above and seeing if you can adapt it to your needs.
     
    joxthebest314 likes this.
  5. joxthebest314

    joxthebest314

    Joined:
    Mar 31, 2020
    Posts:
    95
    Thank you very much for the example, but do you think the IsGrounded method is the only problem or should I change the whole movement method ?

    I also forgot to show the way I changed the IsGrounded state :

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5.  
    6. public class FeetDetector : MonoBehaviour
    7. {
    8.     private CharacBehavior cB;
    9.     // Start is called before the first frame update
    10.     void Start()
    11.     {
    12.           cB = GameObject.Find("Personnage").GetComponent<CharacBehavior>();
    13.     }
    14.  
    15.     // Update is called once per frame
    16.     void Update()
    17.     {
    18.         Debug.DrawRay(gameObject.transform.position, transform.TransformDirection(Vector3.down) *0.2f, Color.red);
    19.         RaycastHit2D hit = Physics2D.Raycast(gameObject.transform.position, transform.TransformDirection(Vector3.down), 0.2f);
    20.         if(hit.collider !=null && hit.collider.gameObject.CompareTag("Ground")){
    21.             cB.isGrounded = true;
    22.         }
    23.         else{
    24.             cB.isGrounded = false;
    25.         }
    26.     }
    27. }
    28.  
     
  6. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,497
    If you're not grounded then NOT forcing your character into the walls (by directly modifying velocity) should solve your problem. You might be doing something else to cause it but I doubt it. It can't do any harm making your IsGrounded state more reliable though.

    You can also make some of your code simpler btw.

    • "gameObject.transform.position" is just "transform.position"
    • "transform.TransformDirection(Vector3.down)" for your game is just "Vector2.down". All 2D stuff uses Vector2 not Vector3.
    • "if (hit.collider != null)" can be "if (hit)" as RaycastHit2D has an implciit bool operator that does "hit.collider != null" for you.
    • Using "transform.position" for queries is odd because if you use Rigidbody2D interpolation then "transform.position" will not equal "Rigidbody2D.position". The physics only updates during the fixed-update unless you tell it not to. Physics queries related to a position of a Rigidbody2D should always use "Rigidbody2D.position".
    • "hit.collider.gameObject.CompareTag("Ground")" - You should set the query filter to only return the "Ground" layer rather than finding everything. In your code, if you hit anything other than ground, you'll ignore it and then assume you're not grounded. This is incorrect logic. Noet that my character controller doesn't perform spatial queries like this, it checks contacts i.e. "Is it touching any collider on the Ground layer" which is all you really want.
     
    Last edited: Apr 1, 2020
    joxthebest314 likes this.
  7. joxthebest314

    joxthebest314

    Joined:
    Mar 31, 2020
    Posts:
    95
    Thanks a lot I will try all of this. You are awesome.
     
  8. joxthebest314

    joxthebest314

    Joined:
    Mar 31, 2020
    Posts:
    95
    There is still an isue, the character should be able to change direction, even if he is not grounded (like adjusting position while in air ). So desactivate the velocity or equivalent is not possible...
    Maybe have I misunderstood your proposition ?
     
  9. joxthebest314

    joxthebest314

    Joined:
    Mar 31, 2020
    Posts:
    95
    I also figured out that the fiction of the material is one of the causes, but I can't delete it, otherwise my character is going to slide around.
     
  10. joxthebest314

    joxthebest314

    Joined:
    Mar 31, 2020
    Posts:
    95
    After a few tests with your script Ii can confirm that the issue is the friction of the floor. I used it to stop my character right after a jump (beacause he kept the x velocity to jump). Unfortunately I still need the friction to stop the infinite slide my character is doing after a jump. I can't figure out a way to do that without the friction (this is my firts game so I lack of ways to fig bugs hahaha).
     
  11. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,497
    When you know you're grounded then you can apply a force in the direction of motion (or just reduce the velocity directly) when in contact with the floor. This is all that "friction" is doing.

    That said, if you look at the "IsGrounded" example in my repo, all the ground has friction. The character though has no friction but that's not for any reason apart from not wanting friction). Drag the "Bounce_0.0_Friction_0.4" material onto the "GirlAndDog" Rigidbody2D and it still works fine without sticking to walls, ledges etc.
     
    joxthebest314 likes this.
  12. joxthebest314

    joxthebest314

    Joined:
    Mar 31, 2020
    Posts:
    95
    Maybe I did it wrong, but even with your scene I get the same issue... The character still can't fall while running in walls... Capture.PNG
     
  13. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,497
    The above isn't my scene though right? Something is wrong there because you can't be pushing against the wall in the above situation because my demo would show that as not grounded. Is the above with the same controller and ContactFilter2D settings?

    Grounded is only true when the collision normal is coming from below which is the whole point of the demo.
     
    joxthebest314 likes this.
  14. joxthebest314

    joxthebest314

    Joined:
    Mar 31, 2020
    Posts:
    95
    Okay my bad I dit it wrong hahaha. It work in your scene, but (sorry I am new) I don't really understand what makes the character not pushing ( I mean what line of the code, so I can try to reproduce it).
     
  15. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,497
    The controller I provide doesn't need to that. It only use the grounded state to determine if it can jump. It freely sets velocity directly.

    It might be easier to share a simple project which is sticking and I can comment on it. Either host it or DM me with your email and I'll add you to a workspace where you can upload it.
     
    joxthebest314 likes this.
  16. joxthebest314

    joxthebest314

    Joined:
    Mar 31, 2020
    Posts:
    95
    I tried to remove all the stuff from a clone of my game, leaving only the character movements. It would be amazing if you could take a look.

    https://github.com/Jo-Jox/SampleScene
     
  17. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,497
    Looking at the project, this is how you originally had it though. I thought you were using a better controller than the code you first posted.
     
    joxthebest314 likes this.
  18. joxthebest314

    joxthebest314

    Joined:
    Mar 31, 2020
    Posts:
    95
    No, unfortunately all I tried to change failed. Do you think I need to change it fundamentally ?
     
  19. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,497
    I've made some modifications that have fixed your issue. Is there any chance you can give me access to push a branch to your repo? https://github.com/MelvMay-Unity

    If not, I can host the changes somewhere for you.
     
    joxthebest314 likes this.
  20. joxthebest314

    joxthebest314

    Joined:
    Mar 31, 2020
    Posts:
    95
    I gave you the access. Thank you so much for your help, we need more people like you hahaha.
     
  21. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,497
    Pushed.

    This isn't the only way to do this but because you want to continuously set the velocity you're not allowing the solver to move away from contacts so it can slide down the surface.
    • Added Ground Layer and assigned to ground objects
    • Refactored controller to make it a little simpler
    • Explicitly set-up a ContactFilter to look for ground at specific angles of contact normals, i.e. Below, Left & Right grounded checks
    • Only assign left velocity if not touching ground on the left. Same with right. Only jump when grounded below.
    The use of an EdgeCollider2D is kind of strange for a character. Depending on what you want you can use a PolygonCollider2D or most efficient is a CapsuleCollider2D. I do have them on there but they're disabled.
     
    joxthebest314 likes this.
  22. joxthebest314

    joxthebest314

    Joined:
    Mar 31, 2020
    Posts:
    95
    Sorry to bother you again, but I find strange the use of the contact filter. This method gives some errors. The strangest thing is if I try to debug log the state of the IsGroundedBelow, it switches every frame from true to false (even if I just don't moove). I now have problems with some moving platforms, because the state IsGroundedBelow seems not ot work perfectly. Do you have any idea about what is going on ?
     
  23. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,497
    IsTouching just looks at existing contacts. ContactFilter2D just filters them. If it's changing to false then the contact(s) do not exist or they are being filtered because they don't meet the criteria the filter sets.

    Contacts are created/updated when the simulation steps so if you do something that causes contacts to be destroyed such as modifying a collider so it needs to be recreated then contacts won't be around until the next simulation step. If you're checking this each frame then you might have multiple frames inbetween the simulation steps which happen at the fixed-update.

    In the end, you can see the contacts in the inspector. Open up the "Info > Contacts" on any Collider2D / Rigidbody2D and it'll list you every single contact. Play your game and pause it when it's false and you don't expect it to be then just look at the inspector. If you have no contacts then you're doing something to cause that.
     
    joxthebest314 likes this.