I am fairly new at scripting but I made a pickup system where a zone is made around a dropped object and if you enter the zone you have the ability to pick it up. However, when there’s two objects the pickup system picks both of them up. My idea was to check the distance of both objects and whichever was closest is the one that would be picked up. But I kinda don’t know how to do that. I am just having a problem with getting the distances of both objects and comparing them. How would I do that? Also What if there’s 3 objects or more?
Here’s the pickup system I made so far:
Here’s the pickup system if there’s two objects
I just need help with how to do it. Any and all help would be appreciated. : )
--Var
--Objects
local Tool = script.Parent.Parent
local Handle = script.Parent
local gun = Tool:WaitForChild("gun")
local TouchInterest = script.Parent:FindFirstChild("TouchInterest")
local TouchField = Handle.TouchField
--Services
--MemoryVars
local PickUpKey = game.ReplicatedStorage:WaitForChild("PickUp").WeaponPickUpKey.Value
--Important Vars
local MaxPickUpDist = 30
--Events
local PickUpEvent = game.ReplicatedStorage:WaitForChild("PickUp").PickUp
--Destroy TouchInterest
if TouchInterest then
if TouchInterest.Name == "TouchInterest" then
TouchInterest:Destroy()
end
end
--Pickup
local Container = script.Parent:WaitForChild("TouchField")
local Zone = require(game.ReplicatedStorage.Zone)
local Zone1 = Zone.new(Container)
local PickUp = false
local PickUpGUI
local Player
local rayloop = false
local canPickUp = false
Zone1.playerEntered:Connect(function(player)
canPickUp = false
if Tool.Parent.Name ~= player.Name then
Player = player
PickUpGUI = player.PlayerGui.GunPickUp.GunPickUpText
PickUp = false
--Ray
local RayParams1 = RaycastParams.new()
RayParams1.FilterDescendantsInstances = {gun, Handle, TouchField, Zone1}
RayParams1.FilterType = Enum.RaycastFilterType.Blacklist
RayParams1.IgnoreWater = false
rayloop = true
while rayloop == true do
local Ray1 = Ray.new(gun.Position, player.Character.LowerTorso.Position - gun.Position, RaycastParams)
local hit, position = game.Workspace:FindPartOnRayWithIgnoreList(Ray1, {gun, Handle, TouchField})
if hit then
if hit.Parent:FindFirstChild("Humanoid") then
PickUpGUI.Text = "Press " .. tostring(PickUpKey) .. " To Pick Up " .. Tool.Name
PickUpGUI.Visible = true
PickUp = true
canPickUp = true
else
PickUp = false
PickUpGUI.Visible = false
canPickUp = false
end
else
PickUpGUI.Visible = false
canPickUp = false
end
wait(0.5)
end
else
PickUp = false
PickUpGUI.Visible = false
canPickUp = false
end
end)
Zone1.playerExited:Connect(function(player)
local PickUpGUI = player.PlayerGui.GunPickUp.GunPickUpText
PickUpGUI.Visible = false
PickUp = true
rayloop = false
canPickUp = false
end)
PickUpEvent.OnServerEvent:Connect(function(player)
local Dist = player:DistanceFromCharacter(Tool.Handle.Position)
if Dist < MaxPickUpDist then
if canPickUp == true then
if Tool then
canPickUp = false
Tool.Parent = player.Backpack
end
end
end
end)
Instead of showing the pickup gui for each item that is close, iterate through which items can be picked up and then only enable the gui for the closest item.
this is how you can find the closest item when you try to pick them up
local userInputService = game:GetService("UserInputService")
local player = game.Players.LocalPlayer
local pickupDistance = 10
local function Pickup()
-- loop all items and get the closest
local closestItem = nil
local closestDistance = math.huge
for i, child in ipairs(workspace.Items) do
local distance = player:DistanceFromCharacter(child.Position)
if distance == 0 then continue end
if distance > closestDistance then continue end
closestItem = child
closestDistance = distance
end
-- if no item was found exit
if closestItem == nil then return end
-- if the closest items distance is more then pickupdistance then exit
if closestDistance > pickupDistance then return end
print("PICKUP:", closestItem.Name, closestDistance)
end
userInputService.InputBegan:Connect(function(input, processed)
-- if the input was processed then exit the function early and do nothing
if processed == true then return end
-- if the input was not a keyboard then exit the function early and do nothing
if input.UserInputType ~= Enum.UserInputType.Keyboard then return end
-- if the input was not key E then exit the function early and do nothing
if input.KeyCode ~= Enum.KeyCode.E then return end
-- call the pickup function
Pickup()
end)
If this is the script for a single tool, then I’m sorry to say, but there’s a much better way to do it. You can have a local script inside of the player and check for tools in a radius using WorldRoot:GetPartBoundsInRadius. Once you get a list of the tools in a radius, check which one is the closest using:
-- Returns the tool closest to a given position
local function getClosestTool(position: Vector3, radius: number): Tool
local currentDistance: number = radius
local currentTool
for _, part: BasePart in pairs(workspace:GetPartBoundsInRadius(position, radius)) do
local tool: Tool? = part:FindFirstAncestorWhichIsA("Tool")
if (part.Name == "Handle") and tool then
local distance: number = (part.Position - position).Magnitude
if (distance < currentDistance) then
currentDistance = distance
currentTool = tool
end
end
end
return currentTool
end