Trailer won't unhook

So I am trying to make it so that when you press Y then the trailer will unhook and when you are close to the trailer and it is detached then if you press Y then it will attach the trailer. The script is a server script inside of the semi truck. There are no errors.

Code
local IsDetached = false
local trailer = script.Parent.Parent.Trailer
local Body = script.Parent.Parent.Body
local TrailerHook = Body["Meshes/Semitruck1_hitch"]
local Detector = script.Parent.Parent.Chassis.Detector
local Main = trailer.Chassis.Main
trailer.PrimaryPart = Main

script.Parent.Parent.Chassis.VehicleSeat.Touched:Connect(function(hit)
	if hit.Parent:FindFirstChild("Humanoid") then
		local UserInputService = game:GetService("UserInputService")
		UserInputService.InputBegan:Connect(function(input)
			if input.KeyCode == Enum.KeyCode.Y then
				if IsDetached == false then
					trailer:SetPrimaryPartCFrame(TrailerHook.Cframe * CFrame.new(0, -0.016, -15))
					IsDetached = true
				elseif IsDetached == true then
					Detector.Touched:Connect(function(hit)
						if hit == Main then
							trailer:SetPrimaryPartCFrame(TrailerHook.Cframe * CFrame.new(0, -0.016, 0))
							IsDetached = false
						end
					end)
				end
			elseif input.KeyCode == Enum.KeyCode.ButtonY then
				if IsDetached == false then
					trailer:SetPrimaryPartCFrame(TrailerHook.Cframe * CFrame.new(0, -0.016, -15))
					IsDetached = true
				elseif IsDetached == true then
					Detector.Touched:Connect(function(hit)
						if hit == Main then
							trailer:SetPrimaryPartCFrame(TrailerHook.Cframe * CFrame.new(0, -0.016, 0))
							IsDetached = false
						end
					end)
				end
			end
		end)
	end	
end)
Updated Code

Server Script:

local Workspace = game:GetService("Workspace")
local RunService = game:GetService("RunService")
local UserInputService = game:GetService("UserInputService")

local PackagedScripts = script.Parent
local PackagedVehicle = PackagedScripts.Parent

local constraints = PackagedVehicle:WaitForChild("Constraints")
local VehicleConfig = PackagedVehicle:WaitForChild("Configuration", 10)
if not VehicleConfig then
	warn("No vehicle configuration present, will use default values")
end

local mphConversion = 0.6263 -- using a 28cm = 1stud conversion rate
-- local kphConversion = 1.008 -- using the same conversion rate, but if you prefer KPH, replace mphConversion with kphConversion wherever it appears in the code

--[[ Chassis Variables ]]--
local VehicleParameters = { -- These are default values in the case the package structure is broken
	MaxSpeed = 75/mphConversion,
	ReverseSpeed = 45/mphConversion,
	DrivingTorque = 30000,
	BrakingTorque = 70000,
	StrutSpringStiffnessFront = 28000,
	StrutSpringDampingFront = 1430,
	StrutSpringStiffnessRear = 27000,
	StrutSpringDampingRear = 1400,
	TorsionSpringStiffness = 20000,
	TorsionSpringDamping = 150,
	MaxSteer = 0.55,
	WheelFriction = 2
}

local Chassis = nil
local LimitSteerAtHighVel = true
-- Limits the amount you can steer based on velocity. Helpful for keyboard/non-analog steer inputs
local SteerLimit = 0.2 -- Max amount the steering float (-1 to 1) will be limited by if limitSteerAtHighVel is true

local DoGravityAdjust = true -- Adjust chassis values based on the current gravity setting.
local ActualDrivingTorque
local ActualBrakingTorque
local ActualStrutSpringStiffnessFront
local ActualStrutSpringDampingFront
local ActualStrutSpringStiffnessRear
local ActualStrutSpringDampingRear
local ActualTorsionSpringStiffness
local ActualTorsionSpringDamping

-- Adjust torque and springs based on gravity to keep the car drivable
local function gravityAdjust()
	local defaultGravity = 196.2
	local actualGravity = Workspace.Gravity
	local gravityChange = actualGravity / defaultGravity
	-- Speed is adjusted so that the height of jumps is preserved
	-- So maxSpeed is scaled proportionally to the sqrt of gravity
	ActualDrivingTorque = VehicleParameters.DrivingTorque * gravityChange
	ActualBrakingTorque = VehicleParameters.BrakingTorque * gravityChange

	ActualStrutSpringStiffnessFront = VehicleParameters.StrutSpringStiffnessFront * gravityChange
	ActualStrutSpringDampingFront = VehicleParameters.StrutSpringDampingFront * math.sqrt( gravityChange )
	ActualStrutSpringStiffnessRear = VehicleParameters.StrutSpringStiffnessRear * gravityChange
	ActualStrutSpringDampingRear = VehicleParameters.StrutSpringDampingRear * math.sqrt( gravityChange )

	ActualTorsionSpringStiffness = VehicleParameters.TorsionSpringStiffness * gravityChange
	ActualTorsionSpringDamping = VehicleParameters.TorsionSpringDamping * math.sqrt( gravityChange )
end

local function updateFromConfiguration()
	for property, value in pairs(VehicleParameters) do
		local configProp = VehicleConfig:FindFirstChild(property)
		if configProp then
			if property == "MaxSpeed" or property == "ReverseSpeed" then
				VehicleParameters[property] = configProp.Value/mphConversion -- convert to studs/sec
			else
				VehicleParameters[property] = configProp.Value
			end
		end
	end
end

local updateEvents
if VehicleConfig then
	updateFromConfiguration()
	
	updateEvents = {}
	local props = VehicleConfig:GetChildren()
	for i = 1, #props do
		updateEvents[props[i].Name] = props[i].Changed:connect(function(value)
			VehicleParameters[props[i].Name] = value
			if DoGravityAdjust then
				gravityAdjust()
			end
			if Chassis then
				Chassis.InitializeDrivingValues() -- reinitialize chassis so that changes are reflected in the rig
			end
		end)
	end
end

if DoGravityAdjust then
	gravityAdjust()
end

workspace.Changed:Connect(function(prop)
	if prop == "Gravity" then
		if DoGravityAdjust then
			gravityAdjust()
		end
		if Chassis then
			Chassis.InitializeDrivingValues() -- reinitialize chassis so that changes are reflected in the rig
		end
	end
end)

local Motors
local SteeringPrismatic
local RedressMount

--[[ Private Functions ]]--
local function getVehicleMotors()
	local motors = {}
	for _, c in pairs(constraints:GetChildren()) do
		if c:IsA("CylindricalConstraint") then
			table.insert(motors, c)
        end
    end
	return motors
end

local function getSprings(springType)
	local springs = {}
	local trailer = PackagedVehicle:FindFirstChild("Trailer")
	
	local function search(children)
		local searchStrutSpring = "StrutSpring"
		local searchFrontSpring = "StrutSpringF"
		local searchTorsionSpring = "TorsionBarSpring"
		for _, c in pairs(children) do
			if c:IsA("SpringConstraint") then
				if springType == "StrutFront" then
					if string.find(c.Name, searchFrontSpring) then
						table.insert(springs, c)
					end
				elseif springType == "StrutRear" then
					if (not string.find(c.Name, searchFrontSpring)) and string.find(c.Name, searchStrutSpring) then
						table.insert(springs, c) -- we have option of Mid and Rear for these
					end
				elseif springType == "TorsionBar" then
					if string.find(c.Name, searchTorsionSpring) then
						table.insert(springs, c)
					end
				end
			end
		end
	end

	search(constraints:GetChildren())
	if trailer then
		trailer.Body["Meshes/Trailer1_Trailer1.010"].Touched:Connect(function(hit)
			if hit.Parent == trailer.Parent.Body["Meshes/Semitruck1_hitch"] then
				UserInputService.InputBegan:Connect(function(key)
					if not key.KeyCode == Enum.KeyCode.Y then
						search(trailer.Constraints:GetChildren())
					end
				end)
			end
		end)
	end
	
	return springs
end

local function getMotorVelocity(motor)
	return motor.Attachment1.WorldAxis:Dot( motor.Attachment1.Parent.RotVelocity )
end

local function adjustSpring( spring, stiffness, damping )
	spring.Stiffness = stiffness
	spring.Damping = damping
end

local function setMotorTorque(torque)
	for _, motor in pairs(Motors) do		
		motor.MotorMaxTorque = torque
	end
end

local function setMotorTorqueDamped(torque, velocityDirection, accelDirection)
	for _, motor in pairs(Motors) do
		if VehicleParameters.MaxSpeed == 0 then 
			motor.MotorMaxTorque = 0
		else
			local maxSpeed = VehicleParameters.MaxSpeed
			if accelDirection < 0 and velocityDirection < 0 then
				maxSpeed = VehicleParameters.ReverseSpeed
			end
			
			local r = math.abs(Chassis.driverSeat.Velocity.Magnitude / maxSpeed)
			motor.MotorMaxTorque = math.exp( -3 * r * r ) * torque
		end
	end
end

local function setMotorMaxAcceleration(acceleration)
	for _, motor in pairs(Motors) do
		motor.MotorMaxAngularAcceleration = acceleration
	end
end

--[[ Module Functions ]]--
Chassis = {}

Chassis.root = PackagedVehicle:FindFirstChild("Chassis") --the root of the Chassis model
Chassis.driverSeat = Chassis.root:FindFirstChildOfClass("VehicleSeat")
Chassis.passengerSeats = {
		Chassis.root:FindFirstChild("SeatFR"),
		Chassis.root:FindFirstChild("SeatRL"),
		Chassis.root:FindFirstChild("SeatRR")
}

local randomSuspension = Chassis.root:FindFirstChild("SuspensionFL")
local wheelRadius = randomSuspension.Wheel.Size.y/2
Chassis.driverSeat.MaxSpeed = VehicleParameters.MaxSpeed * wheelRadius

function Chassis.InitializeDrivingValues()
	-- Constraint tables always ordered FL, FR, RL, RR
	Motors = getVehicleMotors()
	
	local strutSpringsFront = getSprings("StrutFront")
	local strutSpringsRear = getSprings("StrutRear")
	local torsionSprings = getSprings("TorsionBar")

	RedressMount = Chassis.root:WaitForChild("RedressMount")
	
	SteeringPrismatic = constraints:FindFirstChild("SteeringPrismatic")
	SteeringPrismatic.UpperLimit = VehicleParameters.MaxSteer
	SteeringPrismatic.LowerLimit = -VehicleParameters.MaxSteer

	for _,s in pairs(strutSpringsFront) do
		adjustSpring(s, ActualStrutSpringStiffnessFront, ActualStrutSpringDampingFront)
	end
	for _,s in pairs(strutSpringsRear) do
		adjustSpring(s, ActualStrutSpringStiffnessRear, ActualStrutSpringDampingRear)
	end
	for _,s in pairs(torsionSprings) do
		adjustSpring(s, ActualTorsionSpringStiffness, ActualTorsionSpringDamping)
	end
	
	local chassisChildren = Chassis.root:GetChildren()
	for i = 1, #chassisChildren do
		local model = chassisChildren[i]
		if model:IsA("Model") then
			local wheel = model:FindFirstChild("Wheel")
			if wheel then
				local old = wheel.CustomPhysicalProperties
				local new = PhysicalProperties.new(old.Density, VehicleParameters.WheelFriction, old.Elasticity, old.FrictionWeight, old.ElasticityWeight)
				wheel.CustomPhysicalProperties = new
			end
		end
	end

	setMotorTorque(10000)
end

function Chassis.GetDriverSeat()
	return Chassis.driverSeat
end

function Chassis.GetPassengerSeats()
	return Chassis.passengerSeats
end

function Chassis.GetBase()
	return Chassis.root.PrimaryPart or Chassis.root:FindFirstChild("FloorPanel")
end

--Set target angular velocity for all 4 wheels.
function Chassis.SetMotorVelocity(vel)
	for _, motor in pairs(Motors) do
		motor.AngularVelocity = vel
	end
end

--Get average angular velocity from all 4 wheels
function Chassis.GetAverageVelocity()
	local t = 0
	for _, motor in pairs(Motors) do
		t = t + getMotorVelocity(motor)
	end
	return t * (1/#Motors)
end

--Set braking torque and stop back 2 wheels
function Chassis.EnableHandbrake()
	setMotorMaxAcceleration(math.huge)
	Motors[3].MotorMaxTorque = ActualBrakingTorque
	Motors[4].MotorMaxTorque = ActualBrakingTorque
	Motors[3].AngularVelocity = 0
	Motors[4].AngularVelocity = 0
end

--Set target steering position based on current velocity
function Chassis.UpdateSteering(steer, currentVel)
	local baseSteer = steer
	local targetSteer = 0
	
	local vehicleSeat = Chassis.GetDriverSeat()
	local maxSpeed = VehicleParameters.MaxSpeed
	local maxSteer = VehicleParameters.MaxSteer
	
	local currentVelocity = vehicleSeat.Velocity
	
	if LimitSteerAtHighVel then
		local c = SteerLimit * (math.abs(currentVel)/VehicleParameters.MaxSpeed) + 1
		--decrease steer value as speed increases to prevent tipping (handbrake cancels this)
		steer = steer/c
	end
	SteeringPrismatic.TargetPosition = steer * steer * steer * maxSteer
end

function Chassis.UpdateThrottle(currentVel, throttle)
	local targetVel = 0
	if math.abs(throttle) < 0.1 then
		-- Idling
		setMotorMaxAcceleration(math.huge)
		setMotorTorque(2000)
	elseif math.sign(throttle * currentVel) > 0 or math.abs(currentVel) < 0.5 then
		setMotorMaxAcceleration(math.huge)
		
		local velocityVector = Chassis.driverSeat.Velocity.Unit
		local directionalVector = Chassis.driverSeat.CFrame.lookVector
		local dotProd = velocityVector:Dot(directionalVector) -- Dot product is a measure of how similar two vectors are; if they're facing the same direction, it is 1, if they are facing opposite directions, it is -1, if perpendicular, it is 0
		
		setMotorTorqueDamped(ActualDrivingTorque * throttle * throttle, dotProd, math.sign(throttle))
		-- Arbitrary large number
		local movingBackwards = dotProd < 0
		local acceleratingBackwards = throttle < 0
		local useReverse = (movingBackwards and acceleratingBackwards)
		
		targetVel = math.sign(throttle) * (useReverse and VehicleParameters.ReverseSpeed or VehicleParameters.MaxSpeed)
	else
		-- Braking
		setMotorMaxAcceleration(100)
		setMotorTorque(ActualBrakingTorque * throttle * throttle)
		targetVel = math.sign(throttle) * 500
	end
	Chassis.SetMotorVelocity( targetVel )
end

local redressingState = false
local targetAttachment
function Chassis.Redress()
	if redressingState then
		return
	end
	redressingState = true
	local p = Chassis.driverSeat.CFrame.Position + Vector3.new( 0,10,0 )
	local xc = Chassis.driverSeat.CFrame.RightVector
	xc = Vector3.new(xc.x,0,xc.z)
	xc = xc.Unit
	local yc = Vector3.new(0,1,0)

	if not targetAttachment then
		targetAttachment = RedressMount.RedressTarget
	end

	targetAttachment.Parent = Workspace.Terrain
	targetAttachment.Position = p
	targetAttachment.Axis = xc
	targetAttachment.SecondaryAxis = yc
	RedressMount.RedressOrientation.Enabled = true
	RedressMount.RedressPosition.Enabled = true
	wait(1.5)
	RedressMount.RedressOrientation.Enabled = false
	RedressMount.RedressPosition.Enabled = false
	targetAttachment.Parent = RedressMount
	wait(2)
	redressingState = false
end

function Chassis.Reset() --Reset user inputs and redress (For when a player exits the vehicle)
	Chassis.UpdateThrottle(1, 1) --Values must  be changed to replicate to client.
	Chassis.UpdateSteering(1, 0) --i.e. setting vel to 0 when it is 0 wont update to clients
	Chassis.EnableHandbrake()
	setMotorTorque(ActualBrakingTorque)
	Chassis.SetMotorVelocity(0)
	Chassis.UpdateSteering(0, 0)
	RedressMount.RedressOrientation.Enabled = true
	RedressMount.RedressPosition.Enabled = true
	RedressMount.RedressOrientation.Enabled = false
	RedressMount.RedressPosition.Enabled = false
	redressingState = false
end

return Chassis

second Server Script:

local IsDetached = false
local trailer = script.Parent.Parent.Trailer
local Body = script.Parent.Parent.Body
local TrailerHook = Body["Meshes/Semitruck1_hitch"]
local Detector = script.Parent.Parent.Chassis.Detector
local Main = trailer.Chassis.Main
local ComputerEvent = script.Parent.FireSever.DetachAttachTrailerComputer
local XboxOneEvent = script.Parent.FireSever.DetachAttachTrailerXboxOne
trailer.PrimaryPart = Main

ComputerEvent.OnServerEvent:Connect(function()
	if IsDetached == false then
		trailer:SetPrimaryPartCFrame(TrailerHook.Cframe * CFrame.new(0, -0.016, -15))
		print("Should be detached...")
		IsDetached = true
	elseif IsDetached == true then
		Detector.Touched:Connect(function(hit)
			if hit == Main then
				trailer:SetPrimaryPartCFrame(TrailerHook.Cframe * CFrame.new(0, -0.016, 0))
				IsDetached = false
			end
		end)
	end

end)

XboxOneEvent.OnServerEvent:Connect(function()
	if IsDetached == false then
		trailer:SetPrimaryPartCFrame(TrailerHook.Cframe * CFrame.new(0, -0.016, -15))
		IsDetached = true
	elseif IsDetached == true then
		Detector.Touched:Connect(function(hit)
			if hit == Main then
				trailer:SetPrimaryPartCFrame(TrailerHook.Cframe * CFrame.new(0, -0.016, 0))
				IsDetached = false
			end
		end)
	end
end)

Local Script:

script.Parent.Parent.DriverDetecter.Touched:Connect(function(hit)
	if hit.Parent:FindFirstChild("Humanoid") then
		local UserInputService = game:GetService("UserInputService")
		UserInputService.InputBegan:Connect(function(input)
			if input.KeyCode == Enum.KeyCode.Y then
				script.DetachAttachTrailerComputer:FireServer()
				print("Should be working...")
			elseif input.KeyCode == Enum.KeyCode.ButtonY then
				script.DetachAttachTrailerXboxOne:FireServer()
			end
		end)
	end	
end)

Help would be much appreciated.

1 Like

UserInputService only works in LocalScripts. You will need to fire an event when the player presses Y.

1 Like

Oops. Thank you for that I forgot lol. Well back to the point it still doesn’t work. Still no errors either.

You should try using AlignPosition instead of just setting the CFrame.
AlignPosition

I get how I could use that for attaching the trailer but what about detaching? It seems to be aimed towards bringing two parts together.

You can just set the enabled property to false.

This would also not work for another reason; I am not the one who made the truck code I am just programming the attach/detach script and the script for the trailer is too advanced for me to change. And to do this I would have to.

You can’t use UserInputService on the server you’d need to use a remoteevent when the player presses Y

I fixed that I now am using a local script to do that with remote events.

I found out what was happening. The game is not sensing that I am pressing Y. The scripts are in Local scripts. Any help would be very helpful.