Interactive Script Problem

So I made a script for interacting with items. When the player is closer than 10 studs from it, a BillboardGui is supposed to pop up, and when F is pressed it should print “activated”. This script works, just only for one part at a time.

Video Example:

In this video there are 4 fruits, 2 apples and 2 oranges. The script only works for the second apple I walk up to and no other fruits. Each fruit has a BoolValue named "Pickable in it that allows you to pick it up and a “PrimaryPart” that helps get its Position.

Screenshot:
ApplenOrange

Code:

--Table
for i, part in pairs(workspace.Fruits:GetChildren()) do
	if part:FindFirstChild("Pickable") then
		interactive = part:FindFirstChild("PrimaryPart")
		frame = part.BillboardGui.TextLabel
		item = part
	end
end

--Activator
inputService.InputBegan:Connect (function(input, gameProcessedEvent)
    if gameProcessedEvent then return end
    if input.KeyCode == Enum.KeyCode.F and inRange and debounce then --If F pressed Print "activated"
		debounce = false
        print("activated")
		storage.PickupItem:FireServer(item)
    end
end)

--Interactive Thing
runService.Heartbeat:Connect(function ()
	if debounce then
    inRange = (interactive.Position - plr.Character.HumanoidRootPart.Position).Magnitude <= 10 --Pops up when within 10 studs
    frame.Visible = inRange
else
	frame.Visible = debounce
end
end)

How do I get this code to work for every fruit instead of just one?

That is because you forgot to set the debounce to true again.

I only want each fruit to be picked up once so I purposely didn’t set debounce to true again. I added it anyway to see if this solution would help but it still only works for one fruit.

Here is a useful function I made. One thing I noticed was what if there was more than one interactive that was close? So to solve this, I wrote a function that gets the closest interactive. I also moved some code around and changed some stuff to make it a bit better/neater. To make this work, all TextLabels inside of the BillboardGuis must not be visible. You may also have to define a few things here and there, but it should work.

local Interactive = nil
local RANGE = 10

local function GetClosestInteractive()
	local CloseInteractives = {}
	
	for i, part in pairs(workspace.Fruits:GetChildren()) do
		if part:FindFirstChild("Pickable") then
			local mag = (part.PrimaryPart.Position-HumanoidRootPart.Position).Magnitude
			if mag <= RANGE then
				table.insert(CloseInteractives, {Mag = mag, Part = part})
			end
		end
	end
	
	if #CloseInteractives == 1 then
		return CloseInteractives[1].Part
	elseif #CloseInteractives > 1 then
		table.sort(CloseInteractives, function(a,b) -- We do this to get the closest part. 
			return a.Mag < b.Mag
		end)
		return CloseInteractives[1].Part -- The first index in the will be the closest part.
	else
		return nil
	end
end

--Activator
inputService.InputBegan:Connect(function(input, gameProcessedEvent)
    if gameProcessedEvent then return end
    if input.KeyCode == Enum.KeyCode.F and Interactive ~= nil then -- If there is an interactive. 
        print("activated")
		storage.PickupItem:FireServer(Interactive)
    end
end)

--Interactive Thing
runService.Heartbeat:Connect(function()
	local ClosestInteractive = GetClosestInteractive()
	if ClosestInteractive ~= nil and ClosestInteractive ~= Interactive then -- If there is an interactive close enough and it isnt the current interactive.
		if Interactive == nil then -- If there is not an old interactive
			Interactive = ClosestInteractive
		else -- If there IS an old interactive			Interactive.BillboardGui.TextLabel.Visible = false -- Make the old interactive invisible.
			Interactive = ClosestInteractive
		end
		Interactive.BillboardGui.TextLabel.Visible = true -- Make the new interactive visible.
    elseif ClosestInteractive == nil then
          if Interactive ~= nil then                  Interactive.BillboardGui.TextLabel.Visible = false -- Make the old interactive invisible.
			Interactive = nil
          end
	end
end)
1 Like

This code works almost perfectly except when the player goes beyond the range the BillboardGui doesn’t dissapear and you can still press F to print activate. I turned the TextLabels Visibility off like you said though.

There I updated the code by adding an elseif condition in the RenderStepped event. It should work perfectly now. Sorry for the weird mobile formatting though.

1 Like

Thanks so much! It works just how I want it to.

1 Like