How to have talk UI show up for the closest NPC

Please note, this works some what. My problem is if 2 NPC’s are near each other, it will only show the talk for the first one you came close to. When you go to talk tho, you talk to the correct NPC (the one you are closest too)

It has to do with

local ActionClone = PlayerGui:FindFirstChild('TalkAction')
if ActionClone then return end

And I tried just doing if ActionClone exists then delete it, but that causes the UI to be constantly made and deleted like a million times a second.

local function RenderStepped()
	local LastInput = UserInputService:GetLastInputType()
	NPC = nil
	
	local Character = Player.Character
	if Character then
		local HumanoidRootPart = Character:FindFirstChild('HumanoidRootPart')
		if not HumanoidRootPart then return end
		
		for _, v in pairs(NPCs:GetChildren()) do
			local Distance = (v.PrimaryPart.CFrame.Position - HumanoidRootPart.CFrame.Position).magnitude
			if not NPC or Distance <= NPC.Distance then
				NPC = {
					Current = v, 
					Distance = Distance
				}
			end
		end
		
		if not NPC then return end
		
		Distance = NPC.Distance
		
		if Distance <= ReachableDistance then
			-- Show action
			local DialogueClone = PlayerGui:FindFirstChild('Dialogue')
			if DialogueClone then return end
			
			local ActionClone = PlayerGui:FindFirstChild('TalkAction')
			if ActionClone then return end
			
			local ActionClone = Action:Clone()
			ActionClone.Name = 'TalkAction'
			
			if LastInput == Enum.UserInputType.Touch then
				ActionClone.Control.Tap.Visible = true
				ActionClone.Control.Key:Destroy()
				
				ActionClone.Control.Activated:Connect(function()
					Start()
				end)
			end
			
			ActionClone.Adornee = NPC.Current
			
			ActionClone.Parent = PlayerGui
			
			local ActionTween = TweenService:Create(ActionClone.Control, TweenInfo.new(0.15), {Size = UDim2.new(1, 0, 1, 0)})
			ActionTween:Play()
		else
			-- Too far, delete action
			DeleteAction()
		end
	end
end

RunService.RenderStepped:Connect(RenderStepped)

Example of what I mean

2 Likes

If I’m correct you want the billboard ( E Icon ) to show for both NPCs
You instantiate a new billboard every time or use the same one?

3 Likes

I only want 1 billboard to show, but I want it to show for the closest NPC, not the first one you come across.

2 Likes

That’s probably caused because both npcs are in range, but the script detects the last npc in the for loop, so it basically ignores the first one even if It is closer.

To solve It maybe you could put all the npcs in range, into a table and then check the closest one. You can know which is the closest npc by looping trough the table like this:

local npcs = {
      npc1 = 3, --// This number would be the Distance value
      npc2 = 7
   }

local closest = math.huge --// math.huge will return a value higher o equal to any other value


--[[
 We're basially using math.huge has the initial value to be sure that the first npc
 distance will be lower than the initial value.
--]]

for index = 1, #npcs do
   if npcs[index] < closest then
   --// We're checking if the old value is higher than the current npc distance, if it is, we replace the old value with the new lowest/closest value
      lowest = npcs[index]
   end
end

Have you tried using magnitude instead?

(HumanoidRootPart of the Player - HumanoidRootPart of NPC ).magnitude < How far you want the player to be to be able to see it

He is using .magnitude in his script.

This is weird, he should try using CollectionService and the tagging plugin then make it so each NPC controls on it’s own, instead of the for loop

1 Like