Search Unity

  1. Looking for a job or to hire someone for a project? Check out the re-opened job forums.
    Dismiss Notice
  2. Unity 2020 LTS & Unity 2021.1 have been released.
    Dismiss Notice
  3. Good news ✨ We have more Unite Now videos available for you to watch on-demand! Come check them out and ask our experts any questions!
    Dismiss Notice

floating a object on water

Discussion in 'Scripting' started by arshiyan, Oct 6, 2009.

  1. Soilyman


    Feb 7, 2017
    Thanks to everyone in this thread for giving me some much needed help on getting started with buoyancy; even this much time later. I tweaked the script based on some of the things posted in here and figured I'd share for anyone else who (like me) stumbles upon this thread via a google search. My script has some properties which are context specific to my game, such as all water volumes being stationary triggers, but hopefully it's simple enough to tweak.

    I decided to change andeeeee's floatHeight variable to a multiplier named buoyancyStrength as I felt this was a more accurate description of what it represents. Some interesting uses I found by playing with this value:
    • buoyancyStrength = -1 - object sinks, accelerating with depth (not that useful but hey)
    • buoyancyStrength = 0 - object sinks only as far as it is forced down by outside forces; does not float back up
    • buoyancyStrength = 1 - a floating object that struggles to take external weight on top
    • buoyancyStrength = 3 - a sturdy floating object that can hold some external weight on top
    I also incorporated a Transform array to add multiple buoyancy points via the inspector; these are empty child objects of the floating object. It's not something I've tried yet, but I imagine it would be possible to use structs or dictionaries and pair each buoyancy point with its own buoyancyStrength variable so that different parts of your object would float differently. I don't know if that would be of any use to anyone but it's just something to consider.

    I also did away with the bounceDamp variable from the original script, as, like Dylan, I also found that the rigidbody's angular drag was more successful in stopping the incessant bobbing. Instead, I have a bobbingDamp variable which simply increases the object's angular drag if it is in the water. The waterLevel is also updated dependant on the body of water which the object is currently in. I can afford this simple fix as all bodies of water in my project are flat and stationary.

    Code (CSharp):
    1. using UnityEngine;
    3. public class Floater : MonoBehaviour {
    4.     [SerializeField] private Transform[] m_BuoyancyPoints;
    5.     [SerializeField] private float m_BuoyancyStrength = 1f;
    6.     [SerializeField] private float m_BobbingDamp = 0.5f;
    8.     private Rigidbody m_ThisRigidbody;
    9.     private bool m_InWater = false;
    10.     private float m_WaterLevel;
    13.     private void Start() {
    14.         m_ThisRigidbody = GetComponent<Rigidbody>();
    15.     }
    17.     private void FixedUpdate () {
    18.         if (m_InWater) {
    19.             foreach (Transform item in m_BuoyancyPoints) {
    20.                 float forceFactor = 1f - (item.position.y - m_WaterLevel) * m_BuoyancyStrength;
    22.                 if (forceFactor > 0f) {
    23.                     Vector3 uplift = -Physics.gravity * (forceFactor - m_ThisRigidbody.velocity.y) / m_BuoyancyPoints.Length;
    24.                     m_ThisRigidbody.AddForceAtPosition(uplift, item.position);
    25.                 }
    26.             }
    27.         }
    28.     }
    30.     private void OnTriggerEnter(Collider other) {
    31.         if (other.CompareTag("Water")) {
    32.             Vector3 waterPosition = other.transform.position;
    33.             float waterHeightExtent = other.GetComponent<MeshRenderer>().bounds.extents.y;
    34.             m_WaterLevel = waterPosition.y + waterHeightExtent;
    36.             m_ThisRigidbody.angularDrag = m_BobbingDamp;
    38.             m_InWater = true;
    39.         }
    40.     }
    42.     private void OnTriggerExit(Collider other) {
    43.         if (other.CompareTag("Water")) {
    44.             m_ThisRigidbody.angularDrag = 0.05f;
    46.             m_InWater = false;
    47.         }
    48.     }
    49. }
    Nyo likes this.
  2. Nyo


    Jan 25, 2011
  3. TheMonkeysaur


    May 2, 2017
    This thread is really interesting, I've been trying this out and with both the originally posted script and the new on above, I still have my object slowly sinking through my water, not sure what I am getting wrong?
  4. SavaTim


    Feb 25, 2017
    Look This