2
\$\begingroup\$

Is there anyway to know if all 2d rigid bodies in untiy 3d phisics world have stopped?

\$\endgroup\$
2
  • 2
    \$\begingroup\$ Other than querying when all rigid bodies are at a stand still, I think this is a pretty open ended question (perhaps primarily opinion based). It's up to you when you want to end the turn. Like allowing X seconds for animated responses, then waiting for all objects to stop. I'd suggest you reword the question to ask only about querying when all objects stop moving. \$\endgroup\$
    – House
    Apr 2 '14 at 15:28
  • \$\begingroup\$ I did what you suggested. After going out for a walk and read your suggestion everything is a bit more clear :). \$\endgroup\$
    – Notbad
    Apr 2 '14 at 16:19
0
\$\begingroup\$

Here's a brute force way to do it...

bool allSleeping = true;
Rigidbody2D[] allBodies = FindObjectsOfType<Rigidbody2D>();

foreach(Rigidbody2D body in allBodies)
{
    if(body.isAwake)
    {
       allSleeping = false;
       break;
    }
}
return allSleeping;

Note that FindObjectsOfType is slow - you don't want to do this every frame. If possible, it's better to cache a list of all Rigidbody2D objects and update it as needed, rather than re-fetching it every time you want to check for awake bodies.

\$\endgroup\$
1
  • \$\begingroup\$ This is one of the ways I implemented it mainly because I am the one pushing the elements in my game after an explosion. I retrieve all the elements in a radius and then push them away. But I thought there were going to be something more high level in the physics system. Thanks anyway. \$\endgroup\$
    – Notbad
    Apr 3 '14 at 10:31
1
\$\begingroup\$

You can create a manager script that keeps count of how many rigidbodies are currently not sleeping as so (VERY simple example):

using System;
using UnityEngine;
using System.Collections;

public class SleepTracker : MonoBehaviour 
{
    public static SleepTracker Instance { get; private set; }

    public event Action onAllObjectsSleeping;

    private int awakeObjects;

    void Awake()
    {
        Instance = this;
    }

    public void IncAwake()
    {
        this.awakeObjects++;
    }

    public void DecrAwake()
    {
        this.awakeObjects--;
        if (this.awakeObjects == 0)
            StartCoroutine(AllObjectsAreSleepingCoroutine());
    }

    private IEnumerator AllObjectsAreSleepingCoroutine()
    {
        yield return new WaitForSeconds(1.0f);
        Debug.Log("All objects are sleeping!");
        if (this.onAllObjectsSleeping != null)
            this.onAllObjectsSleeping();
    }
}

And then, in every object you want to keep track, you just put this component:

using UnityEngine;
using System.Collections;

public class TrackSleep : MonoBehaviour
{
    private bool eventFired;

    void Start ()
    {
        this.eventFired = false;
        this.rigidbody2D.AddForce(new Vector2(4.0f, 0.0f));
        StartTracking();
    }

    private void StartTracking()
    {
        SleepTracker.Instance.IncAwake();
    }

    void Update () 
    {
        if (this.rigidbody2D.IsSleeping() && !this.eventFired)
        {
            SleepTracker.Instance.DecrAwake();
            this.eventFired = true;
        }
    }
}

This way, instead of querying every frame, you simply register/unregister at the correct times. When every rigibody is asleep, the manager will fire the onAllObjectsSleeping event that you can listen to like so:

void Awake()
{
    SleepTracker.Instance.onAllObjectsSleeping += DoSomething;
}

private void DoSomething()
{
    // OMG, everybody's asleep!
}

This is a every simplified implementation, but you should be able to follow the idea.

\$\endgroup\$
1
  • \$\begingroup\$ It is not a bad way of semi authomated tracking. Thanks for the idea. \$\endgroup\$
    – Notbad
    Apr 3 '14 at 10:31

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .