Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- -- Module: TDS_PathfindingModule
- local PathfindingService = game:GetService("PathfindingService")
- local Players = game:GetService("Players")
- local Workspace = game:GetService("Workspace")
- local Debris = game:GetService("Debris")
- local player = Players.LocalPlayer
- local character = player.Character or player.CharacterAdded:Wait()
- local humanoid = character:WaitForChild("Humanoid")
- local rootPart = character:WaitForChild("HumanoidRootPart")
- -- === 模組表 ===
- local TDS = {}
- -- === 參數設定 ===
- local MAX_RETRIES = 3
- local PATHFINDING_TIMEOUT = 5
- local PATH_VISUALIZATION_DURATION = 30
- local MAX_DEVIATION = 10 -- 偏離距離
- -- === 路徑顏色策略 ===
- local PATH_COLORS = {
- [1] = { point = BrickColor.new("Bright red"), connection = BrickColor.new("Really red") },
- [2] = { point = BrickColor.new("Bright green"), connection = BrickColor.new("Earth green") },
- [3] = { point = BrickColor.new("Bright blue"), connection = BrickColor.new("Really blue") }
- }
- local isNavigating = false
- local pathParts = {}
- local attemptColor = 1
- -- === 清除之前路徑顯示 ===
- local function clearPathVisualization()
- for _, part in pairs(pathParts) do
- if part and part.Parent then part:Destroy() end
- end
- pathParts = {}
- end
- -- === 可視化路徑 ===
- local function visualizePath(waypoints, colorSet)
- clearPathVisualization()
- for i, waypoint in ipairs(waypoints) do
- local pathPart = Instance.new("Part")
- pathPart.Name = "PathPoint_" .. i
- pathPart.Anchored = true
- pathPart.CanCollide = false
- pathPart.Material = Enum.Material.Neon
- pathPart.BrickColor = colorSet.point
- pathPart.Size = Vector3.new(1, 0.2, 1)
- pathPart.Position = waypoint.Position
- pathPart.Parent = Workspace
- local light = Instance.new("PointLight")
- light.Brightness = 2
- light.Range = 5
- light.Color = colorSet.point.Color
- light.Parent = pathPart
- if i > 1 then
- local prev = waypoints[i-1]
- local distance = (waypoint.Position - prev.Position).Magnitude
- local connection = Instance.new("Part")
- connection.Name = "PathConnection_" .. (i-1) .. "_to_" .. i
- connection.Anchored = true
- connection.CanCollide = false
- connection.Material = Enum.Material.ForceField
- connection.BrickColor = colorSet.connection
- connection.Size = Vector3.new(0.2, 0.2, distance)
- connection.CFrame = CFrame.lookAt((waypoint.Position + prev.Position) / 2, waypoint.Position)
- connection.Parent = Workspace
- table.insert(pathParts, connection)
- end
- table.insert(pathParts, pathPart)
- end
- for _, part in pairs(pathParts) do
- Debris:AddItem(part, PATH_VISUALIZATION_DURATION)
- end
- end
- -- === 將目標調整到地面 ===
- local function snapToGround(position)
- local params = RaycastParams.new()
- params.FilterType = Enum.RaycastFilterType.Exclude
- params.FilterDescendantsInstances = {character}
- local result = Workspace:Raycast(position + Vector3.new(0, 50, 0), Vector3.new(0, -100, 0), params)
- if result then
- return result.Position + Vector3.new(0, humanoid.HipHeight + 0.5, 0)
- end
- return nil
- end
- -- === 偏移檢測 ===
- local function monitorDeviation(expectedPos)
- local currentPos = rootPart.Position
- return (currentPos - expectedPos).Magnitude <= MAX_DEVIATION
- end
- -- === 三階段策略尋路 ===
- local function tryPathfindingWithStrategies(target)
- for attempt = 1, 3 do
- attemptColor = attempt
- local path = PathfindingService:CreatePath({
- AgentHeight = 5,
- AgentRadius = 2,
- AgentCanJump = true,
- WaypointSpacing = (attempt == 1 and 4) or (attempt == 2 and 2) or 1
- })
- local success, err = pcall(function()
- path:ComputeAsync(rootPart.Position, target)
- end)
- if success and path.Status == Enum.PathStatus.Success then
- print("✅ 成功找到路徑(策略:" .. attempt .. ")")
- return path
- else
- warn("❌ 策略 " .. attempt .. " 失敗:" .. (err or path.Status.Name))
- end
- end
- return nil
- end
- -- === 移動到單一路徑點 ===
- local function moveToWaypoint(waypoint, index, total)
- local start = tick()
- humanoid:MoveTo(waypoint.Position)
- local done = false
- local connection
- connection = humanoid.MoveToFinished:Connect(function()
- done = true
- connection:Disconnect()
- end)
- while not done and tick() - start < PATHFINDING_TIMEOUT do
- wait(0.1)
- end
- if connection then connection:Disconnect() end
- return done
- end
- -- === 核心導航函數 ===
- local function navigateTo(targetPos)
- if isNavigating then return false end
- isNavigating = true
- local adjustedTarget = snapToGround(targetPos)
- if not adjustedTarget then
- warn("❌ 無法找到地面")
- isNavigating = false
- return false
- end
- local path = tryPathfindingWithStrategies(adjustedTarget)
- if not path then
- warn("❌ 所有策略失敗")
- isNavigating = false
- return false
- end
- local waypoints = path:GetWaypoints()
- if #waypoints == 0 then
- warn("❌ 路徑點為空")
- isNavigating = false
- return false
- end
- visualizePath(waypoints, PATH_COLORS[attemptColor])
- for i, wp in ipairs(waypoints) do
- if not isNavigating then return false end
- -- 偏移檢測
- if not monitorDeviation(wp.Position) then
- warn("⚠️ 偵測到偏移,重新尋路...")
- isNavigating = false
- return navigateTo(targetPos)
- end
- -- 移動
- if wp.Action == Enum.PathWaypointAction.Walk then
- if not moveToWaypoint(wp, i, #waypoints) then
- warn("❌ 無法到達節點,重新尋路...")
- isNavigating = false
- return navigateTo(targetPos)
- end
- elseif wp.Action == Enum.PathWaypointAction.Jump then
- humanoid.Jump = true
- wait(0.5)
- end
- -- ✅ 走完該節點 → 刪除對應的方塊 & 連線
- local pointName = "PathPoint_" .. i
- local connectionName = "PathConnection_" .. (i-1) .. "_to_" .. i
- for index, part in ipairs(pathParts) do
- if part.Name == pointName or part.Name == connectionName then
- if part and part.Parent then
- part:Destroy()
- end
- table.remove(pathParts, index)
- end
- end
- end
- print("🎉 成功抵達目標!")
- isNavigating = false
- return true
- end
- -- === 對外 API ===
- function TDS:NavigateToPosition(x, y, z)
- spawn(function()
- navigateTo(Vector3.new(x, y, z))
- end)
- end
- function TDS:NavigateToPlayer(playerName)
- local targetPlayer = Players:FindFirstChild(playerName)
- if targetPlayer and targetPlayer.Character and targetPlayer.Character:FindFirstChild("HumanoidRootPart") then
- local pos = targetPlayer.Character.HumanoidRootPart.Position
- self:NavigateToPosition(pos.X, pos.Y, pos.Z)
- else
- warn("❌ 找不到玩家:" .. playerName)
- end
- end
- function TDS:StopCurrentNavigation()
- if isNavigating then
- isNavigating = false
- humanoid:MoveTo(rootPart.Position)
- clearPathVisualization()
- print("⏹️ 導航已停止")
- else
- print("ℹ️ 無進行中的導航")
- end
- end
- --TDS:NavigateToPosition(7, 129, 151)
- return TDS
Advertisement
Add Comment
Please, Sign In to add comment