Making a Boat Tilt

I’m working on a boat script, and I want the boat to tilt with BodyGyro, the problem is if I do it like that then turning the boat left and right to steer will effect the way the boat turns differently.

seat = script.Parent
gyro = seat.BodyGyro
pos = seat.BodyPosition
vel = seat.BodyVelocity

pos.position = seat.Position
gyro.cframe = seat.CFrame
speed = 0
ready = true
wait()
seat.Anchored = false

local movingRight = false
local movingLeft = false

function move(property)
	if property == "Steer" then
		if not ready then
			return
		end
		ready = false
		local steer = seat.Steer
		while steer ~= 0 do
			steer = seat.Steer
			if steer == 1 then
				movingRight = true
				movingLeft = false
				gyro.cframe = gyro.cframe * CFrame.fromEulerAnglesXYZ(0,-.1,0)
			elseif steer == -1 then
				movingLeft = true
				movingRight = false
				gyro.cframe = gyro.cframe * CFrame.fromEulerAnglesXYZ(0,.1,0)
			end
			wait()
			vel.velocity = seat.CFrame.lookVector * speed
		end
		ready = true
	elseif property == "Throttle" then
		while property == "Throttle" do
			local throttle = seat.Throttle
			if throttle == 1 and speed < seat.MaxSpeed then
				speed = speed + 1
			elseif throttle == -1 and speed > 0 then
				speed = speed - 1
			end
			wait(.1)
			vel.velocity = seat.CFrame.lookVector * speed
		end
		
	end
end

seat.Changed:connect(move)
10 Likes

I’ve learned that the best way to control a boat in Roblox. Is to not control a boat in Roblox. Now this is gonna sound crazy but.

I make my boat get represented by a single part. Then I manipulate that part. The only thing the boat needs to do is match its orientation with that part. You get pretty natural behavior like this.

That’s exactly what this script does, however it still doesn’t solve the issue in the matter. When you rotate the boat, it’s on the X coordinate, but tilting it would mess up the coordinate making the boat float in the air sorta.

You can tell I’m only manipulating 1 part because the first variable is Seat = script.Parent

EDIT: Also when I say making the boat tilt I mean the bodygyro manipulating the seat

1 Like

Yeah I don’t use any “real” bodymovers in the boat. The ones I use are these.

I actually can’t see what the problem would be with your code. It’s not like you’re rotating it on two axis at the same time… Have you tried dropping the force values on axis you aren’t manipulating?

The script I showed you has 0 problems at all. The problem is when I try to add to the Z axis for the gyro. It’s supposed to tilt the way you turn, that’s the way I’m trying to make it. Here’s an example of what worked, but not the way I planned it to;

gyro.cframe = gyro.cframe * CFrame.fromEulerAnglesXYZ(0,-.1,.3) -- added to the Z Axis

After doing this in the script, it forces the boat to spin in circles rather than tilting. I just want it to tilt the boat which way youre steering

The Y axis will rotate the ship in a circle. In this case though you’re manipulating both axis at once. You should modify the Z axis on another line to rotate on the Y first then Z. In this case you’re rotating on the Y and Z at the same time so you’re ending up with entirely different behavior.

I’ll give that a try real quick.

same problem;
https://gyazo.com/f8bb04d956dd6b4c7434871069be03f7

I did as said this way;

	gyro.cframe = gyro.cframe * CFrame.fromEulerAnglesXYZ(0,0,0)
	gyro.cframe = gyro.cframe * CFrame.fromEulerAnglesXYZ(0,0,.1)
2 Likes

Hmm :thinking: that’s all I know :sob:

Instead of doing gyro.CFrame = gyro.CFrame * ..., which is additive, I think you should include it in a fresh construction of the CFrame.

This is usually done by checking each frame or so if a WASD key is held down, and if it is, add it to a variable that creates the CFrame. It won’t be needed here though since you check using Steer.

It looks like we can do this all in your steer block, and you have your logic built for it already.

So what I would do is have a steerY variable outside of move that adds/subtracts 0.1 when steering in a direction, and assign Z to a specific number based on which direction it’s steering in as well. Then I would construct a brand new CFrame, independent from the last, with Z in mind already:

local steerY = 0

-- in your steer block
if not ready then return end
ready = false
local steer = seat.Steer
while steer ~= 0 do
    steer = seat.Steer
    local steerZ = 0
    if steer == 1 then
        movingRight = true
        movingLeft = false
        steerY = steerY - 0.1
        steerZ = 0.3
    elseif steer == -1 then
        movingRight = false
        movingLeft = true
        steerY = steerY + 0.1
        steerZ = -0.3
    end
    gyro.CFrame = CFrame.Angles(0, steerY, 0) * CFrame.Angles(0, 0, steerZ)
end
-- end steer block

This new steer should do what you want. You might want to change the signs on steerY and steerZ operations, though they should be opposite from each other when steering in the other direction.

7 Likes

OK, here is my crazy idea.

What if you created an alternating loop.
The loop applies the one axis of force on evens. Wait .2 second, then applies the other axis of force on odd runs.

This reduces the stress on the physics engine but could get the same desired result. I find what is right and what works are often two different things.

2 Likes

Make the velocity not act out in the Y axis by making the MaxForce in the Y axis 0, then it shouldn’t fly upwards or downwards at all.

Also for the tilting, remeber that you’re making the gyro tilt continously on it’s same position constantly, you should probably only want to turn based on the seating. Maybe add some variables if you don’t want it to tilt too far.

I did this exact thing a while back, what i did was create a motor that had two parts: a handle and a controller. The handle was the part1, and all of the other ship parts were welded to it. The controller was the part0, and it had a gyro force along with a velocity force. To turn the ship or move it, I would modify the forces on the controller. To tilt it I would just set the desired angle of the motor. The controller was the master object; it was in charge of all of the ship’s movement and I could easily do all sorts of things with it. Meanwhile, having that motor that indirectly connected it to the rest of the parts on the ship allowed for a nice swaying mechanic to have on the side.

(Edit; this wasn’t intentionally replying to goldenstein)

Don’t use a gyro, just use a RootPart and CFrame it. No reason to use a gyro, you end up with weird behaviour like this.

To get the same nice rocking motions (i.e accelerating through the middle, decelerating towards the end of the title) you can use a mathematical function. Your code will look a little like this

local rad = 180/math.pi --convert degrees to radians 
local maxSway = 20 * rad
local swayTime = 5 -- the time for it to go from 20 degrees one way, to the other

local boat = workspace.Boat

local startTime = tick()

function easingStyle(i)
--this function basically has to take a number 0-1 and return a number from -1 to 1 with some easing effect added.
   i = (i-.5) * 2
   return -1 + 2 * i ^ 2
end

game:GetService("RunService").HeartBeat:Connect(function()
   local runTime = tick() - startTime
   local animationProgress = (runTime % swayTime)/swayTime -- return a scalar 0-1
  
   local swayRadians = (maxSway * animationProgress)
   boat:SetPrimaryPartCFrame(CFrame.new(boat.PrimaryPart.CFrame.p) * CFrame.Angles(swayRadians, 0, 0)
end)

some of the logic there is probably wrong, but its a pretty simple calculation to set up

3 Likes

Blockquote
local seat = script.Parent
local speed = 0
local bv = script.Parent.BodyVelocity
local bg = script.Parent.BodyGyro

seat.Changed:Connect(function(Direction)
if Direction == “Thtottle” then
wait()
if seat.Throttle == 1 then
if speed < seat.MaxSpeed then
speed = speed + 0.5
end

		bv.Velocity = script.Parent.CFrame.LookVector * speed
	elseif seat.Throttle == 0 then
		if speed > 0 then 
			speed = speed
		elseif speed < 0 then 
			speed = speed + 0.5
		end
		
		bv.Velocity = script.Parent.CFrame.LookVector * speed 
	elseif seat.Throttle == -1 then 
		if speed > -seat.MaxSpeed then
			speed = speed
		end
		
		bv.Velocity = script.Parent.CFrame.LookVector * speed 
	end
	
	if seat.Steer == 1 then 
		bg.CFrame = bg.CFrame * CFrame.fromEulerAnglesXYZ(0, -math.rad(1), 0) 
	elseif seat.Steer == -1 then 
		bg.CFrame = bg.CFrame * CFrame.fromEulerAnglesXYZ(0, math.rad(1), 0)
	end
end

end

Blockquote

I did this for my boat but it won’t work. It erroring on this part of script.

seat.Changed:Connect(function(Direction)
Any help.
if Direction == “Thtottle” then