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. Dismiss Notice

[Solved] Collision against ground is blocking (tiling)

Discussion in '2D' started by msh91, Mar 2, 2019.

  1. msh91

    msh91

    Joined:
    Apr 22, 2017
    Posts:
    37
    [Solved!]

    I've created a ground using the tile system, with Grid, Tilemap, Tilemap Collider 2D, etc.
    I've created an enemy which is made from a sprite renderer (full square), box collider 2d, and a simple ai that moves in a direction and flip direction on hit (if collider is not ground)

    I have 2 tiles one near each other, at the same height and Y position, yet somehow when my enemy walks from one tile to the other, the collision seems to be a blocking one that doesn't allow him to move anymore.

    I'm attaching an animated gif to show the problem.
    You can also see in the logs it first collides with a crate, at which point it will flip movement direction, and then it will collide with the Tilemap_Base (the one with Tilemap, Tilemap Renderer and Tilemap Collider 2D components), at which point it will stop moving.

    How do I fix this? why is it even happening?
     

    Attached Files:

    • bug.gif
      bug.gif
      File size:
      711.5 KB
      Views:
      1,290
    Last edited: Mar 6, 2019
  2. Nivbot

    Nivbot

    Joined:
    Mar 21, 2015
    Posts:
    65
    I think you’ll need to show your movement code to really show what’s happening
     
  3. msh91

    msh91

    Joined:
    Apr 22, 2017
    Posts:
    37
    Sure, there's not much going on though:

    Code (CSharp):
    1. public class AISimpleMove : MonoBehaviour
    2. {
    3.     public float Speed = 3.0f;
    4.     public bool XMoveDirection = true;
    5.  
    6.     private World mWorld;
    7.     private Rigidbody2D mRigidBody2D;
    8.  
    9.     private void Start()
    10.     {
    11.         mRigidBody2D = GetComponent<Rigidbody2D>();
    12.         mWorld = World.GetWorld();
    13.     }
    14.  
    15.     private void Update()
    16.     {
    17.         Vector2 dir = XMoveDirection ? Vector2.right : Vector2.left;
    18.         mRigidBody2D.velocity = dir * Speed;
    19.     }
    20.  
    21.     private void OnCollisionEnter2D(Collision2D collision)
    22.     {
    23.         int mask = 1 << collision.gameObject.layer;
    24.         if ((mWorld.GroundLayer.value & mask) != mask)
    25.         {
    26.             // we collided with something (not floor); switch direction
    27.             XMoveDirection = !XMoveDirection;
    28.         }
    29.     }
    30. }
    p.s.
    World is a custom class, of course. It just holds the GroundLayer in this case though, nothing special.
     
  4. Nivbot

    Nivbot

    Joined:
    Mar 21, 2015
    Posts:
    65
    I see it colliding with the tilemap first and then the crate. Looks it’s just bouncing off then not moving.

    Also why do you have !XMoveDirection? If you want to do the opposite you should use -MoveDirection unless there’s some other use for ! Than comparatives.
     
  5. msh91

    msh91

    Joined:
    Apr 22, 2017
    Posts:
    37
    Regarding XMoveDirection : it's a bool. You can also see it by the way I'm using it to decide the dir (line 17).

    and the bounce is set to 0 so it's not a bouncing, it's just moving in the opposite direction, and then stopping.
    If you look closely where it stops, you'll see it stops at the border between 2 tiles.

    I'm assuming the reason there is no extra message for the tile is because it's the same collider - TilemapCollider2D.
     
  6. Nivbot

    Nivbot

    Joined:
    Mar 21, 2015
    Posts:
    65
    I think I know why, but don’t quote me on it. You’re using velocity so once you set the velocity it’s going at, well, that velocity. When you try to go with the exact opposite velocity all that does is counteract the previous velocity. Thus making it zero.

    You start at zero and and a velocity of left 3. Then you add a velocity of right 3. So basically -3 + 3.... zero.

    I hope that makes sense. If you’re going to use velocity in that way I think you’ll have to double it in the opposite direction.

    Personally, I don’t like using velocity for movement but that’s just me. I’m on my phone so I can’t test it but I’m going to assume I’m correct. Let me know because I’m not sure
     
  7. Nivbot

    Nivbot

    Joined:
    Mar 21, 2015
    Posts:
    65
    Of course now that I think about it the box should slow it so now I’m not sure. But since it’s in a loop maybe the loop is triggering again after the hit and before the switch. I dunno
     
  8. Nivbot

    Nivbot

    Joined:
    Mar 21, 2015
    Posts:
    65
    Nah, just tested it. Not that apparently. Unless something different with yours
     
  9. Nivbot

    Nivbot

    Joined:
    Mar 21, 2015
    Posts:
    65
    Also, now that I think about it that idea is stupid to begin with. the velocity change would just be a velocity change. Was late at night and I was tired : ). I'm stumped myself, but hopefully you figure it out. I don't know why anything other than the collider would have any effect.
     
  10. msh91

    msh91

    Joined:
    Apr 22, 2017
    Posts:
    37
    I didn't figure it out, actually. The velocity seems to be fine. Also now even though you only see one loop in the gif, it does work, generally speaking. That is, the green cube usually goes from right to left, hitting the crates, and everything is fine. But every now and then it stops. It doesn't keep going (unless I hit it with the player or something).

    Just to clarify about the frequency: It will happen at most after 1m if the game is on. So pretty frequent.
     
  11. Nivbot

    Nivbot

    Joined:
    Mar 21, 2015
    Posts:
    65
    That's weird. Sounds like the collision and loop are getting signals crossed sometimes
     
  12. ChuanXin

    ChuanXin

    Unity Technologies

    Joined:
    Apr 7, 2015
    Posts:
    1,068
    Could you try adding a CompositeCollider2D to the Tilemap GameObject and setting "Used by Composite" in the TilemapCollider2D? You may need to set the Body Type of the additional RigidBody2D to be Static.

    It is difficult to tell, but possibly your Cube is hitched at the collider shapes between Tiles? Using the CompositeCollider2D can help smooth out the edges between Tiles.
     
  13. msh91

    msh91

    Joined:
    Apr 22, 2017
    Posts:
    37
    Finally found the problem and the solution.

    The problem: When using TilemapCollider2D (only!), there will be a collider for each tile. When two nearby tiles each has a box collider, and another box collider is moving on top of it, due to imperfect, the moving box collider will collider against one of the sides of the tiles. Assuming the rotation of the moving object is locked, it won't be able to jump on it either, so it will just get stuck.

    The *correct* solution: Add a composite collider. This will create a single collider for adjacent tiles, so there won't be any nearby tile side to get stuck into.

    Added bonus:
    When using TilemapCollider2D, colliders are also created for tiles that are not reachable (e.g. ground tiles surrounded by other ground tiles). When adding the CompositeCollider2D, it will remove the inefficiency of them since they are now combined.

    p.s.
    When adding CompositeCollider2D, a RigidBody2D is automatically added. Don't forget to set it to "Static". Otherwise your world will start falling (or rather, your tiles)

    p.s.2
    ChuanXin - just noticed your comment. an hour after finding the solution online, and a minute after posting my comment. Thanks though, was spot on!
     
  14. Nivbot

    Nivbot

    Joined:
    Mar 21, 2015
    Posts:
    65
    good to know.
     
  15. Tommy-Renecade

    Tommy-Renecade

    Joined:
    Mar 28, 2018
    Posts:
    3
    Thank you this was driving me crazy when my player was moving between tiles with the Box Collider 2D on them. He would stop moving all of a sudden which was super weird. The method above works if you are using the Box Collider 2D on your ground tiles. Add the Composite Collider 2D and check "Use By Composite" on the Box Collider 2D.
     
  16. Azengar

    Azengar

    Joined:
    Nov 20, 2016
    Posts:
    11
    I've just experienced the same problem and thanks a lot for the help! It is weird though that tiles on a single row with a perfectly squared collider will sometimes trigger a box collider above them and I'd love to understand exactly why.
     
  17. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    10,533
    This is a common problem with physics systems and nothing new. I must've described it hundreds of times on the forums. It's annoying but cannot be helped.

    The "floor" (your row of tiles) isn't a continuous surface, it's composed of separate collider shapes. Collisions are calculated between collider shapes, not groups of colliders. It's possible therefore for a shape to catch the corner of shapes that are simply next to each other (not a continuous surface).

    Using a CapsuleCollider2D or CircleCollider2D can reduce the impulses caused by this because of their curved geometry but it won't remove the issue completely.

    The EdgeCollider2D can produce a single continuous surfaces made of multiple edges and solves this problem. If you must have multiple colliders or a collider with mutiple shapes (tilemap, polygoncollider etc) then you can merge them together using the CompositeCollider2D and set it to use "Outline" generation (continuous edges).

    A nice visual description of it can be found here.
     
    Williammsu likes this.
  18. GoodThingsComeIn

    GoodThingsComeIn

    Joined:
    Jul 26, 2017
    Posts:
    1
    Hi all, a little late to this thread but hope my example helps.

    I am creating some "Bouncy Ground" in my platformer using 2D Box Colliders on some sprites. There are several tiles next to each other, so when the player collides on a couple of different tiles, it would trigger the "OnTriggerEnter2D()" twice or more, resulting in running the velocity code multiple times.

    The below class is attached to the bouncy tiles. Hope this helps you understand more about why the "CompositeCollider" is actually solving the problem.

    Code (CSharp):
    1. public class BouncyTile : MonoBehaviour
    2. {
    3.    
    4.    
    5.  
    6.     // bounce off tiles
    7.     void OnTriggerEnter2D(Collider2D col) {
    8.  
    9.         Rigidbody2D rigidbody = col.gameObject.GetComponent<Rigidbody2D>();
    10.  
    11.         if(rigidbody != null) {
    12.  
    13.             // if this has a rigidbody
    14.  
    15.  
    16.             // if we are below the block and hit the block, bounce down
    17.             if(rigidbody.velocity.y > 0f && rigidbody.gameObject.transform.position.y < this.transform.position.y) {
    18.  
    19.                 rigidbody.velocity = new Vector2(rigidbody.velocity.x, rigidbody.velocity.y * -1.2f);
    20.                 Debug.LogError("Bounce Down: " + rigidbody.velocity);
    21.             }
    22.  
    23.             // if we are above the block and hit the block, bounce up
    24.             if(rigidbody.velocity.y < 0f && rigidbody.gameObject.transform.position.y > this.transform.position.y) {
    25.  
    26.                 rigidbody.velocity = new Vector2(rigidbody.velocity.x, rigidbody.velocity.y * -1.2f);
    27.                 Debug.LogError("Bounce Up: " + rigidbody.velocity);
    28.             }
    29.  
    30.         }
    31.        
    32.     }
    33. }
    P.S. This is my first post on this forum, so hopefully people find it and appreciate!
    Thanks all!