How can I detect when multiple rigid body velocities are under 0.1?

51 Views Asked by At

I am developing an 8 ball pool/billiards game in which I want to find out when all the balls on the table stop.

I tried using this piece of code however the number of balls that have stopped keeps on incrementing to massive numbers when the value should be 16 or less.

    IEnumerator CheckObjectsHaveStopped()
    {
        bool allSleeping = false;
        Rigidbody[] GOS = FindObjectsOfType(typeof(Rigidbody)) as Rigidbody[];
        while (!allSleeping)
        {
            allSleeping = true;
            foreach (Rigidbody GO in GOS)
            {
                if (GO.velocity.magnitude <= 0.1)
                {
                    Balls_Stopped += 1;
                    Debug.Log("Balls Stopped = " + Balls_Stopped);
                    yield return null;
                }
            }

        }

        if (Balls_Stopped == Balls_Left)
        {
            print("All objects sleeping");
            //Do something here
        }
    }
2

There are 2 best solutions below

4
Stankeneddy774 On

Depending on your implementation requirements, it may be easier to treat each Ball as their own object. Then you can add a method/property to the Ball object such as "IsMoving".

I also recommend either serializing these ball objects in the inspector, or using FindObjectsOfType once at the beginning of your game so it is not impacting the performance of your game.

For example:

//Ball.cs

[RequireComponent(typeof(Rigidbody))]
public class Ball : MonoBehaviour {
    private Rigidbody rigidbody;

    public bool IsMoving => rigidbody.velocity.magnitude > 0.1f;

    private void Awake() {
        rigidbody = GetComponent<Rigidbody>();
    }
}

//Ball managing script
public class BallManagerScript : MonoBehaviour {
    private Ball[] balls;

    private void Awake() {
        balls = FindObjectsOfType<Ball>();
    }

    public bool CheckIfAnyBallsAreMoving() {
        foreach (Ball ball in balls) {
            if (ball.IsMoving) return true;
        }

        return false;
    }
}

This will allow you to have an array of Balls, which you can cycle through and check if each independent one is moving. From there, use that function to see if any of the balls are moving.

Make sure to add the Ball script to all balls in your game, so they can be referenced and checked.

using [RequireComponent(typeof(Rigidbody))]will ensure that each GameObject that Ball is attached too, will have a Rigidbody (because your script has a depdendency of Rigidbody)

0
derHugo On

Using LINQ you could do:

using System.Linq;

...

var allStopped = GOS.All(r => r.velocity.magnitude <= 0.1f);