Vehicle steering lag

I’m trying to make a suspension car. It works, and in studio it’s very responsive, but in the game client there’s a huge delay when steering. I tried to switch the script to a local script but then it doesn’t drive at all. I also tried setting network ownership, but it didn’t make any difference.

Server script:

-- get the specifications
local speed = script.speed.Value
local accleration = script.acceleration.Value
local steeringspeed = script.steeringSpeed.Value
local steeringangle = script.steeringAngle.Value

-- set up the shortcuts
local vehicle = script.Parent.Parent
local seat = script.Parent

-- find the tires
local A	= vehicle.A		-- front left
local AA = vehicle.AA	-- front right
local B = vehicle.B		-- back left
local BB = vehicle.BB	-- back right

-- find the steering mechanism
local steerA = vehicle.SteeringA.Servo
local steerB = vehicle.SteeringB.Servo


-- set up wheels' motor accerlation
A.Motor.MotorMaxTorque = accleration
AA.Motor.MotorMaxTorque = accleration
B.Motor.MotorMaxTorque = accleration
BB.Motor.MotorMaxTorque = accleration

local VehicleSeat = script.Parent
 
VehicleSeat.Changed:Connect(function(prop)
	if prop == "Occupant" then
		local humanoid = VehicleSeat.Occupant
		if humanoid then
			local player = game:GetService("Players"):GetPlayerFromCharacter(humanoid.Parent)
			if player then
				VehicleSeat:SetNetworkOwner(player)
			end
		else
			VehicleSeat:SetNetworkOwnershipAuto()
		end
	end
end)

while true do
	-- power the wheels
	velocity = seat.Throttle * speed -- use the seat's throttle to determine the wheels' action (backward? forward? nothing?)
	A.Motor.AngularVelocity = velocity
	AA.Motor.AngularVelocity = velocity
	B.Motor.AngularVelocity = -velocity
	BB.Motor.AngularVelocity = -velocity
	wait()
	-- steering
	steering = seat.Throttle * speed
	steerA.AngularSpeed = steeringspeed
	steerA.ServoMaxTorque = 100000000
	steerA.TargetAngle = steeringangle*seat.Steer
	steerB.AngularSpeed = steeringspeed
	steerB.ServoMaxTorque = 100000000
	steerB.TargetAngle = steeringangle*seat.Steer
end

Any help would be appreciated. :slightly_smiling_face:

4 Likes

Vehicle movement such as steering and acceleration should be all handled on the client. The only time the server comes in is when you do checks for speed hacks, teleporting vehicles, customization, tuning etc.

Setting the network owner to the client will not do anything if the server is still responsible for turning the wheels.

As I said, I tried to switch the script to a local script, but the car wouldn’t move.

May I ask how exactly did you attempt switch the script to local?

I used the class converter plugin.

This may be the issue. Converting code in a normal script is not as simple as moving all the code to a local script. Not all API, Properties, Objects etc. that are on the server are available locally. It’s sometimes much more complicated than that.

I cannot provide any further solutions as the code you provided is pretty limited.

What do you mean by limited? It is the entire script that controls the vehicle.

Sorry, I meant that it may require a full inspection of all the scripts of the vehicle to actually identify where the problem is. In the code you provided above, the only issue I see is using :SetNetworkOwner because this is only available to the server, not locally. Aside from that, the code above should work on a local script, so the issue may be somewhere else.

The only other script inside the vehicle is the sound script, and there are no errors in the output at all.

Are there other scripts (Inside ServerStorage, StarterGui, StarterPlayer, etc.) that the vehicle needs in order to work?

No, just the script I provided.

How about the control script? Can you post the script that the player uses to control the vehicle?

Not sure what you mean by that. The script I provided is the only script used.

How is the vehicle controlled by a player?

Through the script I included in the post.

Local Script in StarterPlayerScripts:

--services
local Workspace = game:GetService("Workspace")
-- get the specifications
local speed = script.speed.Value
local accleration = script.acceleration.Value
local steeringspeed = script.steeringSpeed.Value
local steeringangle = script.steeringAngle.Value

-- set up the shortcuts
local vehicle = Workspace:WaitForChild("Vehicle") --change "Vehicle" to the name of the vehicle model
local seat = vehicle:WaitForChild("Seat") --change "Seat" to the name of the driver seat

-- find the tires
local A	= vehicle.A		-- front left
local AA = vehicle.AA	-- front right
local B = vehicle.B		-- back left
local BB = vehicle.BB	-- back right

-- find the steering mechanism
local steerA = vehicle.SteeringA.Servo
local steerB = vehicle.SteeringB.Servo


-- set up wheels' motor accerlation
A.Motor.MotorMaxTorque = accleration
AA.Motor.MotorMaxTorque = accleration
B.Motor.MotorMaxTorque = accleration
BB.Motor.MotorMaxTorque = accleration

local VehicleSeat = script.Parent

while true do
	-- power the wheels
	velocity = seat.Throttle * speed -- use the seat's throttle to determine the wheels' action (backward? forward? nothing?)
	A.Motor.AngularVelocity = velocity
	AA.Motor.AngularVelocity = velocity
	B.Motor.AngularVelocity = -velocity
	BB.Motor.AngularVelocity = -velocity
	wait()
	-- steering
	steering = seat.Throttle * speed
	steerA.AngularSpeed = steeringspeed
	steerA.ServoMaxTorque = 100000000
	steerA.TargetAngle = steeringangle*seat.Steer
	steerB.AngularSpeed = steeringspeed
	steerB.ServoMaxTorque = 100000000
	steerB.TargetAngle = steeringangle*seat.Steer
end

Normal Script in ServerScriptService:

local vehicle = Workspace:WaitForChild("Vehicle") --change "Vehicle" to the name of the vehicle model
local seat = vehicle:WaitForChild("Seat") --change "Seat" to the name of the driver seat

seat.Changed:Connect(function(prop)
	if prop == "Occupant" then
		local humanoid = VehicleSeat.Occupant
		if humanoid then
			local player = game:GetService("Players"):GetPlayerFromCharacter(humanoid.Parent)
			if player then
				VehicleSeat:SetNetworkOwner(player)
			end
		else
			VehicleSeat:SetNetworkOwnershipAuto()
		end
	end
end)

Give this a try, however read the comments in the code

Any reason why to put the local script in starter player scripts?

It’s just a development practice. I don’t like placing local scripts in starter gui or in the backpack. Also, do note that local scripts only work in certain places, local scripts do not run when it is a descendant of the workspace, server script service, etc (player’s character is an exception)

Would it be best to put the server script in the vehicle? There are multiple vehicles so that wouldn’t work.

Having multiple copies of one script that does the same thing is not efficient memory wise. You could have one script that has a reference to every vehicle in the game and use a loop to listen to every seats’ event:

local Workspace = game:GetService("Workspace")

local Vehicles = {
    Workspace.Vehicle_1,
    Workspace.Vehicle_2,
    Workspace.Vehicle_3,
}

local function OnSeatChanged(prop)
	if prop == "Occupant" then
		local humanoid = VehicleSeat.Occupant
		if humanoid then
			local player = game:GetService("Players"):GetPlayerFromCharacter(humanoid.Parent)
			if player then
				VehicleSeat:SetNetworkOwner(player)
			end
		else
			VehicleSeat:SetNetworkOwnershipAuto()
		end
	end
end

for i, v in ipairs(Vehicles) do
    v.seat.Changed:Connect(OnSeatChanged)
end

Or if all the vehicles are placed in one folder/model, then you could do this:

local Workspace = game:GetService("Workspace")
local VehiclesContainer = Workpace:WaitForChild("Vehicles")

local function OnSeatChanged(prop)
	if prop == "Occupant" then
		local humanoid = VehicleSeat.Occupant
		if humanoid then
			local player = game:GetService("Players"):GetPlayerFromCharacter(humanoid.Parent)
			if player then
				VehicleSeat:SetNetworkOwner(player)
			end
		else
			VehicleSeat:SetNetworkOwnershipAuto()
		end
	end
end

for i, v in ipairs(VehiclesContainer:GetChildren()) do
    v.seat.Changed:Connect(OnSeatChanged)
end
2 Likes