Search Unity

Reset Rigidbody2D

Discussion in '2D' started by Wox, Mar 17, 2020.

  1. Wox

    Wox

    Joined:
    Dec 14, 2009
    Posts:
    93
    Hi!

    I'm trying to reset a Rigidbody2D after it falls and hits the ground, all works except the
    myRigidBody.sleepMode = RigidbodySleepMode2D.StartAsleep;
    It goes back to the start position but it do not want to sleep.
    Help Please!.


    Code (CSharp):
    1. void OnCollisionEnter2D(Collision2D other)
    2. {
    3. if (other.gameObject.layer == 8)
    4. {
    5.  
    6.  
    7. myRigidBody.position = myStartPosition;
    8. myRigidBody.velocity = Vector3.zero;
    9. myRigidBody.angularVelocity = 0f;
    10. myRigidBody.constraints = orginalConstrains;
    11. myRigidBody.sleepMode = RigidbodySleepMode2D.StartAsleep;
    12.  
    13. }
    14. }
     
  2. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,459
    Are you saying it's not sleeping? It'll only sleep if you're not modifying it in any way i.e. adding forces and it's not moving for a period of time defined in the Physics2D settings.
     
  3. Wox

    Wox

    Joined:
    Dec 14, 2009
    Posts:
    93
    I want to reset objects in the level when the players dies and restart from a re-spawn point.
    So I have stones and other objects that falls down on to the ground with rigidbodies2d on em.
    I can reset all except the sleeping state on the objects.
    The state they have are Start asleep. How do i make em sleep again after they have woken?

    The Debug.Log(myRigidBody.sleepMode) prints StartAsleep after reset code but still they fall.
    What else do I have to reset to make the rigid body sleep again?
    It is like they still have collision with the ground after the Reset().
    Do I need to make a coroutine yield WaitForFixedUpdate after moving it to know that it do not collide
    with anything? Or turn the collider on/off?
     
  4. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,459
    That's just the mode controlling when or if it should sleep. By repositioning them, that isn't the "Start". That's just your notion of start. The "Start" there refers to when they're created i.e. the scene loaded.

    To get them to sleep you use Rigidbody2D.Sleep() ;)

    Ref: Rigidbody2D API docs.
     
    Last edited: Mar 18, 2020
  5. Wox

    Wox

    Joined:
    Dec 14, 2009
    Posts:
    93
    Hmm if i log it ( Debug.Log(myRigidBody.IsSleeping() ) , it goes to sleep for one frame the it wakes up again.
    When it falls for the first time and hit the ground it never falls asleep either.
     
  6. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,459
    Can you please let me know what you've tried. Reading between the lines I presume you're now calling the Rigidbody2D.Sleep method before this "Debug.Log" stuff?

    Anyway, as I said above, it not falling asleep is because it's not meeting the criteria for sleeping which is because it's moving, some script is modifying the body/collider or it has a new contact being generated. All these wake the body. This isn't done by Unity but by Box2D, the physics system and is a low-level thing. Doing stuff like creating huge forces by increasing gravity high can also cause it not to sleep because it's constantly moving.

    BTW: You can see sleep-state, contacts (etc) in the inspector by going to the Rigidbody2D and opening the "Info" roll-out. If you pause you can see if contacts are produced, what the velocities are, sleep-state etc.
     
    Last edited: Mar 18, 2020
  7. Wox

    Wox

    Joined:
    Dec 14, 2009
    Posts:
    93
    Thanks for the super fast and good help, got it working by enabling and disabling the collider!

    Here is the code (don't know if all is needed in the Reset() but it works )
    Used keys for testing purpose.


    Code (CSharp):
    1. public class Stone : MonoBehaviour
    2. {
    3.     public SoundManager_sc sm;
    4.     private Vector2 myStartPosition;
    5.     private LayerMask GroundLayerMask;
    6.     private Rigidbody2D myRigidBody;
    7.     private RigidbodyConstraints2D orginalConstrains;
    8.     private CircleCollider2D myCollider;
    9.  
    10.     private void Awake()
    11.     {
    12.         myStartPosition = transform.position;
    13.     }
    14.  
    15.     void Start()
    16.     {
    17.         myStartPosition = transform.position;
    18.         sm = FindObjectOfType<SoundManager_sc>();
    19.         GroundLayerMask = LayerMask.GetMask("Ground");
    20.         myRigidBody = GetComponent<Rigidbody2D>();
    21.         orginalConstrains = myRigidBody.constraints;
    22.         myCollider = GetComponent<CircleCollider2D>();
    23.         onGround = false;
    24.     }
    25.  
    26.     private void Update()
    27.     {
    28.         if (myCollider.enabled == false && myRigidBody.IsSleeping() == true) myCollider.enabled = true;
    29.  
    30.         if (Input.GetKeyUp("h") == true) ResetMe();
    31.  
    32.         if (Input.GetKeyUp("g") == true) myRigidBody.WakeUp();
    33.     }
    34.  
    35.     void ResetMe()
    36.     {
    37.         myCollider.enabled = false;
    38.         transform.position = myStartPosition;
    39.         myRigidBody.constraints = RigidbodyConstraints2D.None;
    40.         myRigidBody.velocity = new Vector2(0.0f, 0.0f);
    41.         myRigidBody.angularVelocity = 0f;
    42.         myRigidBody.rotation = 0.0f;
    43.         myRigidBody.constraints = orginalConstrains;
    44.         myRigidBody.Sleep();
    45.     }
    46.  
    47.     void OnCollisionEnter2D(Collision2D other)
    48.     {
    49.         if (other.gameObject.layer == 8)
    50.         {
    51.             sm.Play("StoneFall");
    52.             myRigidBody.velocity = new Vector2(0.0f, 0.0f);
    53.             myRigidBody.constraints = RigidbodyConstraints2D.FreezeAll;
    54.  
    55.         }
    56.     }
    57. }
     
    MelvMay likes this.
  8. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,459
    I don't really follow your change, especially considering that enabling a collider would wake the body but if you say it's working then that's all that matters.:)
     
  9. Wox

    Wox

    Joined:
    Dec 14, 2009
    Posts:
    93
    Works :) (for now anyway :) )
    Why would it wake it up if it's not colliding whit anything?
    It is being enabled a frame after I move the rigidbody so it has nothing to collide with.

    I can imagine same thing can be done by enabling/disabling isKinematic and some flags.
     
  10. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,459
    You say frame but physics isn't updated per-frame, it's update each fixed-update. That might be in-sync with some frames but it's not guaranteed.
     
  11. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,459
    Part of the problem here is that it sounds like you've got gravity active on an object but you want to use sleep to stop that affecting it. If it wakes, for any reason, then it'll fall so this is a fairly unstable set-up. Know that even if something overlaps the bounding-box of the collider (not even in contact with it) then it'll wake. This is why I describe using sleep to keep it in "mid air" with gravity applied as "unstable".

    Anyway, the reason why this is occurring is because whilst a Rigidbody2D will go to sleep on its own based upon its movement, it'll wake up if its in contact with anything that is also awake. This contact propagates and is known as a contact island. This is why when you have, say, a stack of objects and you move one, they all wake up.

    In your situation, you're repositioning the body and telling it to sleep but when the simulation steps, it sees that its in contact with something that is awake so it wakes up. It'll then determine no contacts and it'll eventually go to sleep but in your set-up it'll start falling. Disabling a collider will immediately destroy any contacts as well as the collider shapes it owns which is why this works for you. Note that all you really need to do is disable then immediately enable it.

    I'll add finally that a much quicker way to do what you want to do is to turn off the simulation on the Rigidbody2D then turn it back on again. This will destroy contacts immediately but it doesn't result in things like collider shapes being destroyed. It also works for all attached colliders and disables joints and everything from also waking it. So turn this option off/on should produce the same result and have less overhead.

    A lot of information but useful, maybe for others reading it too.
     
    Last edited: Mar 19, 2020
    Lord_Eniac and Chris-Trueman like this.