Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Creating Pouring Effect. Pour rice grains from a mug if mug has been rotated enough

Discussion in 'Physics' started by TBulbuc, Jul 10, 2020.

  1. TBulbuc

    TBulbuc

    Joined:
    Apr 30, 2020
    Posts:
    21
    Hello,

    I am trying to creating a 'pouring' effect where I can rotate a mug past some angle threshold and have rice grains from inside the mug pour out. To limit the calculations required, I have disabled rice and mug collisions and rely on childing the rice to the mug, then once the mug has been rotated past 90 [deg.], the rice grains parent is set to null and I want them to fall downwards towards the ground/into a cooking pot.

    Right now when I grab the mug and rotate it, the rice grains just fall through the side of the mug opposed to traveling out the top of the mug then downwards ( i.e. pouring) . So I have a 'targetObject' which is a empty gameobject and is a child of the mug. It is set at the top/opening of the mug and I was trying to make the rice grains first travel to the position of this object, then free fall downwards to create a 'realistic' pouring effect , however they are still just falling through the side of the mug. I have tried a bunch of different options/ combination of things to make the rice interact with the physics engine upon the mug tipping past the threshold angle such as: isKinematic() true/false, Sleep/Wake, adding rigidbody components to the grains only after the mug has been tipped, etc.

    The 9 individual rice grains have a box collider and rigidbody component and are parented to an empty gameobject called Rice. The parent Rice object is a child of the mug object at the start of the scene.

    Any insight on how to make this work would be greatly appreciated. Thanks in advance!
    ================================================================================
    Here is the code attached to the mug object:
    Code (CSharp):
    1. using UnityEngine;
    2.  
    3. public class Mug : MonoBehaviour
    4. {
    5.     [SerializeField] private Rice rice;
    6.  
    7.     private float initialAngle;
    8.     private int count = 0;
    9.  
    10.     void Awake()
    11.     {
    12.         this.gameObject.GetComponent<Rigidbody>().velocity = Vector3.zero;
    13.         this.gameObject.GetComponent<Rigidbody>().angularVelocity = Vector3.zero;
    14.         initialAngle = transform.rotation.eulerAngles.y;
    15.     }
    16.  
    17.     void Update()
    18.     {
    19.         //check if mug has been tipped past a threshold
    20.         if(Mathf.Abs(initialAngle - transform.rotation.eulerAngles.y) >= 90)
    21.         {
    22.             if(count == 0)
    23.             {
    24.                 Debug.Log("Mug has been tipped past threshold.");
    25.                 rice.pourRice();
    26.                 count++;
    27.             }
    28.         }
    29.     }
    30. }
    31.  
    ==============================================================================
    Here is the code attached to the parent Rice object ( Rice is a child of the mug, and the parent of the individual rice grains):

    Code (CSharp):
    1.  
    2.  
    3. using UnityEngine;
    4.  
    5. public class Rice : MonoBehaviour
    6. {
    7.     [SerializeField] private Rigidbody[] rigidbodies;
    8.     [SerializeField] private Transform[] transforms;
    9.     [SerializeField] private GameObject targetObject;
    10.     private float speed = 0.5f;
    11.  
    12.     void Awake()
    13.     {
    14.         //Allow the rice transform to be purely controlled by the mug's movement through parent/child relation
    15.         foreach(Rigidbody rb in rigidbodies)
    16.         {
    17.             rb.useGravity = false;
    18.             rb.velocity = Vector3.zero;
    19.             rb.angularVelocity = Vector3.zero;
    20.         }      
    21.         targetObject = GameObject.Find("targetObject");
    22.     }
    23.     public void pourRice()
    24.     {
    25.         Debug.Log("Entered <pourRice()>");
    26.         foreach(Rigidbody rb in rigidbodies)
    27.         {
    28.             Debug.Log("Entered 1st <Foreach> Loop");
    29.             //Allow rice grains to interact w/ physics engine
    30.             rb.useGravity = true;
    31.             rb.velocity = Vector3.zero;
    32.             rb.angularVelocity = Vector3.zero;
    33.         }
    34.         foreach(Transform t in transforms)
    35.         {
    36.             Debug.Log("Entered 2nd <Foreach> Loop");
    37.             t.SetParent(null);
    38.             //Force the rice grains to the edge of the mug
    39.             float distance =  speed * Time.deltaTime; // calculate distance to move (distance = velocity * time)
    40.             Vector3 mugEdge = targetObject.transform.position;
    41.             t.position = Vector3.MoveTowards(t.position, mugEdge, distance);
    42.             Debug.Log("Moving objects to the edge of the mug");
    43.         }
    44.         Debug.Log(" >>> End of <pourRice()> loop <<<");
    45.     }
    46. }