|
|
| local Players = game:GetService("Players")
|
| local UserInputService = game:GetService("UserInputService")
|
| local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
| local RunService = game:GetService("RunService")
|
| local CollectionService = game:GetService("CollectionService")
|
|
|
| local player = Players.LocalPlayer
|
| local mouse = player:GetMouse()
|
| local camera = workspace.CurrentCamera
|
| local character = player.Character or player.CharacterAdded:Wait()
|
|
|
| local DraggingConfig = require(ReplicatedStorage:WaitForChild("Shared"):WaitForChild("DraggingConfig"))
|
| local DragEvent = ReplicatedStorage:WaitForChild("Events"):WaitForChild("DragEvent")
|
| local DropEvent = ReplicatedStorage:WaitForChild("Events"):WaitForChild("DropEvent")
|
|
|
| local isDragging = false
|
| local draggedPart = nil
|
| local targetAttachment = nil
|
| local currentHoldDistance = DraggingConfig.HoldDistance
|
| local highlightedPart = nil
|
| local highlight = nil
|
|
|
| local renderConnection = nil
|
| local hoverConnection = nil
|
|
|
|
|
| local function createHighlight(part)
|
| removeHighlight()
|
| if not part then return end
|
|
|
| highlight = Instance.new("SelectionBox")
|
| highlight.Adornee = part
|
| highlight.Color3 = Color3.fromRGB(100, 200, 255)
|
| highlight.LineThickness = 0.03
|
| highlight.SurfaceTransparency = 0.8
|
| highlight.SurfaceColor3 = Color3.fromRGB(100, 200, 255)
|
| highlight.Parent = part
|
|
|
| highlightedPart = part
|
| end
|
|
|
| function removeHighlight()
|
| if highlight then
|
| highlight:Destroy()
|
| highlight = nil
|
| end
|
| highlightedPart = nil
|
| end
|
|
|
|
|
| local function updateHover()
|
| if isDragging then return end
|
|
|
| local target = mouse.Target
|
| if target and (CollectionService:HasTag(target, "Draggable") or CollectionService:HasTag(target, "TreeSegment")) then
|
| if target ~= highlightedPart then
|
| createHighlight(target)
|
| end
|
| else
|
| removeHighlight()
|
| end
|
| end
|
|
|
| local function updateDraggingPosition()
|
| if not isDragging or not draggedPart or not targetAttachment then return end
|
|
|
| local char = player.Character
|
| if not char then return end
|
|
|
| local head = char:FindFirstChild("Head")
|
| if not head then return end
|
|
|
| local rayOrigin = head.Position
|
| local rayDirection = camera.CFrame.LookVector * currentHoldDistance
|
|
|
| local raycastParams = RaycastParams.new()
|
| raycastParams.FilterDescendantsInstances = {char, draggedPart}
|
| raycastParams.FilterType = Enum.RaycastFilterType.Exclude
|
|
|
| local raycastResult = workspace:Raycast(rayOrigin, rayDirection, raycastParams)
|
|
|
| local targetPos = rayOrigin + rayDirection
|
| if raycastResult then
|
| targetPos = raycastResult.Position
|
| end
|
|
|
| targetAttachment.WorldCFrame = CFrame.new(targetPos) * CFrame.Angles(0, camera.CFrame.Rotation.Y, 0)
|
| end
|
|
|
| local function stopDragging()
|
| if not isDragging then return end
|
| isDragging = false
|
| draggedPart = nil
|
| targetAttachment = nil
|
| currentHoldDistance = DraggingConfig.HoldDistance
|
|
|
| if renderConnection then
|
| renderConnection:Disconnect()
|
| renderConnection = nil
|
| end
|
|
|
| DropEvent:FireServer()
|
| end
|
|
|
| local function onInputBegan(input, gameProcessed)
|
| if gameProcessed then return end
|
|
|
| if input.UserInputType == Enum.UserInputType.MouseButton1 then
|
| if isDragging then return end
|
|
|
| local targetPart = mouse.Target
|
| if not targetPart then return end
|
|
|
| if not CollectionService:HasTag(targetPart, "Draggable") and not CollectionService:HasTag(targetPart, "TreeSegment") then return end
|
|
|
| local char = player.Character
|
| if not char or not char:FindFirstChild("HumanoidRootPart") then return end
|
|
|
| local distance = (char.HumanoidRootPart.Position - targetPart.Position).Magnitude
|
| if distance > DraggingConfig.MaxGrabDistance then return end
|
|
|
| removeHighlight()
|
|
|
| DragEvent:FireServer(targetPart, mouse.Hit.Position)
|
|
|
| local attachmentName = "TargetAttachment_Player" .. player.UserId
|
|
|
| local t = 0
|
| while not workspace.Terrain:FindFirstChild(attachmentName) and t < 1 do
|
| t = t + task.wait()
|
| end
|
|
|
| targetAttachment = workspace.Terrain:FindFirstChild(attachmentName)
|
|
|
| if targetAttachment then
|
| isDragging = true
|
| draggedPart = targetPart
|
| currentHoldDistance = DraggingConfig.HoldDistance
|
|
|
| renderConnection = RunService.RenderStepped:Connect(updateDraggingPosition)
|
| end
|
| end
|
| end
|
|
|
| local function onInputEnded(input, gameProcessed)
|
| if input.UserInputType == Enum.UserInputType.MouseButton1 then
|
| stopDragging()
|
| end
|
| end
|
|
|
|
|
| local function onInputChanged(input)
|
| if not isDragging then return end
|
|
|
| if input.UserInputType == Enum.UserInputType.MouseWheel then
|
| currentHoldDistance = math.clamp(
|
| currentHoldDistance + input.Position.Z * 2,
|
| 3,
|
| DraggingConfig.MaxGrabDistance
|
| )
|
| end
|
| end
|
|
|
|
|
| player.CharacterAdded:Connect(function(char)
|
| character = char
|
| camera = workspace.CurrentCamera
|
| stopDragging()
|
| end)
|
|
|
|
|
| hoverConnection = RunService.RenderStepped:Connect(updateHover)
|
|
|
| UserInputService.InputBegan:Connect(onInputBegan)
|
| UserInputService.InputEnded:Connect(onInputEnded)
|
| UserInputService.InputChanged:Connect(onInputChanged)
|
|
|