Overlapping Objects

I am following along the new 2021 Unity 2D course, and in the Delivery Driver Lesson “Colliders and Rigid Bodies” I notice my implementation has the circle and the car object overlap a little bit when they collide. Did I miss something? I have gone over the lesson multiple times to ensure what I have is exactly what is in the lesson to see if I missed something, but as far as I can tell I matched it exactly and it still occurs. Does anyone know why this may happen?

In the Unity documentation it mentions avoiding moving an object by setting the transform and instead doing it by altering the rigid body. But a game dev friend said that it could have something to do with the rigid body type being “Dynamic” vs “Kinematic” and that I should use “Kinematic” if I am moving the object manually. They also mentioned that I should be using FixedUpdate instead because that is when Physics is calculated.

Can anyone clarify for me? Is this something addressed later in the course? Thanks!

1 Like

Hi Xabin,

Welcome to our community! :slight_smile:

The “physics” in Unity is a simulation, not the real world. Since nobody wants to wait a second each time something happens in a game, the physics simulation is highly optimised meaning the performance is high but the precision is rather low. Overlapping colliders when game objects collide with one another are expected. Unless the result looks really strange, it is better to accept that behaviour for the sake of performance. After you completed your game, you could tweak the values in the Physics2D settings a bit to see if you can achieve better results without making the game laggy.

Since this course caters to beginners, Rick tries to keep things simple. What you figured out about the Rigidbody2D and the physics is correct. You can certainly achieve better results with the Rigidbody2D methods and FixedUpdate. The solution is a bit more complex, though. If you want to challenge yourself, you could follow my instruction. It was for a project in the Unity 3D course, so you’ll have to try to understand and to apply it. Since I do not know your code, I obviously cannot refer to anything in your code.

  1. Select all game objects with colliders that are not supposed to move. In their Inspector, tick “Static”. Do not do that for moving game objects, only for non-moving ones.

  2. This is the “difficult” part. Your goal is to make the physics simulation control your game object. You won’t manipulate the Transform values directly anymore (via the Translate method) but “communicate” with the Rigidbody, which gets used by the physics simulation.

    2.1) In your player/mover class, create a new method named FixedUpdate. It’s a Unity method.

    2.2) Declare the xValue and yValue variables at the top of your code but without the [SerializeField] attribute. They will act as containers for the value which you got in the Update method.

    2.3) Fetch the user input in the Update method and assign the values returned by GetAxis to the instance variables, which you declared in 2.2).

    2.4) Now look up the Rigidbody.AddRelativeForce method up in the API and read the example. Do something similar in your code but use the Rigidbody2D.AddRelativeForce method. Test your game.

    2.5) If it works, go back to your code. Instead of a hard-coded Vector3 object, you create a new Vector3 object with the xValue and the yValue values. Pass on that Vector3 object to the AddRelativeForce method. Then test your game again. It might be that you made a little mistake but if you see it in your game, you will very likely know what went wrong.

Since structs have not been covered at this point, here is the pattern:

  1. Vector3 velocity = new Vector3(x, y, z);

You would pass on velocity to AddRelativeForce by which I mean: Put the variable name into the parentheses.

x, y and z are just placeholders in my example. Replace them with your variables. One of the values is supposed to be 0f, which you may hardcode.

The solution will appear to be a bit circuitous but there is a reason for that: While you could get the user input in FixedUpdate, that’s not recommended because data could get “lost” as FixedUpdate does not get called “each frame”. You want to check the user input each frame. See the definition of GetAxis in the API.

Let me know how it worked. :slight_smile:

2 Likes

Hey Nina! Thank you for the response! I only have a little bit of time this weekend to continue the course but I read over what you mentioned and tried to apply it. I ran into some weird issues though. I think I worked around them, but I am not sure they are in the spirit of what you were describing or not. Or if they are not the recommended way to interact with this stuff.

The first thing I did was create a Vector2d with the inputX and inputY, and passed it into AddRelativeForce. I noticed was that the car wouldn’t rotate but it did move in the direction I would press. To get around that I added back in the transform.Rotate, but I don’t know if that was the intention. It still means that rotation is happening directly on the transform rather than on the rigidbody2d, and in the Update method rather than FixedUpdate.

However, this broke movement, and I figured it was because I was adding a vector of both the horizontal and vertical input as a relative force, and since it is “relative” it was applying it relative to the transform’s rotation (I think?), which was now all over the place. To get around this, my guess was that the vertical axis input was the “target velocity” and that was the only force I needed to add (you mentioned one value should be 0f). Since everything is in 2d, and I was using a Vector2 instead of the Vector3 you mentioned, I passed in the “Movement Speed” * “Y Input(Vertical)” as the Y value, leaving X 0, into the AddRelativeForce function. What I think this resulted in was:

  • The transform was rotated at a constant speed in Update like the course originally, which set the direction the car is facing at any given moment
  • AddRelativeForce added the velocity in the direction the car was facing during FixedUpdate.

But this lead to another set of issues. In the course version, the car stops when you stop pushing forward on the Vertical axis. By using AddRelativeForce I was noticing that the car never stopped. In fact it would drift around depending on how i added force. I poked around a bit and was curious if adding a “Force” and “Rotating the Transform” was the right choice vs using “SetRotation” and “MovePosition” on the RigidBody.

While trying to figure that out, a friend mentioned that linear drag existed on the RigidBody2D, and so I tried setting that high and it worked (after I updated the move speed), but I am not sure that is the correct way to solve this. I also noticed that even though I was setting the transform rotation, if I collided with something the car would spin ever so slightly and never stop. I tried adding Angular Drag to solve that too and it seemed to.

Is this what you meant? Or was there something I am misunderstanding? SetRotation and MovePosition seem similar to transform’s Rotate and Translate (but not quite the same). I also looked at AddForce instead of AddRelativeForce, but wasn’t sure if I should be using that instead. My guess would be if I did I would need to include the x and y inputs in the vector. But that wouldn’t solve my rotation problem.

Here is the code that I ended up with:

    [SerializeField]
    float steerSpeed = 300.0f;

    [SerializeField]
    float moveSpeed = 20.0f;

    float inputX;
    float inputY;

    Rigidbody2D driverRigidBody;

    // Start is called before the first frame update
    void Start()
    {
        driverRigidBody = GetComponent<Rigidbody2D>();
        driverRigidBody.drag = 6.0f;
        driverRigidBody.angularDrag = 20.0f;
    }

    // Update is called once per frame
    void Update()
    {        
        inputX = Input.GetAxis("Horizontal");
        inputY = Input.GetAxis("Vertical");
        float steerAmount = -1 * inputX * steerSpeed * Time.deltaTime;
        transform.Rotate(0, 0, steerAmount);
    }

    void FixedUpdate() 
    {
        float moveAmount = inputY * moveSpeed;
        driverRigidBody.AddRelativeForce(new Vector2(0, moveAmount));           
    }

Thanks for your help understanding this!

First of all, good job on challenging yourself. :slight_smile:

Secondly, it is absolutely fine if you take my suggestions as an inspiration not as an instruction to the only solution there is. If you found an alternative which does the job for you, that’s perfectly fine.

The AddRelativeForce method is supposed to move the game object “forward”. Of course, if the game object is supposed to move into another direction (but still “foward”), you must rotate the game object.

I see that you defined the user input as follows:

  • vertical axis for moving forwards/ backwards
  • horizontal axis for moving left/right by rotating the game object

That looks fine to me.

Instead of working with angular drag, I would probably have used the AddTorque method of the Rigidbody2D. Like in the AddRelativeForce method, there are different Force types which you could test.

However, I don’t see any reason why you should not use your code if it works. :slight_smile:

Ahh good to know I wasn’t way off base! For the AddTorque option, would there need to be some sort of friction applied to stop it from turning if there is no input (similar to AddRelativeForce)? If so would I still need the angular drag, or is there a different way to have it stop rotating? I am also guessing I would have to somehow cap the top rotational speed?

Have you already tested your ideas? According to the API, “[a]ngular drag can be used to slow down the rotation of an object. The higher the drag the more the rotation slows down”.

I have tested angular drag and that seems to do the trick if I try to balance that vs the amount of Torque I apply. I am guessing that is the main way to slow down the rotation. The other option I can think of is to somehow cap the angular velocity regardless of the torque applied. I don’t see any value on the rigid body that would indicate we can cap the rotational velocity implicitly, but I am guessing I just do it to the angularvelocity manually after I apply the force.

This topic was automatically closed 24 hours after the last reply. New replies are no longer allowed.

Privacy & Terms