I have created a script for moving parts, where the parts follow each other, and the first part follows the route, but the more parts I create, the more the route gets disrupted, which looks very bad.
Please help me fix this issue. I understand that I need to make some kind of offset, but I have not been able to achieve it.
Here is my current script:
local RunService = game:GetService('RunService')
local RailFolder = workspace:WaitForChild('Rail')
local IncludeTable = {}
for i, z in pairs(RailFolder:GetDescendants()) do
if z.Name == 'Ballast' then
table.insert(IncludeTable, z)
end
end
local RayCastParams = RaycastParams.new()
RayCastParams.FilterDescendantsInstances = IncludeTable
RayCastParams.FilterType = Enum.RaycastFilterType.Include
RayCastParams.IgnoreWater = true
local distance = 100
local Spd = 100
local Revers = 'F'
local Height = 7
local CurrentSeat = nil
local LastSeat = nil
local CurrentSeatPer
local ForwardRayPart = nil
local BackwardRayPart = nil
local MovementStarted = false
local RunSeviceConnect
local OptionsDistance = {}
local EndBaseParts = {}
local ForwardRayBaseTable = {}
local BackRayBaseTable = {}
local Seats = {}
local AllBaseparts = {}
local Parent = script.Parent
local function StartMove (Val)
if not MovementStarted then
local LerpTable = {{true}}
MovementStarted = true
local function findrail(Raypart)
local RayOrigin = Raypart.CFrame.Position
local RayDist = Raypart.CFrame.LookVector * distance
local RayRes = workspace:Raycast(RayOrigin, RayDist, RayCastParams)
if RayRes then
distance = RayRes.Distance + RayRes.Distance
return RayRes
end
end
local function OffsetPoint (FirstPart, SecondPart)
end
--local function MinDistantPoint (FirstPart, SecondPart)
-- local FirstCFrameLook = FirstPart.CFrame.LookVector
-- local firstPos = FirstPart.CFrame.Position + (FirstCFrameLook * (FirstPart.Size.Z / 2))
-- local TwoPos = FirstPart.CFrame.Position - (FirstCFrameLook * (FirstPart.Size.Z / 2))
-- local Pos = SecondPart.CFrame.Position
-- local OneMagn = (firstPos - Pos).Magnitude
-- local TwoMagn = (TwoPos- Pos).Magnitude
-- local min = math.min(OneMagn, TwoMagn)
-- local UsePos = FirstPart.CFrame
-- --print(FirstPart)
-- if min == OneMagn then
-- UsePos += (FirstCFrameLook * (FirstPart.Size.Z / 2))
-- elseif min == TwoMagn then
-- UsePos -= (FirstCFrameLook * (FirstPart.Size.Z / 2))
-- end
-- return UsePos
--end
local function MaxDistantPoint (Ballast, CurrentBasePart, RayPart)
local PositionBase = CurrentBasePart.CFrame.Position
local railCframelook = Ballast.CFrame.LookVector
local firstPos = Ballast.CFrame.Position + (railCframelook * (Ballast.Size.Z / 2))
local TwoPos = Ballast.CFrame.Position - (railCframelook * (Ballast.Size.Z / 2))
local RayLookPos = RayPart.CFrame.Position + (RayPart.CFrame.LookVector * 10000)
local OneMagn = math.round((RayLookPos - firstPos).Magnitude)
local TwoMagn = math.round((RayLookPos - TwoPos).Magnitude)
local min = math.min(OneMagn, TwoMagn)
local CurrentUsePos = Ballast.CFrame + (Ballast.CFrame.UpVector * Height)
if min == OneMagn then
local Magnitude = (PositionBase - (CurrentUsePos.Position + (railCframelook * Ballast.Size / 2))).Magnitude
if Magnitude - 1 < Ballast.Size.Z / 2 then
CurrentUsePos += railCframelook * Ballast.Size.Z / 2
end
else
local Magnitude = (PositionBase - (CurrentUsePos.Position - (railCframelook * Ballast.Size / 2))).Magnitude
if Magnitude - 1 < Ballast.Size.Z / 2 then
CurrentUsePos -= railCframelook * Ballast.Size.Z / 2
end
end
return CurrentUsePos
end
local function ChangeRotFunct (Part, SecondPart)
local railCframelook = Part.CFrame.LookVector
local basepartCframelook = SecondPart.CFrame.LookVector
local ChangeRot = false
local OneX = math.round(railCframelook.Unit.X)
local TwoX = math.round(basepartCframelook.Unit.X)
local OneZ = math.round(railCframelook.Unit.Z)
local TwoZ = math.round(basepartCframelook.Unit.Z)
local kof = 1
if OneX ~= 0 and TwoX ~= 0 then
if OneX + TwoX == 0 then
ChangeRot = true
else
ChangeRot = false
end
else
if TwoZ + OneZ == 0 then
ChangeRot = true
else
ChangeRot = false
end
end
return ChangeRot
end
RunSeviceConnect = RunService.Heartbeat:Connect(function(deltatime)
local LocalPerSeat = 1
if Revers == 'F' then
if CurrentSeatPer == -1 then
LocalPerSeat = CurrentSeatPer * -1
else
LocalPerSeat = CurrentSeatPer * 1
end
elseif Revers == 'B' then
if CurrentSeatPer == -1 then
LocalPerSeat = CurrentSeatPer * 1
else
LocalPerSeat = CurrentSeatPer * -1
end
end
local CurrentUseRay = ForwardRayPart
local CurrentUseBaseTable = ForwardRayBaseTable
if LocalPerSeat == -1 then
CurrentUseRay = BackwardRayPart
CurrentUseBaseTable = BackRayBaseTable
end
local LeaderBasePart = CurrentUseBaseTable[1][1]
if LerpTable[1][1] then
local Rail = findrail(CurrentUseRay)
if Rail then
local Ballast = Rail.Instance
local MovePos = MaxDistantPoint(Ballast, LeaderBasePart, CurrentUseRay)
local ChangeRot = ChangeRotFunct(Ballast, LeaderBasePart)
if ChangeRot then
MovePos *= CFrame.Angles(0, math.rad(180), 0)
end
if LerpTable[1][2] ~= nil then
local Tab = LerpTable[1]
Tab[1] = false
Tab[2] = LeaderBasePart
Tab[3] = 0
Tab[4] = LeaderBasePart.CFrame
Tab[5] = MovePos
else
local Tab = LerpTable[1]
Tab[1] = false
table.insert(Tab, LeaderBasePart)
table.insert(Tab, 0)
table.insert(Tab, LeaderBasePart.CFrame)
table.insert(Tab, MovePos)
end
end
end
for i = 2, #CurrentUseBaseTable, 1 do
local Tab = CurrentUseBaseTable[i]
local FollowTab = CurrentUseBaseTable[i - 1]
local BasePart = Tab[1]
local FollowPart = FollowTab[1]
local Distance = Tab[2]
if LerpTable[i] == nil or LerpTable[i][4] then
local LeaderCFrame = FollowPart.CFrame
local ChangeRot = ChangeRotFunct(BasePart, FollowPart)
if ChangeRot then
LeaderCFrame *= CFrame.Angles(0, math.rad(180), 0)
end
--local ChangeOr = BasePart.CFrame.Rotation * LeaderCFrame.Rotation:Inverse()
--local LeaderCFrame = LeaderCFrame * ChangeOr:
if LerpTable[i] == nil then
table.insert(LerpTable, {0, BasePart.CFrame, LeaderCFrame, false})
else
local Tab = LerpTable[i]
Tab[1] = 0
Tab[2] = BasePart.CFrame
Tab[3] = LeaderCFrame
Tab[4] = false
end
end
local Tab = LerpTable[i]
local Alpha = Tab[1]
local StartPose = Tab[2]
local EndPose = Tab[3]
local Lenght = (EndPose.Position - StartPose.Position).Magnitude
local LocalSpd = Spd
local AddLenght = (BasePart.CFrame.Position - FollowPart.CFrame.Position).Magnitude
local Var = Distance - AddLenght
LocalSpd -= Var * #CurrentUseBaseTable
local AddSpd = LocalSpd
AddSpd /= Lenght
AddSpd *= deltatime
Alpha += AddSpd
local MaxAlpha = 1
Alpha = math.clamp(Alpha, 0, MaxAlpha)
if Alpha >= MaxAlpha then
if not Tab[4] then
Tab[4] = true
end
end
Tab[1] = Alpha
local Goal = StartPose:Lerp(EndPose, Alpha)
BasePart.CFrame = Goal
end
if LerpTable[1] ~= nil then
local Tab = LerpTable[1]
local Alpha = LerpTable[1][3]
local BasePartS = LerpTable[1][2]
local StartPose = LerpTable[1][4]
local EndPose = LerpTable[1][5]
local Needed = LerpTable[1][1]
--print(deltatime)
local Lenght = (EndPose.Position - StartPose.Position).Magnitude
local AddSpd = Spd
AddSpd /= Lenght
AddSpd *= deltatime
Alpha += AddSpd
Alpha = math.clamp(Alpha, 0, 1)
--print(Alpha)
Tab[3] = Alpha
if Alpha >= 0.7 then
if not Tab[1] then
Tab[1] = true
end
end
local Goal = StartPose:Lerp(EndPose, Alpha)
BasePartS.CFrame = Goal
end
end)
else
if Val == 'Stop' then
RunSeviceConnect:Disconnect()
MovementStarted = false
end
end
end
for i, a in pairs(Parent:GetDescendants()) do
if a.Name == 'BasePart' then
table.insert(AllBaseparts, a)
elseif a:IsA('Seat') or a:IsA('VehicleSeat') then
table.insert(Seats, a)
end
end
local function OptD (CurrentBase)
local CFrameBase = CFrame.new(CurrentBase.Position)
local Pos = CurrentBase.Position - CFrameBase.LookVector * 10
--local Pos = CurrentBase.Position
local newtab = {}
for i, k in AllBaseparts do
if k ~= CurrentBase then
local magnitude = (k.Position - Pos).Magnitude
table.insert(newtab, magnitude)
end
end
table.sort(newtab)
local first = newtab[1]
local two = newtab[2]
local fpart
local tpart
for i, a in AllBaseparts do
if a ~= CurrentBase then
local magnitude = (a.Position - Pos).Magnitude
if first and magnitude == first and not fpart then
fpart = a
end
if two and two < first * 1.5 and magnitude == two and not tpart then
tpart = a
end
end
end
local Pos2 = CurrentBase.Position
if fpart then
first = (fpart.Position - Pos2).Magnitude
end
if tpart then
two = (tpart.Position - Pos2).Magnitude
end
if fpart and tpart then
table.insert(OptionsDistance, {CurrentBase, fpart, tpart, first, two})
elseif fpart then
table.insert(EndBaseParts, CurrentBase)
table.insert(OptionsDistance, {CurrentBase, fpart, 'none', first, 'none'})
end
end
for i, l in pairs(AllBaseparts) do
OptD(l)
end
local function GetRay ()
local PositionMove = CurrentSeat.Position + CurrentSeat.CFrame.LookVector * 5000
local function CheckDistance (FirstPart, SecondPart)
local Base = FirstPart.Position
local Base2 = SecondPart.Position
local FirstMagnitude = (PositionMove - Base).Magnitude
local SecondMagnitude = (PositionMove - Base2).Magnitude
local Min = math.min(FirstMagnitude, SecondMagnitude)
if Min == FirstMagnitude then
return FirstPart, SecondPart
else
return SecondPart, FirstPart
end
end
local function AddToTable (RecBasePart, AddTab)
local ExcludeFirst = RecBasePart
local ExcludeSecond = nil
local noneNum = 0
repeat
for i, a in pairs(OptionsDistance) do
--print(a)
local First = a[1]
local Second = a[2]
local Third = a[3]
local SecondDist = a[4]
local ThirdDist = a[5]
if First == ExcludeFirst then
local Tab = {}
table.insert(Tab, First)
if Third == 'none' then
noneNum += 1
ExcludeFirst = Second
table.insert(Tab, SecondDist)
elseif ExcludeSecond == Second then
ExcludeFirst = Third
table.insert(Tab, ThirdDist)
elseif ExcludeSecond == Third then
ExcludeFirst = Second
table.insert(Tab, SecondDist)
end
table.insert(AddTab, Tab)
ExcludeSecond = First
break
end
end
task.wait()
until noneNum > 1
end
table.clear(ForwardRayBaseTable)
table.clear(BackRayBaseTable)
if #EndBaseParts == 2 then
local ForwardBase, Backward = CheckDistance(EndBaseParts[1], EndBaseParts[2])
local ForwardBaseRays = {}
for i, m in ForwardBase.Parent:GetChildren() do
local name = string.lower(m.Name)
if string.find(name, 'ray') then
table.insert(ForwardBaseRays, m)
end
end
AddToTable(ForwardBase, ForwardRayBaseTable)
AddToTable(Backward, BackRayBaseTable)
local ForwardRay, BackRay = CheckDistance(ForwardBaseRays[1], ForwardBaseRays[2])
ForwardRayPart = ForwardRay
local BackwardBaseRays = {}
for i, z in pairs(Backward.Parent:GetChildren()) do
local name = string.lower(z.Name)
if string.find(name, 'ray') then
table.insert(BackwardBaseRays, z)
end
end
local ForwardBRay, BackBRay = CheckDistance(BackwardBaseRays[1], BackwardBaseRays[2])
BackwardRayPart = BackBRay
else
local RaysTab = {}
for i, a in pairs((EndBaseParts[1].Parent:GetChildren())) do
local name = string.lower(a.Name)
if string.find(name, 'ray') then
table.insert(RaysTab, a)
end
end
table.insert(ForwardRayBaseTable, EndBaseParts[1])
table.insert(BackRayBaseTable, EndBaseParts[2])
local ForwardRay, BackRay = CheckDistance(RaysTab[1], RaysTab[2])
ForwardRayPart = ForwardRay
BackwardRayPart = BackRay
end
StartMove()
end
for i, m in pairs(Seats) do
m:GetPropertyChangedSignal('Occupant'):Connect(function()
if m.Occupant then
CurrentSeat = m
if m:GetAttribute('Front') then
CurrentSeatPer = 1
else
CurrentSeatPer = -1
end
GetRay()
else
--StartMove('Stop')
end
end)
end
--print(OptionsDistance)
--print(EndBaseParts)

