Can't remove RigidBody constraints?

I have a RigidBody2D that I apply constrains to along the X and Y axis by using

rb2d.constraints = RigidbodyConstraints2D.FreezePositionY | RigidbodyConstraints2D.FreezePositionX;

But when I try to remove them, nothing works, the code is definitely executing, but when I hit pause and view the GameObject in the hierarchy, the freeze X and Y boxes in it’s Rigidbody2D component are still checked, here’s some of the things I’ve tried…

rb2d.constraints = RigidbodyConstraints2D.None;

rb2d.constraints = OrignialConstraints;
//OrigninalConstraints is a variable of type RigidbodyConstraints2D that I assigned in Start()

rb2d.constraints &= ~RigidbodyConstraints2D.FreezePositionY;
rb2d.constraints &= ~RigidbodyConstraints2D.FreezePositionX;

According to the documentation on Rigidbody constraints as well as a bunch of forum posts, each of these should work, but none do. I’m certain the constraints aren’t being reapplied anywhere, they’re just not being removed.

Needless to say this is causing all kind of problems, is there either a way to get the constraints removed that I haven’t tried, or another way of freezing a GameObject in place (without just doing currentPosition = OldPosition every frame, or disabling gravity)

Any thoughts would be very much appreciated :slight_smile:

Fred T.A

Bump, still baffled by this, is this a bug with Unity? The code I’m using seems to be fine for everybody else…is there something else that can interfere with assigning RigidBody constraints?

It works for me. Is there a reason why at first you use “2b2d” and then “rigidbody”?

Another way to stop a rigidbody is to set it’s bodyType to static.

1 Like

No reason, just the way I typed it out, corrected now :slight_smile:

Thanks for the tip, I’ll try setting it to static and see if that works

Haven’t had any luck with this :confused:

there doesn’t seem to be any BodyType property within RigidBody, not that I can see from the script or the editor, I was hoping to change it using

rb2d.bodyType = RigidbodyType2D.Static;

But it didn’t get me anywhere…is bodyType not a thing anymore in the current version of Unity?

What does your changing of rigidbody constraints look like in the context of your script? It looks like you are deliberately overriding your changes back to the original constraints somewhere. It could be an order of execution issue, or coming from another script, or placed in Update.

So assign them to restrict movement along the X and Y axis, then yes, I override them back to remove the constraints later on, but the method that assigns the constraints for X and Y is only called once, many minutes before the method that removes those constraints later on. If I pause and unchecked the constraints boxes in the inspector, they don’t check themselves again, so I’m fairly sure it’s not something to do with the constraints being continually reapplied

This probably isn’t related, but I had a similar problem trying to unparent a child from it’s parent GameObject, whenever I tried to remove the parenting using

gameObject.transform.parent = gameobject.transform;
//Or
gameObject.transform.parent = null;

There would be no change, and the GameObject would still be parented to the parent GO, the only thing that worked was either unparenting it via the hierarchy in the editor or using

gameObject.transform.parent = SomeOtherGameObject.transform;

Not the same problem I know, just has a similar smell to it, could they be related?

Something’s wrong with your code. Parenting to null absolutely works.

Denying possibilities is not the problem solver way.

We really have to see how you have applied all that in your script. Simply saying a method isn’t working is a mere declaration, not a question.

The problem solver way is to narrow down the problem no? Keep ruling out possibilities until I know where the problem is so I can fix it?

If you want to see all the relevant code, here it is, but it’s definitely only executing once, and in the correct order

    void InitialiseStasis()
    {
        stasisAcceleration.x = 0;
        stasisAcceleration.y = guiController.acceleration;
        stasisVelocity.x = rb2d.velocity.x;
        stasisVelocity.y = stasisVelocityYNoGrav = rb2d.velocity.y;
        stasisAltitude = guiController.altitude;
        inStasis = true;
        rb2d.constraints = RigidbodyConstraints2D.FreezePositionY | RigidbodyConstraints2D.FreezePositionX;
        //Prevents the rocket moving vertically or horizontally

        guiController.OutputText("\t <color=#500050D0>DEBUG: Rocket has entered stasis</color>");
        soundController.AcceptSound.Play();
    }

    void DeinitialiseStasis()
    {
        rb2d.constraints = RigidbodyConstraints2D.None; //Allows the rocket to move
        inStasis = false;
        guiController.OutputText("\t <color=#500050D0>DEBUG: Rocket has left stasis</color>");
        soundController.AcceptSound.Play();
        if (timeFactor != 1)
        {
            timeFactor = 1;
            guiController.OutputText(" \t <color=#E1E107D0>Lunar approach: temporal ratio reset</color>");
            soundController.AcceptSound.Play();
        }
    }

I know for a fact that the InitialiseStasis() method is called once and only once, and later on the DeinitialiseStasis() method is called once after this. If there were called multiple times or in the wrong order, I would be able to see from the text being output

    void FixedUpdate()
    {        if (!inStasis)
        {
            if (guiController.altitude > stasisLowerLimit && guiController.altitude < stasisUpperLimit && !inStasis)
            {
                InitialiseStasis(); //Do this if within the stasis limits, not in stasis
            }
       else //must be in stasis
        {
            if ((guiController.altitude < stasisLowerLimit || guiController.altitude > stasisUpperLimit) && inStasis)
            {
                DeinitialiseStasis();//Do this if in stasis, outside stasis limits
            }//The rocket goes up, enters the stasis zone, then leaves the stasis zone

I don’t think you need the inStasis checks. All it seems to be doing is going back and forth between the two functions. Removing the inStasis checks would make the function calls based on your altitude and whether it’s within the limits or not.

You could try this:

void FixedUpdate()
{
    if (guiController.altitude > stasisLowerLimit && guiController.altitude < stasisUpperLimit)
    {
        InitialiseStasis();
    }
    if (guiController.altitude < stasisLowerLimit || guiController.altitude > stasisUpperLimit)
    {
        DeinitialiseStasis();
    }
}

If you really need to check the state of the rocket, Id’ very much rather use Enums to create a simple state machine for your rocket. With 3 states, instead of a boolean handling 2 states, there should not be conflict in those state.

enum RocketState{ inStasis, inFlight, stationary }
RocketState currentRS = RocketState.stationary;

Because what you were doing looked pretty much like this

if(false)
    set to true
else
    set to false//and the behaviour loops from here switching between true and false repeatedly.

Also, the most reliable thing to check if something is called multiple times IMO is print statements. Even if your UI text changes once, it does not tell you how many times its being executed.

Yes that is true, however your behaviour is outright denial. Ruling out possibilities is testing to see if they are the culprit, and moving on if they are not. Also, if something consistently works for everyone else but not you, the problem most likely lies elsewhere, which is why I kept pressing for you to reveal how you have applied the changing of constraints.

Yes, it does, that’s now how the OutputText method works, it doesn’t just change text in a field, it outputs each new string line by line.

The inStasis checks are needed, otherwise the code will just keep executing repeatedly, the InitialiseStasis method should only be called once, when it’s within the limits and not already in stasis, as for the enumeration suggestion, you are right, that would be a more efficient approach, but I’ve got a deadline to meet and it unfortunately wouldn’t get me anywhere in solving the problem at hand.

As I said, I had run tests to rule out the possibility of the constraints being reapplied somewhere. Pausing the game and unchecking the constraints in the inspector resulting in the constraints being unassigned and not applied again for the remainder of the game.

How bout this then

    void InitialiseStasis()
    {
        stasisAcceleration.x = 0;
        stasisAcceleration.y = guiController.acceleration;
        stasisVelocity.x = rb2d.velocity.x;
        stasisVelocity.y = stasisVelocityYNoGrav = rb2d.velocity.y;
        stasisAltitude = guiController.altitude;
        inStasis = true;
        //Prevents the rocket moving vertically or horizontally

        guiController.OutputText("\t <color=#500050D0>DEBUG: Rocket has entered stasis</color>");
        soundController.AcceptSound.Play();
    }

    void DeinitialiseStasis()
    {
        inStasis = false;
        guiController.OutputText("\t <color=#500050D0>DEBUG: Rocket has left stasis</color>");
        soundController.AcceptSound.Play();
        if (timeFactor != 1)
        {
            timeFactor = 1;
            guiController.OutputText(" \t <color=#E1E107D0>Lunar approach: temporal ratio reset</color>");
            soundController.AcceptSound.Play();
        }
    }
    void FixedUpdate()
    {        if (!inStasis)
        {
            rb2d.constraints = RigidbodyConstraints2D.FreezePositionY | RigidbodyConstraints2D.FreezePositionX;
            if (guiController.altitude > stasisLowerLimit && guiController.altitude < stasisUpperLimit && !inStasis)
            {
                InitialiseStasis(); //Do this if within the stasis limits, not in stasis
            }
       else //must be in stasis
        {
            rb2d.constraints = RigidbodyConstraints2D.None; //Allows the rocket to move
            if ((guiController.altitude < stasisLowerLimit || guiController.altitude > stasisUpperLimit) && inStasis)
            {
                DeinitialiseStasis();//Do this if in stasis, outside stasis limits
            }//The rocket goes up, enters the stasis zone, then leaves the stasis zone

not sure if i got the order mixed up for which state matches which rigidbody constraint, but it still looks to me the problem is having the rigidbody constraints being in the functions. If you change the rigidbody constraints in the update loop it should guarantee you the rigidbodyconstraints you want based on the inStasis bool while keeping all other functionality running only once.

Continually assigning the constraints every FixedUpdate to the correct value? Hadn’t thought of that, sounds like a good idea though, I’ll give it a go and report back, thanks for the suggestion :slight_smile:

Have you solved this problem yet? I am currently facing the same issue.

Ah I’m sorry I can’t for the life of me remember, looks like I forgot to post my findings on this :confused: