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
  3. Join us on November 16th, 2023, between 1 pm and 9 pm CET for Ask the Experts Online on Discord and on Unity Discussions.
    Dismiss Notice

Platformer can't detect ground?

Discussion in 'Physics' started by asacafrw35tyth, Sep 3, 2016.

  1. asacafrw35tyth

    asacafrw35tyth

    Joined:
    Nov 17, 2015
    Posts:
    8
    Basically, I'm trying to make a 2D platformer. I need to be able to tell if players are grounded to determine if they can jump, to do this I set a trigger under the player to check if he's on the ground (although the same problem applies to raycasting down, a method many tutorials suggest).

    If the trigger box extends to the edges of the player's collision box, a collision with the wall at medium speed causes the player to glitch inside the wall for a frame and the trigger registers a hit. If the trigger doesn't extend to the edges on the collision box, then it's possible for the player to land on a platform (player collider touches platform collider) but the smaller ground trigger doesn't touch the platform, so the game thinks the player hasn't landed on the ground.

    It seems like the box collider on my character must have a notion of "grounded" because it knows not to accelerate through the floor that I'm standing on. Is there a way to tap into that and use it for my purposes?

    I'm really at a loss here. This seems like such a simple mechanic but I can't get it to implement properly. Any help is appreciated.
     
    Last edited: Sep 3, 2016
  2. Cybearg

    Cybearg

    Joined:
    Jan 18, 2015
    Posts:
    46
    I'd also be interested in hearing peoples' solutions, but as far as I know the ideal solution would be to not use a raycast OR a trigger, but instead just use your character's collider.

    When a collider contacts a surface, it returns a collision (this applies to 2D and 3D), such as in OnCollisionStay2D(), which includes an array of ContactPoints called contacts. From this, you can get all the Vector3/2's showing everywhere that your character's collider is touching another collider. You'll probably need a dummy game object at your character's feet to specify what you consider to be "ground".

    From there, find the Dot Product of the upward Vector and the normalized difference between the contact point(s) Vector3 and the Vector3 of your ground dummy object, something like this:
    Code (CSharp):
    1. ContactPoint2D contactPoint = ...;
    2. bool grounded = false;
    3. Vector3 contactVector = contactPoint.point;
    4. Vector3 groundVector = myGroundVectorTransform.position;
    5. Vector3 differenceVector = (groundVector - contactVector).normalized;
    6. float dotProduct = Vector3.Dot(Vector3.up, differenceVector);
    7. if (dotProduct > 0) { // myGroundVector is above the contact point, meaning the character's "feet" are resting on the "ground"
    8.   grounded = true;
    9. }
    If the Dot Product for one of the contact points is > 0, that means that the vector from the ground vector to the contact point vector is facing the same direction as Vector3.up. In other words, your character's ground-point is above the contact point. Since the ground-point is basically at the player's feet, this can only mean that your character is standing on something. Feel free to add in comparing tags or layers to confirm that the player is standing on "ground" and not some other random collider (like the top of an enemy's head, for instance).

    Also watch this excellent video about Dot Products (and then watch the whole series, because it's superb).

    People with more experience, please correct me if I'm wrong.