Custom Water + Ships

How do i calculate the buoyant force of an object? I’m aware that it goes something like **Fb = Vs × D × g . I find it slightly confusing.

For the volume (Vs) you use the volume of the ship thats below the waterline. D is the density, in this case salty water is 1023.6 kg/m³, and g is gravity which can be workspace.Gravity or 198.2.

1 Like

Do you have any methods of sampling the height of water of various points of the hull of the ship? (i’m not sure how to do this)

this is super helpful! thanks!

Well, how do you think the ocean is rendered? Theres some code in there that calculates the Y position of the ocean at a given X,Z coordinate.

If they body position are in different spots this shouldn’t happen unless: the MaxForce isn’t set to (0, n, 0) or the difference between the two heights is more than the distance between the two body positions.

Using a few BodyPositions is probably the easiest way.

Edit:
RatiusRat is correct, I thought there was a ApplyAtCenter property for BodyPositions. The BodyPositions have to affect separate assemblies then, so you’d need to use BallSocketConstraints or hinges–anything that makes a new assembly and connects it to the larger one.

A better way is to calculate the points, find the orientation and position relative to the center of mass, then use a BodyPosition and BodyGyro to position the boat.

2 Likes

In the code with waves I don’t see any Y position, however there are X,Z coordinates

 X = Instance2.CFrame.Position.X,
 Z = Instance2.CFrame.Position.Z

Are these the sample positions i need?

local Wave1 = GerstnerWave(SamplePosition, 150, Vector2.new(1, 0), .05, 1, speedCounter)
							local Wave2 = GerstnerWave(SamplePosition, 175, Vector2.new(0, .3), .2, 1.25, speedCounter)
							local Wave3 = GerstnerWave(SamplePosition, 200, Vector2.new(1, 1), .1, 1.5, speedCounter)
							local TotalDisplacement = Wave1 + Wave2 + Wave3
							bone.Position = origPosTable[bone] + TotalDisplacement

Did you program the ocean? Making a ship base that reacts to waves is very complex so you gotta know what you’re doing.

edit: Not sure, it seems it uses gerstner waves is what I can tell from that

I created this version myself, I saw a post on the dev forum and was inspired by it. I wanted to try it myself. I’m not super experienced in coding, however I managed to create this using a gerstner wave pattern.

will the code i put above work as our sample heights?

Have you tested that theory though? I’ve welded two parts together and both have a bodyposition. They are set at different positions yet only 1 is active while the other is cancelled.

i’m aware that the method that @Soliform is talking about is also used here:

It seems like the code here is using a combination of gerstner waves and adding them together. You can reuse this code for the most part. Basically what I’d do is this:
Sample the ocean height at these points:
image
Then, subtract the left’s position from the right’s and the front’s from the rear’s. This will make vectors pointing through them, like this
image
You can use the green line as the forward vector and the purple line as the right vector. The up vector is the cross product of these two. This is how you calculate the rotation of the ship.
For the position, you can just calculate the y position at the center of mass then subtract it by the waterline height and position the ship there.

Edit: For movement, you’ll need to use a drag equation.

3 Likes

I’ll do this now! Thanks for the help your amazing!

we got a part to float up and down using this code, however we are stuggling to get it to float at angles.

local Controller = require(game.CollectionService:GetTagged("2A9746FA-AD27-46FA-B54C-4468D23213B2")[1])
--local Controller = workspace:WaitForChild("Workspace"):WaitForChild("Ocean"):WaitForChild("Controller")

local displacement = Controller.GetDisplacementAtPosition
local RunService = game:GetService("RunService")

local part = script.Parent

local UpVector = Vector3.new(0, 1, 0)

RunService.Heartbeat:Connect(function()
	local Tile = Controller.Object.Parent.Tiles:FindFirstChildOfClass("MeshPart")
	
	local GlobalMoveCFrame = CFrame.lookAt(Vector3.new(), 
		workspace.CurrentCamera.CFrame.LookVector - workspace.CurrentCamera.CFrame.LookVector:Dot(UpVector) * UpVector, UpVector)
	local GlobalMoveVector = GlobalMoveCFrame:VectorToWorldSpace(Vector3.new(0, 0, 0))
	local Displacement = displacement(part.Position, GlobalMoveVector, part:GetAttribute("Displacement"))
	
	local TargetPosition = part.Position * Vector3.new(1, 0, 1) + Vector3.new(Displacement.X, Tile.Position.Y + Displacement.Y, Displacement.Z)

	part.BodyPosition.Position = TargetPosition
end)

– Gyro

You need something to control rotation, like a BodyGyro or AlignOrientation. Then use the 4 sample points like I showed in the picture and calculate a rotation matrix from them.

1 Like

What do you mean by ‘Sample’ ?

How do you calculate the body gyro?

Like I said, you can get the ocean height at 4 points along the ships hull like I showed in the picture. Then you can do the following:

local xVector = (leftPosition - rightPosition).Unit
local zVector = (forwardPosition - rearPosition).Unit
local yVector = xVector:Cross(zVector)
local gyroCF = CFrame.fromMatrix(Vector3.new(), xVector, yVector, zVector)

1 Like