Need help with trigonometry and math.sign (angle calculation for boats)

Hey there,

I have been working with custom water for about a while now.

So, to solve how much my boat should tilt (both axis, X and Z) I use this calculation

local hFront = bowPos.Y - sternPos.Y
local bFront = (bow.WorldPosition - stern.WorldPosition).Magnitude
		
local angleFront = math.atan(hFront / bFront) * math.sign(sternPos.X - bowPos.X)
		
local hSide = portPos.Y - starboardPos.Y
local bSide = (port.WorldPosition - starboard.WorldPosition).Magnitude

local angleSide = math.atan(hSide / bSide) * math.sign(starboardPos.Z - portPos.Z)

bow, port, starboard and stern are the actual positions of the respective corners of the boat (if you dont know search them up)

bowPos, portPos, starboardPos and sternPos is the wave height at the respective corners of the boat.

Now, when I test it everything looks good

But, when I turn the boat 90d, everything gets ruined (both angles)

I believe its the sign values being incorrect.

  • Is there any better alternative I can use for angle calculation (which also gets rid of this issue?) I tried math.atan2 but its the same thing.
  • Am I doing all calculations properly? (Is the sign wrong or is something else wrong?)

Thanks in advance and have a great day.

Correct me if I am wrong, but I believe your math.sign() functions are only limited to one axis, so when the boat is facing in the Z direction, your math.sign() for angleFront is still measuring the difference in X between the portPos and bowPos, which in that instance would be equal. Same goes with angleSide. It doesn’t seem like the angles of the boat are going too crazy so signage might be the issue as you suspected. Let me know if this is true :slight_smile:

On second thought, the differences in height in hFront and hSide should yield you a sign already, so is it actually necessary to have math.sign() functions to apply signage to your angle?

I would recommend just using vectors:

local boatPos = -- Your boat's position, or 0,0,0 if this CFrame is only going to be used for rotation
local xVector = (portPos - starboardPos).Unit
local zVector = (bowPos - sternPos).Unit
local yVector = zVector:Cross(xVector)
local targetCFrame = CFrame.fromMatrix(boatPos, xVector, yVector, zVector)
2 Likes

Hm, nice info. Thats probably the reason why it ruins the angles

I do get a sign value, but its the same as what I did earlier.

1 Like

Damn that works so great!!!

2 Likes