[FIXED] - Rigidbody2D Collision Problem

So I started making a 2D game in unity that is essentially set up on a 4x7 grid (150 pixels per unit). I have a square sprite (1x1) that has both a Rigidbody 2D and a Box Collider 2D. The walls (also 1x1) have just a Box Collider 2D. Both box colliders are left at size 1 for X and Y. The RigidBody has gravity and angular drag set to 0 and fixed angle checked. All of the other properties on all of the physics components were left as their default values.

I’ve attacked a PlayerController script to my player. The script(C#) for player movement is simple so far:

public class PlayerController : MonoBehaviour {

public float speed;

void FixedUpdate() {

//&& isFree(-Vector2.right)
if (Input.GetKeyDown(KeyCode.LeftArrow))
rigidbody2D.velocity = new Vector2(-speed, 0);
if (Input.GetKeyDown(KeyCode.RightArrow))
rigidbody2D.velocity = new Vector2(speed, 0);
if (Input.GetKeyDown (KeyCode.UpArrow))
rigidbody2D.velocity = new Vector2(0, speed);
if (Input.GetKeyDown(KeyCode.DownArrow))
rigidbody2D.velocity = new Vector2(0, -speed);

}
}

All of the walls are at whole x and y locations such, like (0, 3, 0). If the players starts at (0,0,0) and moves up to the box, it stops a tiny bit before the walls edge. If the edge is at (0,3,0), the player edge would stop at (0,2.98,0).

Here is an image of the behavior. The green thing is the player and the dark brown box is the wall. The light brown is just the background. The box colliders of the wall and the player are not touching, even though the player already stopped.

If I wanted to get pixel perfect collisions, namely the player moving up to the exact edge of the wall, is my script adequate. Is there some project physics setting that is causing this? Are the Box Colliders supposed to be touching when the player stops?

NOTE: An interesting note is that when I tested this same scenario with 3D objects, the cube player moved all the way up to the wall.

Any help would be greatly appreciated! It’s also very late here so if this doesn’t make sense or I can provide some more information to help, please let me know.

-Alec

Have you tried shrinking the colliders on one of the objects by 0.02 or in all (including the player) by 0.01 to see if that works for what you want?

I had that same thought and I forgot to mention that I did try this. Instead of the box colliders set to a scale of 1x and 1y, 0.985x and 0.985y artificially mirrored the intended collision point. Even this, though, was not consistent. Sometimes the player went all the way up to 3, and other times 2.9998.
I’m still trying to find out why the player stops before the edge of the box collider.

I had a similar effect when trying to clamp scale when I moved. Hopefully someone with more experience can jump in & clarify but I ended up just thinking that it was caused by the movement over time bit of code such that if the next tick thru the code would take it beyond the point it’s meant to go then it stops just short rather than inside it. Perhaps that’s what is happening here

That’s interesting.
That thought occurred to me as well. For instance, lets say the player is moving at 8 pixels per tick and the Box Collider is 30 pixels away. The player would move to 8, then 16, then 24 and finally try to move to 32. Then, either before or after the move to 32 pixels takes place, it would snap back to 24.
To test this, I set a very low speed so in the previous example it would move at a lower pixel per tick rate. However, I found that the player stopped at the same location at very low speeds and very high speeds.

My guess is this is a FixedUpdate() vs. Update() issue. Like, there is imperfect precision in movement based on Update().

It’s just a guess. I’m very curious to understand this. Excellent question.

@BusyCat - If I change Fixed Update to Update the same result occurs :(. Good suggestion though! :slight_smile:

I’m interested to see if other people can replicate my exact problem. The easiest way would be to:

  1. Create a new project.
  2. Create two sprite game objects with a box sprite: one for the player and another for the wall.
  3. Add a Box Collider 2D component to each game object.
  4. Add a Rigidbody 2D to the player and make gravity and angular drag 0. Also check ‘Fixed Angle’.
  5. Finally, add a simple movement script to the player. Mine is as follows: (I set my speed parameter to 4 in this example)

using UnityEngine;
using System.Collections;

public class PlayerController : MonoBehaviour {

public float speed;
void FixedUpdate() {
if (Input.GetKeyDown (KeyCode.UpArrow)) {
rigidbody2D.velocity = new Vector2(0, speed);
}
}
}

Here is what my player object looks like:

If anyone goes through the trouble of trying this, does your player object move exactly up to the wall, or does it stop short? Does the player move until it touches the wall’s box collider?
Thanks in advance! :slight_smile:

Box2D adds a small buffer region around colliders which is defined to be (and I quote the Box2D manual) ‘numerically significant but visually insignificant’. Your sprites are at a scale which makes them visually significant however.

This region is there to allow colliders to agree that they are touching but not be overlapped numerically. Whilst you are free to change the size of this region using Physics2D.minPenetrationForPenalty, be aware that changing it can seriously affect collision detection.

It is recommended that your sprites be at a scale where this numerically small value isn’t visible. A more commonly used option is to just reduce the size of your colliders where this is important.

5 Likes

Thanks for clearing that up for us @MelvMay

2 Likes

Thanks for clearing this up :slight_smile: