XR: How to detect when a stationary GameObject has been thrown and stops moving?

First, let me apologize as I’m still learning C# and Unity. I have searched extensively through these forums and haven’t found anything that directly answers my question, or isn’t pseudo-code.

I am trying to make a cornhole game, where the user can throw some GameObjects (“bag”) onto another object (“board” that has a Mesh Collider), and I need to run a function (add to the Score) when each bag stops moving. I have a separate Trigger collider just below the hole of the board, to add a different score amount if that item is hit by the “bag” GameObject.

In my scene, on Load, the bags are sitting on a shelf not moving.
The user can pick up these “bag” objects and throw them – I have given each one a Box Collider, a Rigidbody, and the XR Grab Interactable.

I am not sure the best way to go about this.

I have tried adding a Collision script to each “bag” item but it doesn’t seem to be working.

Here’s the code I’ve tried:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CornholeBagCollision : MonoBehaviour
{
    private Rigidbody rb;
    bool IsMoving = false;
    float speed;
    
    void Start()
    {
        var rb = this.GetComponent<Rigidbody>();
    }

    void Update()
    {
        if (IsMoving)
        {
            StartCoroutine(WaitForMoveStops());
        }
    }
    
    public void StartCollisionCheck()
    {
        IsMoving = true;
    }

    private IEnumerator WaitForMoveStops()
    {
        speed = rb.velocity.magnitude;

        Debug.Log("speed: " + speed);

        if (speed < 0.5)
        {
            rb.velocity = new Vector3(0, 0, 0);
            Debug.Log("Bag stopped");
        }
        else 
        {
            Debug.Log("Bag moving");
        }

        yield return null;
    }

}

In the scene, on each “bag” item, under XR Grab Interactible, under Interactable Events > Deactivated, I assigned the script above and have it run the function “StartCollisionCheck”.

My thoughts were:

  • Wait until the player actually throws the GameObject, otherwise we are constantly checking velocity when it’s not moving
  • Detect where the “bag” stops, and add a Score after the movement detection.

I could be way off with this strategy.

Any help is appreciated!

I think you don’t need the coroutine architecture here - you could just test for the bag moving in Update, using similar code but simplify it to something like this (in Update):

var WasMoving = IsMoving;
IsMoving = rb.velocity.magnitude < 0.5f;
if (WasMoving && !IsMoving)
{
    Debug.Log($"Bag {this} was moving, but has now stopped.", this);
}

This is just written by hand and not tested.

FYI, referencing the game object with “this” as 2nd parameter in Debug.Log means you can click it in the log and it will be highlighted in the Heirarchy.

Also: I know you’re worried about performance, but putting this in Update (and having it check every frame) won’t be too much of an overhead, I’d get it working first before you worry about optimisation at that level. It also has the advantage that if another bag nudges this bag, you’ll still detect it.