Lerping/TweenService with CFrame

Hello there! I’ve hit a roadblock with trying to develop a vehicle chassis where it would rely a lot on CFraming instead of physics.

For this topic, it’s about Steering CFrame lerp! TweenService isn’t really friendly when it is interrupted, for example:

  • TweenService plays CFrame to 90 degrees with linear style.
  • The tween gets interrupted with another tween that goes negative 90 degrees in CFrame with linear style.
  • The result with the second tween is that there is no consistent speed.

I remember once that lerping was a solution to workaround this, but I haven’t really figured out how I was going to do as said. Would I have to convert the distance to target angle into a 0-1 range and find the speed like so?

I’m not sure why you would need to lerp your vehicle’s CFrame in order for it to turn. Can you provide more context about your script? Is it serverside/clientside? Are you working with RunService?

To possibly help in the meantime. For my vehicle script, I used CFrame rotation,
something along the lines of

local vehicleCFrame = CFrame.new() -- default cframe of vehicle, stores both orientation and position

local function rotate(direction, timeDelta)
	-- direction is given in rad/s
	-- timeDelta is the time elapsed since the last rendered frame
	vehicleCFrame = vehicleCFrame * CFrame.Angles(0,direction * timeDelta,0)
end

local function turnLeft(timeDelta)
	rotate(math.rad(45), timeDelta) -- rotate the vehicle clockwise at 45 rad/s
end

local function turnRight(timeDelta)
	rotate(math.rad(45), timeDelta) -- rotate the vehicle clockwise at 45 rad/s
end

local function getCar() -- example function
	return
end

local car = getCar() -- this is where the model of the car is stored
game["Run Service"]:BindToRenderStep("Engine", Enum.RenderPriority.Camera.Value-1, function(timeDelta)
	-- we turn our car to the left at 45 rad/s indefinitely
	turnLeft(timeDelta)
	
	-- once vehicleCFrame is updated, we change the cframe of the actual visual model car
	car:SetPrimaryPartCFrame(vehicleCFrame) 
end)

This is actually a good example! So I’m only doing this CFrame method on the wheels itself to turn, the entire vehicle won’t be moved, it’s just to steer.

What I’d like to have is to CFrame the steering wheels at a controlled speed like hinges and motors where it provides a consistent given speed.

Why don’t you use hinges and motors?

I think in order to get CFrame:Lerp() to work for your case, you would have to call CFrame:Lerp() iteratively every cycle. So movement will be exponential.

I would recommend to store a rotation variable for the steering wheel, then updating the CFrame of the actual steering wheel to reflect the change.

local currentSteeringAngle = 0

If you are using :BindToRenderStep() or a variation of it, you could alter the angle using the time delta.

local turnSpeed = 30 -- turn speed in rad/s
local minAngle = math.rad(-150)
local maxAngle = math.rad(150)

local currentSteeringAngle = 0
local function renderStepped(timeDelta)
	-- turning the wheel left
	currentSteeringAngle = math.clamp(currentSteeringAngle - turnSpeed * timeDelta, minAngle, maxAngle)
	
	-- update the wheel cframe with new angle
end
1 Like

Hinges don’t provide the same behavior as motors where it basically ignores collisions.
I’m trying a new method which is just pure scripts with CFraming and welds.

CFraming the wheel’s turning would be very beneficial and is already showing promise in my tests that patches a lot of bugs that motors couldn’t provide. As said in the original topic post, it will not rely on physics as much. (Anchoring likes to cause a lot of physics issues.)

I’ll look into this, thank you!