--!strict
local Players = game:GetService("Players")
local RunService = game:GetService("RunService")
local player = Players.LocalPlayer
-- =========================
-- CONFIG
-- =========================
local CONFIG = {
TargetSpeed = 250, -- ความเร็วหลักแกน Z
RoadName = "AutoFarmRoad",
RoadSize = Vector3.new(200, 10, 900000),
RoadPosition = Vector3.new(0, 10000, 0),
SpawnPosition = Vector3.new(0, 10015, 0),
SpawnYaw = 0, -- องศาที่หันตอนวางรถกลับ
MinYBeforeReset = 9500,
MaxZBeforeReset = 400000,
CenterX = 0, -- กลางถนน
CenteringGain = 4.5, -- แรงดึงกลับแกน X
MaxSideVelocity = 120, -- จำกัดความเร็วด้านข้าง ไม่ให้ดีดแรงเกิน
TeleportCooldown = 0.25,
OrientationResponsiveness = 50, -- ค่ายิ่งมากยิ่งหันไว
OrientationMaxTorque = 1e9,
}
-- =========================
-- STATE
-- =========================
local currentVehicle: Model? = nil
local currentMainPart: BasePart? = nil
local isResetting = false
local heartbeatConnection: RBXScriptConnection? = nil
-- =========================
-- ROAD SETUP
-- =========================
local function ensureRoad(): Part
local road = workspace:FindFirstChild(CONFIG.RoadName)
if road and road:IsA("Part") then
road.Size = CONFIG.RoadSize
road.Position = CONFIG.RoadPosition
return road
end
if road and not road:IsA("Part") then
road:Destroy()
end
local newRoad = Instance.new("Part")
newRoad.Name = CONFIG.RoadName
newRoad.Size = CONFIG.RoadSize
newRoad.Position = CONFIG.RoadPosition
newRoad.Anchored = true
newRoad.CanCollide = true
newRoad.CanTouch = false
newRoad.CanQuery = false
newRoad.Transparency = 0.5
newRoad.Material = Enum.Material.SmoothPlastic
newRoad.CastShadow = false
newRoad.Locked = true
newRoad.Parent = workspace
return newRoad
end
ensureRoad()
-- =========================
-- UTILS
-- =========================
local function getCharacter(): Model?
return player.Character
end
local function getHumanoid(character: Model?): Humanoid?
if not character then
return nil
end
return character:FindFirstChildOfClass("Humanoid")
end
local function getSeatedVehicle(): (Model?, BasePart?)
local character = getCharacter()
local humanoid = getHumanoid(character)
if not character or not humanoid then
return nil, nil
end
local seat = humanoid.SeatPart
if not seat or not seat:IsA("BasePart") then
return nil, nil
end
local vehicle = seat:FindFirstAncestorOfClass("Model")
if not vehicle then
return nil, nil
end
local mainPart = vehicle.PrimaryPart or seat
if not mainPart or not mainPart:IsA("BasePart") then
return nil, nil
end
return vehicle, mainPart
end
local function clearControllerObjects(part: BasePart?)
if not part then
return
end
local oldAttachment = part:FindFirstChild("AF_Attachment")
if oldAttachment then
oldAttachment:Destroy()
end
local oldAlign = part:FindFirstChild("AF_AlignOrientation")
if oldAlign then
oldAlign:Destroy()
end
end
local function setupOrientationController(part: BasePart)
clearControllerObjects(part)
local attachment = Instance.new("Attachment")
attachment.Name = "AF_Attachment"
attachment.Parent = part
local align = Instance.new("AlignOrientation")
align.Name = "AF_AlignOrientation"
align.Mode = Enum.OrientationAlignmentMode.OneAttachment
align.Attachment0 = attachment
align.RigidityEnabled = false
align.ReactionTorqueEnabled = false
align.Responsiveness = CONFIG.OrientationResponsiveness
align.MaxTorque = CONFIG.OrientationMaxTorque
align.CFrame = CFrame.lookAt(Vector3.zero, Vector3.new(0, 0, 1), Vector3.new(0, 1, 0))
align.Parent = part
end
local function bindVehicle(vehicle: Model, mainPart: BasePart)
if currentMainPart == mainPart and currentVehicle == vehicle then
return
end
if currentMainPart then
clearControllerObjects(currentMainPart)
end
currentVehicle = vehicle
currentMainPart = mainPart
setupOrientationController(mainPart)
end
local function unbindVehicle()
if currentMainPart then
clearControllerObjects(currentMainPart)
end
currentVehicle = nil
currentMainPart = nil
end
local function resetVehicle(vehicle: Model?, mainPart: BasePart?)
if isResetting or not mainPart then
return
end
isResetting = true
mainPart.AssemblyLinearVelocity = Vector3.zero
mainPart.AssemblyAngularVelocity = Vector3.zero
local spawnCF = CFrame.new(CONFIG.SpawnPosition) * CFrame.Angles(0, math.rad(CONFIG.SpawnYaw), 0)
if vehicle then
vehicle:PivotTo(spawnCF)
else
mainPart.CFrame = spawnCF
end
task.delay(CONFIG.TeleportCooldown, function()
isResetting = false
end)
end
-- =========================
-- MAIN LOOP
-- =========================
local function stepVehicle()
if isResetting then
return
end
local vehicle, mainPart = getSeatedVehicle()
if not vehicle or not mainPart then
unbindVehicle()
return
end
bindVehicle(vehicle, mainPart)
local pos = mainPart.Position
-- รีเซ็ตกลับต้นทางถ้าหลุดจากพื้นที่ที่กำหนด
if pos.Y < CONFIG.MinYBeforeReset or pos.Z > CONFIG.MaxZBeforeReset then
resetVehicle(vehicle, mainPart)
return
end
-- ล็อกอัตราหมุนไม่ให้รถเหวี่ยง/ล้มง่าย
mainPart.AssemblyAngularVelocity = Vector3.zero
-- ดึงกลับสู่แกนกลางถนน
local lateralError = CONFIG.CenterX - pos.X
local sideVelocity = math.clamp(
lateralError * CONFIG.CenteringGain,
-CONFIG.MaxSideVelocity,
CONFIG.MaxSideVelocity
)
-- คง Y velocity เดิมไว้ เพื่อไม่ฝืนแรงโน้มถ่วงจนผิดธรรมชาติ
local currentYVelocity = mainPart.AssemblyLinearVelocity.Y
mainPart.AssemblyLinearVelocity = Vector3.new(
sideVelocity,
currentYVelocity,
CONFIG.TargetSpeed
)
end
-- กันรันซ้ำแล้วมีหลาย connection
if _G.AutoDriveConnection then
_G.AutoDriveConnection:Disconnect()
_G.AutoDriveConnection = nil
end
heartbeatConnection = RunService.Heartbeat:Connect(stepVehicle)
_G.AutoDriveConnection = heartbeatConnection
-- cleanup ตอนตัวละครเปลี่ยน
player.CharacterRemoving:Connect(function()
unbindVehicle()
end)You must board the vehicle before using it.
No comments yet. Be the first to comment!
1--!strict
2
3local Players = game:GetService("Players")
4local RunService = game:GetService("RunService")
5
6local player = Players.LocalPlayer
7
8-- =========================
9-- CONFIG
10-- =========================
11local CONFIG = {
12 TargetSpeed = 250, -- ความเร็วหลักแกน Z
13 RoadName = "AutoFarmRoad",
14 RoadSize = Vector3.new(200, 10, 900000),
15 RoadPosition = Vector3.new(0, 10000, 0),
16
17 SpawnPosition = Vector3.new(0, 10015, 0),
18 SpawnYaw = 0, -- องศาที่หันตอนวางรถกลับ
19
20 MinYBeforeReset = 9500,
21 MaxZBeforeReset = 400000,
22
23 CenterX = 0, -- กลางถนน
24 CenteringGain = 4.5, -- แรงดึงกลับแกน X
25 MaxSideVelocity = 120, -- จำกัดความเร็วด้านข้าง ไม่ให้ดีดแรงเกิน
26
27 TeleportCooldown = 0.25,
28
29 OrientationResponsiveness = 50, -- ค่ายิ่งมากยิ่งหันไว
30 OrientationMaxTorque = 1e9,
31}
32
33-- =========================
34-- STATE
35-- =========================
36local currentVehicle: Model? = nil
37local currentMainPart: BasePart? = nil
38local isResetting = false
39local heartbeatConnection: RBXScriptConnection? = nil
40
41-- =========================
42-- ROAD SETUP
43-- =========================
44local function ensureRoad(): Part
45 local road = workspace:FindFirstChild(CONFIG.RoadName)
46
47 if road and road:IsA("Part") then
48 road.Size = CONFIG.RoadSize
49 road.Position = CONFIG.RoadPosition
50 return road
51 end
52
53 if road and not road:IsA("Part") then
54 road:Destroy()
55 end
56
57 local newRoad = Instance.new("Part")
58 newRoad.Name = CONFIG.RoadName
59 newRoad.Size = CONFIG.RoadSize
60 newRoad.Position = CONFIG.RoadPosition
61 newRoad.Anchored = true
62 newRoad.CanCollide = true
63 newRoad.CanTouch = false
64 newRoad.CanQuery = false
65 newRoad.Transparency = 0.5
66 newRoad.Material = Enum.Material.SmoothPlastic
67 newRoad.CastShadow = false
68 newRoad.Locked = true
69 newRoad.Parent = workspace
70
71 return newRoad
72end
73
74ensureRoad()
75
76-- =========================
77-- UTILS
78-- =========================
79local function getCharacter(): Model?
80 return player.Character
81end
82
83local function getHumanoid(character: Model?): Humanoid?
84 if not character then
85 return nil
86 end
87 return character:FindFirstChildOfClass("Humanoid")
88end
89
90local function getSeatedVehicle(): (Model?, BasePart?)
91 local character = getCharacter()
92 local humanoid = getHumanoid(character)
93
94 if not character or not humanoid then
95 return nil, nil
96 end
97
98 local seat = humanoid.SeatPart
99 if not seat or not seat:IsA("BasePart") then
100 return nil, nil
101 end
102
103 local vehicle = seat:FindFirstAncestorOfClass("Model")
104 if not vehicle then
105 return nil, nil
106 end
107
108 local mainPart = vehicle.PrimaryPart or seat
109 if not mainPart or not mainPart:IsA("BasePart") then
110 return nil, nil
111 end
112
113 return vehicle, mainPart
114end
115
116local function clearControllerObjects(part: BasePart?)
117 if not part then
118 return
119 end
120
121 local oldAttachment = part:FindFirstChild("AF_Attachment")
122 if oldAttachment then
123 oldAttachment:Destroy()
124 end
125
126 local oldAlign = part:FindFirstChild("AF_AlignOrientation")
127 if oldAlign then
128 oldAlign:Destroy()
129 end
130end
131
132local function setupOrientationController(part: BasePart)
133 clearControllerObjects(part)
134
135 local attachment = Instance.new("Attachment")
136 attachment.Name = "AF_Attachment"
137 attachment.Parent = part
138
139 local align = Instance.new("AlignOrientation")
140 align.Name = "AF_AlignOrientation"
141 align.Mode = Enum.OrientationAlignmentMode.OneAttachment
142 align.Attachment0 = attachment
143 align.RigidityEnabled = false
144 align.ReactionTorqueEnabled = false
145 align.Responsiveness = CONFIG.OrientationResponsiveness
146 align.MaxTorque = CONFIG.OrientationMaxTorque
147 align.CFrame = CFrame.lookAt(Vector3.zero, Vector3.new(0, 0, 1), Vector3.new(0, 1, 0))
148 align.Parent = part
149end
150
151local function bindVehicle(vehicle: Model, mainPart: BasePart)
152 if currentMainPart == mainPart and currentVehicle == vehicle then
153 return
154 end
155
156 if currentMainPart then
157 clearControllerObjects(currentMainPart)
158 end
159
160 currentVehicle = vehicle
161 currentMainPart = mainPart
162 setupOrientationController(mainPart)
163end
164
165local function unbindVehicle()
166 if currentMainPart then
167 clearControllerObjects(currentMainPart)
168 end
169
170 currentVehicle = nil
171 currentMainPart = nil
172end
173
174local function resetVehicle(vehicle: Model?, mainPart: BasePart?)
175 if isResetting or not mainPart then
176 return
177 end
178
179 isResetting = true
180
181 mainPart.AssemblyLinearVelocity = Vector3.zero
182 mainPart.AssemblyAngularVelocity = Vector3.zero
183
184 local spawnCF = CFrame.new(CONFIG.SpawnPosition) * CFrame.Angles(0, math.rad(CONFIG.SpawnYaw), 0)
185
186 if vehicle then
187 vehicle:PivotTo(spawnCF)
188 else
189 mainPart.CFrame = spawnCF
190 end
191
192 task.delay(CONFIG.TeleportCooldown, function()
193 isResetting = false
194 end)
195end
196
197-- =========================
198-- MAIN LOOP
199-- =========================
200local function stepVehicle()
201 if isResetting then
202 return
203 end
204
205 local vehicle, mainPart = getSeatedVehicle()
206 if not vehicle or not mainPart then
207 unbindVehicle()
208 return
209 end
210
211 bindVehicle(vehicle, mainPart)
212
213 local pos = mainPart.Position
214
215 -- รีเซ็ตกลับต้นทางถ้าหลุดจากพื้นที่ที่กำหนด
216 if pos.Y < CONFIG.MinYBeforeReset or pos.Z > CONFIG.MaxZBeforeReset then
217 resetVehicle(vehicle, mainPart)
218 return
219 end
220
221 -- ล็อกอัตราหมุนไม่ให้รถเหวี่ยง/ล้มง่าย
222 mainPart.AssemblyAngularVelocity = Vector3.zero
223
224 -- ดึงกลับสู่แกนกลางถนน
225 local lateralError = CONFIG.CenterX - pos.X
226 local sideVelocity = math.clamp(
227 lateralError * CONFIG.CenteringGain,
228 -CONFIG.MaxSideVelocity,
229 CONFIG.MaxSideVelocity
230 )
231
232 -- คง Y velocity เดิมไว้ เพื่อไม่ฝืนแรงโน้มถ่วงจนผิดธรรมชาติ
233 local currentYVelocity = mainPart.AssemblyLinearVelocity.Y
234
235 mainPart.AssemblyLinearVelocity = Vector3.new(
236 sideVelocity,
237 currentYVelocity,
238 CONFIG.TargetSpeed
239 )
240end
241
242-- กันรันซ้ำแล้วมีหลาย connection
243if _G.AutoDriveConnection then
244 _G.AutoDriveConnection:Disconnect()
245 _G.AutoDriveConnection = nil
246end
247
248heartbeatConnection = RunService.Heartbeat:Connect(stepVehicle)
249_G.AutoDriveConnection = heartbeatConnection
250
251-- cleanup ตอนตัวละครเปลี่ยน
252player.CharacterRemoving:Connect(function()
253 unbindVehicle()
254end)