You can write your topic however you want, but you need to answer these questions:
-
What do you want to achieve? Keep it simple and clear!
I have a car, specifically a local one, which self-assembles using suspension parts.
I recently converted my server version to a local version, which was fine, but I need to workaround some models parenting tonil
. -
What is the issue? Include screenshots / videos if possible!
The title says it all, the “sus” model is parenting to nil (the model that contains wheels and axels), which makes all the other scripts reset, if they’re inside the suspension (which I have a few of).
To debug the script, I added a print statement that prints out “LOCAL NIL” whenever the script needs to reparent the model. The problem also occurs when the player goes a certain amount of studs away from the car, but not all the time.
Video:
-
What solutions have you tried so far? Did you look for solutions on the Developer Hub? I don’t see any relevant solutions on the Developer Hub. I tried several other solutions, such as reparenting the model, but the scripts inside still tend to reset.
After that, you should include more details if you have any. Try to make your topic as descriptive as possible, so that it’s easier for people to help you!
If this helps, here’s the “main” script. Parts of it were coded years ago, and since this is not designed to be replicated, it is a LocalScript
. RaycastModule
is a module I made that will convert the arguments from the old workspace:FindPartOnRay
to workspace:Raycast
. I’m also working on removing the 2nd argument from Instance.new
, but that’s for another day.
wait(0.2)
local set = script.Config
local SuspensionEnabled = set.SuspensionEnabled.Value
local susLength = set.Max
local susTargetLength = set.Length
local minSusLength = set.Min
local stiffness = set.Stiffness
local pow = set.Pow
local veldamp = set.Damp
local wheelsBreakable = set.WheelBreakable
local wheelHealth = set.WheelHealth
local raycast = require(script.RaycastModule)
local mass = 0
local axelReflectance = 0.2
local axelColor = BrickColor.new("Dark stone grey")
local axelMaterial = Enum.Material.Plastic
--script.Parent.sus:MakeJoints()
local base = script.Parent.Base
local w = Instance.new("Model", script.Parent:WaitForChild("sus"))
w.Name = "Wheels"
local w2 = Instance.new("Model",w)
w2.Name = 'pWheels'
local ax = Instance.new("Model", script.Parent:WaitForChild("sus"))
ax.Name = "axels"
function findNearestThruster(obj)
local range = 50
local closest
for _, other in pairs(script.Parent.sus:GetDescendants())do
if other:IsA("BasePart")and string.match(string.lower(other.Name), "thrust")and other.Parent==script.Parent.sus and other~=obj then
local dist = (other.Position-obj.Position).Magnitude
local dot = (other.Position-obj.Position).Unit:Dot(obj.CFrame.LookVector)
if dist<range and math.abs(dot)<0.1 then
range = dist
closest = other
end
end
end
return closest
end
function clearSrufaces(part)
part.CanCollide = false
for _, normalId in pairs(Enum.NormalId:GetEnumItems())do
part[normalId.Name.."Surface"]=Enum.SurfaceType.Smooth
end
end
function setPrefrences(axel)
axel.Reflectance = axelReflectance
axel.Material = axelMaterial
axel.BrickColor = axelColor
end
function makeAxel(obj, wheel)
local other = findNearestThruster(obj)
if other then
local axel = Instance.new("Part", ax)
axel.Name = "Axel"
axel.Size = Vector3.new(1,1,1)
axel.CFrame = obj.CFrame
setPrefrences(axel)
axel.Massless = true
clearSrufaces(axel)
local axelBase = Instance.new("Part", ax)
axelBase.Name = "AxelBase"
local mesh = Instance.new("SpecialMesh",axelBase)
mesh.MeshType = Enum.MeshType.Sphere
mesh.Scale = Vector3.new(2,1,1)
axelBase.Size = Vector3.new(1,1,1)
axelBase.CFrame = obj.CFrame:Lerp(other.CFrame, 0.5)
setPrefrences(axelBase)
axelBase.Massless = true
clearSrufaces(axelBase)
weldToBase(axelBase)
local axelScript = script.axelScript:Clone()
axelScript.Parent = axel
axelScript.base.Value = axelBase
axelScript.target.Value = wheel
axelScript.Disabled = false
return axel
end
end
function isThrust(t)
local name = string.lower(t.Name)
local isNamed = string.match(name,'thrust',0)
local steerThrust = string.match(name,'steer',0)
local powerThrust = string.match(name,'power',0)
local casterThrust = string.match(name,'caster',0)
return {isNamed,steerThrust,powerThrust,casterThrust}
end
local hover = set.HoverEnabled
function weldToBase(part)
local anchored = part.Anchored
part.Anchored = true
local weld = Instance.new("Weld",base)
local c0 = base.CFrame:ToObjectSpace(base.CFrame)
local c1 = part.CFrame:ToObjectSpace(base.CFrame)
weld.C0 = c0
weld.C1 = c1
weld.Part0 = base
weld.Part1 = part
weld.Name = "Weld from: "..weld.Part0.Name.." to: "..weld.Part1.Name
part.Anchored = anchored
end
function resizeWheel(wheel, sizeMultiplier)
local function resize(obj)
obj.Size*=sizeMultiplier
end
for _, obj in pairs(wheel:GetDescendants())do
if obj:IsA("BasePart")or (obj:IsA("SpecialMesh")and obj.MeshType==Enum.MeshType.FileMesh)or obj:IsA("FileMesh") then
if obj:IsA("BasePart")then
resize(obj)
else
obj.Scale*=sizeMultiplier
end
end
end
resize(wheel)
end
local count = 0
for _, obj in pairs(script.Parent.sus:GetChildren())do
if isThrust(obj)[1] and obj:IsA("BasePart") then
count+=1
local customWheelSize = obj:FindFirstChild("CustomWheelSize")
obj.Transparency = 1
weldToBase(obj)
local thrust = Instance.new("BodyThrust")
local spring = script:WaitForChild("spring"):Clone()
spring.Parent=obj
thrust.Parent = obj
local customWheel = obj:FindFirstChild("CustomWheel")
if customWheel then
customWheel = customWheel.Value
end
local wheel
pcall(function()
wheel = (customWheel or script.Parent.sus:WaitForChild("WheelClone", 1)):Clone()
end)
if not wheel then
wheel = Instance.new("Part")
wheel.Transparency = 1
wheel.Size = Vector3.new(2, 2, 2)
end
wheel.CanCollide = not SuspensionEnabled
wheel.Parent = w
if isThrust(obj)[3]then
wheel.Parent = w2
end
if customWheelSize then
resizeWheel(wheel, customWheelSize.Value)
end
local wx = Instance.new("Weld")
wx.Name = "wheelWeld"
wx.Part0=obj
wx.Part1=wheel
wx.Parent = wheel
local wh = wheelHealth.Value
local axel = makeAxel(obj, wheel)
local scr = script.wheelScript:Clone()
scr.Parent = wheel
if not scr:IsA("ModuleScript")then
scr.Disabled = false
else
scr.Runner.Disabled = false
end
scr.caster.Value = isThrust(obj)[4]
scr.steering.Value = isThrust(obj)[2] and not scr.caster.Value
scr.thruster.Value = obj
local sus = script.Parent.sus
spawn(function()
local lastMode
local lastlastMode
while obj do
if not sus.Parent then print('LOCAL NIL!') end
obj.Parent = sus
sus.Parent = script.Parent
scr.numWheels.Value = count
local startPos = obj.Position-(obj.CFrame.UpVector*minSusLength.Value)
local targetPos = -obj.CFrame.UpVector*(susLength.Value-minSusLength.Value)
local r = Ray.new(startPos, targetPos)
local part, pos, mat, normal = raycast(r, script.Parent)
local dist3 = susLength.Value
if part and part.CanCollide or hover.Value then
lastlastMode=true
local mag = (obj.AssemblyLinearVelocity*obj.CFrame.UpVector).Magnitude
if lastlastMode and not lastMode and mag>50 and not hover.Value then
lastlastMode=false
spring:Play()
spring.PlaybackSpeed = (mag/512)+0.5
spring.Volume = mag/64
if wheelsBreakable.Value and wh>0 then
local damage = mag/24
wh-=damage
if wh<=0 then
obj:Destroy()
obj = nil
wheel.CanCollide = true
wx:Destroy()
scr:Destroy()
axel:Destroy()
break
end
end
end
local dist = (obj.Position-(pos or startPos)).Magnitude
if dist<minSusLength.Value then
dist = minSusLength.Value
end
dist3 = dist
local st = susTargetLength.Value
local dx = obj.CFrame:VectorToObjectSpace(obj:GetVelocityAtPosition(obj.Position)):Dot(Vector3.new(0, 1, 0))*(veldamp.Value/(count/4))
if hover.Value and not part then
dist = ((obj.Position.Y-base.Position.Y)+susLength.Value)-(base.AssemblyLinearVelocity*Vector3.new(1, 0, 1)/100).Magnitude
dist3 = susTargetLength.Value
else
st+=1
end
local stiffForce = math.max(((st - dist)^pow.Value) * ((stiffness.Value*mass*196.2) / st^pow.Value), -math.abs(dx*mass*stiffness.Value*196.2*(base.CFrame.UpVector:Dot(Vector3.new(0, 1, 0)))))
stiffForce/=count/4
local n = obj.CFrame:VectorToObjectSpace(normal or obj.CFrame.UpVector)
local force = n*stiffForce-dx*n*mass
thrust.Force = force
else
thrust.Force = Vector3.new()
end
scr.currentDistance.Value = dist3-(wheel.Size.Y/2)
if not SuspensionEnabled then
scr.currentDistance.Value = susTargetLength.Value
thrust.Force = Vector3.new()
end
scr.onGround.Value = dist3~=susLength.Value
if mat and part then
scr.normal.Value = normal
scr.groundMaterial.Value = mat.Name
scr.hitPart.Value = part
scr.MaxDistance.Value = susLength.Value
scr.MinDistance.Value = minSusLength.Value
scr.targetDistance.Value = susTargetLength.Value
else
scr.groundMaterial.Value = "Air"
end
scr.mass.Value = mass
lastMode=part~=nil
game:GetService("RunService").RenderStepped:Wait()
end
count-=1
end)
end
end
local Pos,sz = script.Parent:GetBoundingBox()
local Pos0 = Vector3.new()
for _, part in pairs(script.Parent.sus:GetChildren())do
if part:IsA("BasePart")then
if not isThrust(part)[1] then
part:Destroy()
else
Pos0+=part.Position
end
end
end
Pos0/=count
local tb = {}
for _, obj in pairs(base:GetJoints())do
if obj:IsA("JointInstance")then
obj.Parent = nil
table.insert(tb,1,obj)
end
end
base.CFrame = Pos
base.Position = Pos0
for _, obj in pairs(tb)do
if obj.Part1 and obj.Part0 then
if obj.Part1~=base then
weldToBase(obj.Part1)
else
weldToBase(obj.Part0)
end
end
end
local mainRod = Instance.new("Part", ax)
mainRod.Massless = true
mainRod.Name = "Main"
local rodWeld = Instance.new("Weld", mainRod)
rodWeld.Part0 = base
rodWeld.Part1 = mainRod
rodWeld.C0 = base.CFrame:ToObjectSpace(Pos)-Vector3.new(0,base.CFrame:ToObjectSpace(Pos).Y,0)
rodWeld.C1 = CFrame.Angles(0,math.pi/2,0)
mainRod.Size = Vector3.new(sz.Z-1.5, 0.75, 1)
setPrefrences(mainRod)
clearSrufaces(mainRod)
mainRod.Shape = Enum.PartType.Cylinder
for _, obj in pairs(script.Parent:GetDescendants())do
if obj:IsA("BasePart")then
obj.Anchored = false
end
end
wait()
mass = require(script.MassGetter)()
Also, the vehicle is cloned and parented to the character using a script in StarterCharacterScripts
.
Please do not ask people to write entire scripts or design entire systems for you. If you can’t answer the three questions above, you should probably pick a different category.
I know what I’m asking is beyond the scope of what most of you can answer, but if you need more details and resources, for example the WheelScript, I can provide them. If you want, I can also send the model of the car.