SHIP AND SEA
Aug 8, 2025 - Solo Project - Unity C#
Aug 8, 2025 - Solo Project - Unity C#
My attempt to make a boat physics system that was as close to life as would be feasible. I thought it was also interesting to make the mesh of the water dynamically respond to where the boat was headed. 🦜
Weight of the submerged water is buoyancy force
The difference between the center of mass and the center of buoyancy makes the ship self-center
Computationally expensive to calculate the intersection volume between the water surface and the ship, so we approximate
The hull of the ship is approximated with many differently-sized cubes
Each cube calculates its own buoyancy by sampling a random water height within its volume
Together, they make the ship float
Use layered and scrolling Perlin noise to get the height at any point on the water surface
Visualize waves using a grid of vertices
Wave plane follows ship
Use fog to hide edges of plane
☆ In this method, both the submerged volume is calculated and is given to Ship.cs. The ship needs it to calculate the total drag of the boat  ( if the boat is out of the water it experience far less drag than if it were in the water ). I use some random variance here because it makes the average water reading of floater more accurate.
☆ For context, this is what Ship.cs is doing.Â
The floaters basically do all the work and the ship is there to hold it together.
☆ I use simple Perlin noise with octaves to get the waves right.
            waves = ServiceLocator<IWaveService>.Locate();
            rb.sleepThreshold = 0f;
            totalMaxVolume = 0f;
            floaters = new UniformScaleFloater[floaterHolder.childCount];
            for (int i = 0; i < floaters.Length; i++)
            {
                floaters[i] = floaterHolder.GetChild(i).GetComponent<UniformScaleFloater>();
                floaters[i].Setup();
                totalMaxVolume += floaters[i].MaxVolume;
                floaters[i].gameObject.name = $"floater_{i + 1}";
            }
☆ This is how I initialize the boat. Notice the use of the service locator pattern to locate the wave motion. Both the boat and water mesh rely on this.
<--
GETTING STARTED
The first step is making sure the weight of the boat in relation to the buoyancy force is correct. This can be done by tweaking some values, or by doing some simple calculations. This is to get the boat floating normally.
THE NEXT STEP
The boat from the tutorials had four sample points on the water. This works, but is less realistic the bigger the boat gets and the more variation there is in the water. To get the boat to move more smoothly, more sample points need to be added.Â
BOAT RELATIVE MOTION
I implemented player movement using the CharacterController. To get the player to stay on the boat, the player's speed is equal to to the boat's speed plus the base movement velocity of the player.Â