Rigidbody problem

Hello! For a very long time I can not figure out why it works this way.
I have a main GameObject let’s call it parent. I also have child GameObjects, let’s call them child. At first, all objects are the same in hierarchy and have RigidBody2D and BoxCollider2D components, but after I release the mouse button, the child object that I have chosen becomes a child of the parent object, the RigidBody2D component is removed from the child. Now I have a group of objects that behaves like one solid object.
The problem is that although I specify from the code what local position the child should take, its local position is slightly different (and sometimes very different). I have already found out that this is either due to the popping of the collider or due to the Rigidbody. How to solve this problem?

public class Mover : MonoBehaviour
{
    private bool isCatchBlock;
    private Block catchedBlock;

    public GameObject parent;
    public Block parentBlock;

    public Camera MainCamera;
    private Vector2 currentMousePos;

    private byte blockCount;

    void FixedUpdate()
    {
        if (Input.GetMouseButtonDown(0))
        {
            //taking an object
            GameObject catchedObj = RaycastHit();
            if (catchedObj != null)
            {
                if (catchedObj.tag == "block")
                {
                    isCatchBlock = true;
                    catchedBlock = catchedObj.GetComponent<Block>();
                    catchedBlock.thisCollider.isTrigger = true;
                }
            }
        }
        if (Input.GetMouseButtonUp(0))
        {
            if (isCatchBlock)
            {
                isCatchBlock = false;
               
                //attaching an object
                blockCount++;
                //if parent becomes static then everything works correctly BUT "below"
                parentBlock.thisRigidbody.bodyType = RigidbodyType2D.Static;
                //if child becomes static, then the coordinates are very similar
                catchedBlock.thisRigidbody.bodyType = RigidbodyType2D.Static;
                Destroy(catchedBlock.thisRigidbody);
                catchedBlock.thisTransform.parent = parent.transform;
                catchedBlock.thisTransform.eulerAngles = new Vector3();
                //everything is always displayed correctly, as it should be
                Debug.Log($"Y = {-0.14f*blockCount}");
                //but here the real localPosition is not the one I set
                catchedBlock.thisTransform.localPosition = new Vector3(0, -0.14f*blockCount, 1);

                catchedBlock.thisCollider.isTrigger = false;
                //if parent becomes dynamic, then everything works wrong again.
                parentBlock.thisRigidbody.bodyType = RigidbodyType2D.Dynamic;
            }
        }
        if (isCatchBlock)
        {
            //drag child
            Vector2 targetPos = (Vector2)MainCamera.ScreenToWorldPoint(Input.mousePosition);
            catchedBlock.thisRigidbody.velocity = new Vector2(7 * (targetPos.x - catchedBlock.thisTransform.position.x), 7 * (targetPos.y - catchedBlock.thisTransform.position.y));
        }
    }

    private GameObject RaycastHit()
    {
        //for convenience
        currentMousePos = MainCamera.ScreenToWorldPoint(Input.mousePosition);
        RaycastHit2D hit = Physics2D.Raycast(currentMousePos, transform.forward);
        return hit ? hit.collider.gameObject : null;
    }
}

First, edge trigger inputs like the Down/Up checks you have are NOT guaranteed to work in FixedUpdate(). Those functions are only valid in Update(). Instead, store the input in a boolean and process it in FixedUpdate().

Second, yes, if a Rigidbody is involved, its velocity, angularVelocity and colliders may certainly move things in ways you don’t anticipate.

Here is some timing diagram help:

Good discussion on Update() vs FixedUpdate() timing:

To track down what is actually moving things and when, you must find a way to get the information you need in order to reason about what the problem is.

What is often happening in these cases is one of the following:

  • the code you think is executing is not actually executing at all
  • the code is executing far EARLIER or LATER than you think
  • the code is executing far LESS OFTEN than you think
  • the code is executing far MORE OFTEN than you think
  • the code is executing on another GameObject than you think it is
  • you’re getting an error or warning and you haven’t noticed it in the console window

To help gain more insight into your problem, I recommend liberally sprinkling Debug.Log() statements through your code to display information in realtime.

Doing this should help you answer these types of questions:

  • is this code even running? which parts are running? how often does it run? what order does it run in?
  • what are the values of the variables involved? Are they initialized? Are the values reasonable?
  • are you meeting ALL the requirements to receive callbacks such as triggers / colliders (review the documentation)

Knowing this information will help you reason about the behavior you are seeing.

If your problem would benefit from in-scene or in-game visualization, consider using Debug.DrawRay() or Debug.DrawLine() to visualize things like raycasts or distances.

You can also put in Debug.Break() to pause the Editor when certain interesting pieces of code run, and then study the scene manually, looking for all the parts, where they are, what scripts are on them, etc.

You could also just display various important quantities in UI Text elements to watch them change as you play the game.

If you are running a mobile device you can also view the console output. Google for how on your particular mobile target.

Another useful approach is to temporarily strip out everything besides what is necessary to prove your issue. This can simplify and isolate compounding effects of other items in your scene or prefab.

Here’s an example of putting in a laser-focused Debug.Log() and how that can save you a TON of time wallowing around speculating what might be going wrong:

1 Like

A Rigidbody2D isn’t a passive renderer, its job is to take control of the Transform by writing the world body position/rotation to it after simulation. Your constant manipulation of the Transform is breaking this and you’re fighting what it’s trying to do. If you want movement, you go via the Rigidbody2D and use its API.

In summary: The Rigidbody2D isn’t some local-space thing, it’s a position/rotation in world-space and it writes that to the Transform. Anything you do to the Transform directly is undermining this.

yes, but before that I remove the rigidbody component so that it does not interfere with the transform, but it still interferes.

Thank you. I will try.

You remove it yet somehow, even though it’s completely gone, it magically “interferes” with it? I highly doubt that’s possible. :wink:

Just watch this.

It’s a silent video and I’m not sure what the video is showing. Maybe explain the video and what the expectation is.

You want the Y position in the console to match the Y position shown in the Inspector? Well for starters you look like you’re outputting the standard 2 digit precision in the console which won’t match the inspector.

Nevertheless, why is one supposed to match the other? I mean the physics system will separate the blocks because it looks like you’re placing them overlapped. It won’t just sit there with them overlapped? There’s also a small contact offset used to keep them stable too. On top of this I notice your blocks are slightly rotated, maybe you don’t want that which is why you can use a rotation constraint on the Rigidbody2D.

You need to explain the expectation in more detail against the video.

Sorry for my English.

I have unity version 2019.2.0f1

Okay thank you.

So you see “-0.1406” in the Inspector and in the console you see “-0.14” and you saying they should be the same? Why should they be the same?

I explained that above when I said:

Just because you put them at a specific Transform position doesn’t mean they’ll stay there. That’s not necessarily their physical resting position either. You can see that because you cause the stack to jump.

What can i do to stop the stack from jumping?

How to set this rest position?

I tried using DestroyImmediate instead of Destroy and the position started to set correctly, but the rotation is not quite right yet.

That’s it, I’ve decided everything. Thanks everyone!