Search Unity

Question Buoyancy

Discussion in 'Physics' started by tysongrunter, Apr 18, 2023.

  1. tysongrunter

    tysongrunter

    Joined:
    Mar 25, 2023
    Posts:
    19
    Okay, I am planning on adding bodies of water into a video game I'm making. I want to have a buoyancy system, where if an rigidbody (including that of the player character) is in the water (which I have as trigger colliders), it compares the water's density to the object's, to determine if it floats or sinks. Objects denser than the water (density is stored as a float) will sink, and objects less dense than the water will float. How would I go about doing that?
     
  2. yant

    yant

    Unity Technologies

    Joined:
    Jul 24, 2013
    Posts:
    596
    Assuming you want to apply the Archimedes principle here, which basically states that the buoyant force is equal to the weight of the fluid displaced by the submerged object, you'd need to calculate how deep in the water each shape is every frame. From there, you calculate the submerged volume, multiply that by gravity and the water density and apply as the force acting directly up. That will target exactly counteracting the weight of the bodies in water at some penetration depth (if possible). Calculating submerged volumes is easier done with primitive shapes.
     
    Edy likes this.
  3. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,491
    As above but if you're asking about 2D physics then exactly what you ask for is provided by the BuoyancyEffector2D.
     
    yant likes this.
  4. tysongrunter

    tysongrunter

    Joined:
    Mar 25, 2023
    Posts:
    19
    I'm building a 3D game.
     
    MelvMay likes this.
  5. tysongrunter

    tysongrunter

    Joined:
    Mar 25, 2023
    Posts:
    19
    Okay, I've been able to make a rudimentary buoyancy system where objects less dense than water will float to the surface if submerged, and objects denser than water will sink to the bottom. I've added those physics to the grabbable objects the player can pick up, carry, and throw, and the player character has a rigidbody and a head check that detects if the player submerges her head below water. Here's the script I'm using to run the events for if the objects are in the water or not:
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class Water : MonoBehaviour
    6. {
    7.     //holds the rigidbody of whatever comes into contact with it
    8.     [SerializeField]
    9.     private Rigidbody rb;
    10.     //holds the density of the water
    11.     public float waterDensity;
    12.     //gets the player script
    13.     [SerializeField]
    14.     private Aquatic aquatic;
    15.     //gets the grabbable script
    16.     [SerializeField]
    17.     private Grabbable grabbable;
    18.  
    19.     //gets the rigidbody of objects put in water
    20.     private void Awake()
    21.     {
    22.         /*rb = gameObject.GetComponent<Rigidbody>();
    23.         player = gameObject.GetComponent<Player>();
    24.         grabbable = Object.FindObjectOfType<Grabbable>();*/
    25.     }
    26.  
    27.     //applies force of buoyancy when the object enters the water
    28.     private void OnTriggerEnter(Collider other)
    29.     {
    30.         Grabbable submergeCheck = other.GetComponent<Grabbable>();
    31.         submergeCheck.isSubmerged = true;
    32.         other.transform.gameObject.SendMessage("FloatInWater", waterDensity);
    33.         Aquatic playerHead = other.GetComponent<Aquatic>();
    34.         playerHead.isSubmerged = true;
    35.         other.transform.gameObject.SendMessage("FloatInWater", waterDensity);
    36.     }
    37.  
    38.     //removes force of buoyancy when the object exits the water
    39.     private void OnTriggerExit(Collider other)
    40.     {
    41.         Grabbable submergeCheck = other.GetComponent<Grabbable>();
    42.         submergeCheck.isSubmerged = false;
    43.         Aquatic playerHead = other.GetComponent<Aquatic>();
    44.         playerHead.isSubmerged = false;
    45.     }
    46. }
    While the buoyancy works for grabbable objects, it doesn't work for the player. Why is that? And how could I fix it?

    SOLVED: I've been able to get my rudimentary buoyancy to work. Here's the code I use for the water:
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class Water : MonoBehaviour
    6. {
    7.     //holds the rigidbody of whatever comes into contact with it
    8.     [SerializeField]
    9.     private Rigidbody rb;
    10.     //holds the density of the water
    11.     public float waterDensity;
    12.     //gets the player script
    13.     [SerializeField]
    14.     private Aquatic aquatic;
    15.     //gets the grabbable script
    16.     [SerializeField]
    17.     private Grabbable grabbable;
    18.  
    19.     //gets the rigidbody of objects put in water
    20.     private void Awake()
    21.     {
    22.         /*rb = gameObject.GetComponent<Rigidbody>();
    23.         player = gameObject.GetComponent<Player>();
    24.         grabbable = Object.FindObjectOfType<Grabbable>();*/
    25.         aquatic = Object.FindObjectOfType<Aquatic>();
    26.     }
    27.  
    28.     //applies force of buoyancy when the object enters the water
    29.     private void OnTriggerEnter(Collider other)
    30.     {
    31.         if(other.TryGetComponent<Grabbable>(out Grabbable grabbable))
    32.         {
    33.             //Grabbable submergeCheck = other.GetComponent<Grabbable>();
    34.             grabbable.isSubmerged = true;
    35.             other.transform.gameObject.SendMessage("FloatInWater", waterDensity);
    36.         }
    37.         else if(other.TryGetComponent<Aquatic>(out Aquatic aquatic))
    38.         {
    39.             //Aquatic playerHead = other.GetComponent<Aquatic>();
    40.             aquatic.isSubmerged = true;
    41.             other.transform.gameObject.SendMessage("FloatInWater", waterDensity);
    42.         }
    43.     }
    44.  
    45.     //removes force of buoyancy when the object exits the water
    46.     private void OnTriggerExit(Collider other)
    47.     {
    48.         if(other.TryGetComponent<Grabbable>(out Grabbable grabbable))
    49.         {
    50.             //Grabbable submergeCheck = other.GetComponent<Grabbable>();
    51.             grabbable.isSubmerged = false;
    52.         }
    53.         else if(other.TryGetComponent<Aquatic>(out Aquatic aquatic))
    54.         {
    55.             //Aquatic playerHead = other.GetComponent<Aquatic>();
    56.             aquatic.isSubmerged = false;
    57.         }
    58.        
    59.     }
    60. }
    61.  
     
    Last edited: Apr 19, 2023