Hello, I have this script that highlights an object that the player is near and sets a TextGui using invisible proximity prompts. I was wondering if there is a more optimal way to do this? I feel like I’m not doing it as optimal as I could be.
Code
local ProximityPromptService = game:GetService("ProximityPromptService")
local table = {
["Buy"] = 1,
["Door"] = 2,
["Interact"] = 3,
["Debris"] = 4,
["Use"] = 5,
}
ProximityPromptService.PromptShown:Connect(function(ProximityPrompt)
local Highlight = Instance.new("Highlight"); Highlight.FillColor = Color3.fromRGB(255, 255, 255); Highlight.FillTransparency = 1 -- Highlight around the object so player knows what they are interacting with (default proximity prompt is invisible)
Highlight.Parent = ProximityPrompt.Parent
Highlight.Adornee = ProximityPrompt.MessageType.ObjName.Price.HighlightAdornee.Value
local gui = game.Players.LocalPlayer.PlayerGui
local msgtype = ProximityPrompt.MessageType -- Every proximity prompt has different values for the type of interaction, object name, and cost
local objtype = msgtype.ObjName
local cost = objtype.Price.Value
gui.GameHUD.InteractFrame.Visible = true -- This is the frame that contains the text to display
if msgtype.Value == 1 then
gui.GameHUD.InteractFrame.InteractText.Text = "Press and hold F to buy "..objtype.Value.." for "..cost
elseif msgtype.Value == 2 then
gui.GameHUD.InteractFrame.InteractText.Text = "Press and hold F to spend "..cost.." to open the door"
elseif msgtype.Value == 3 then
if cost ~= 0 then
gui.GameHUD.InteractFrame.InteractText.Text = "Press and hold F to interact with "..objtype.." for "..cost
else
gui.GameHUD.InteractFrame.InteractText.Text = "Press and hold F to interact with "..objtype
end
elseif msgtype.Value == 4 then
gui.GameHUD.InteractFrame.InteractText.Text = "Press and hold F to spend "..cost.." to remove the debris"
elseif msgtype.Value == 5 then
if cost ~= 0 then
gui.GameHUD.InteractFrame.InteractText.Text = "Press and hold F to use "..objtype.." for "..cost
else
gui.GameHUD.InteractFrame.InteractText.Text = "Press and hold F to use "..objtype
end
end
end)
ProximityPromptService.PromptHidden:Connect(function(ProximityPrompt)
local Highlight = ProximityPrompt.Parent:FindFirstChildOfClass("Highlight")
Highlight:Destroy()
local gui = game.Players.LocalPlayer.PlayerGui
gui.GameHUD.InteractFrame.Visible = false
end)
I reused some variables, cleaned up the if-else chain, added some safety with WaitForChild, fallback message, better naming and readibility.
local Players = game:GetService("Players")
local ProximityPromptService = game:GetService("ProximityPromptService")
local player = Players.LocalPlayer
local gui = player:WaitForChild("PlayerGui")
local interactFrame = gui:WaitForChild("GameHUD"):WaitForChild("InteractFrame")
local interactText = interactFrame:WaitForChild("InteractText")
local promptMessages = {
[1] = function(name, cost) return ("Press and hold F to buy %s for %s"):format(name, cost) end,
[2] = function(_, cost) return ("Press and hold F to spend %s to open the door"):format(cost) end,
[3] = function(name, cost)
return cost ~= 0
and ("Press and hold F to interact with %s for %s"):format(name, cost)
or ("Press and hold F to interact with %s"):format(name)
end,
[4] = function(_, cost) return ("Press and hold F to spend %s to remove the debris"):format(cost) end,
[5] = function(name, cost)
return cost ~= 0
and ("Press and hold F to use %s for %s"):format(name, cost)
or ("Press and hold F to use %s"):format(name)
end,
}
ProximityPromptService.PromptShown:Connect(function(prompt)
local msgType = prompt:WaitForChild("MessageType")
local objName = msgType:WaitForChild("ObjName")
local cost = objName:WaitForChild("Price").Value
local adornee = objName.Price:WaitForChild("HighlightAdornee").Value
local typeValue = msgType.Value
local highlight = Instance.new("Highlight")
highlight.FillColor = Color3.new(1, 1, 1)
highlight.FillTransparency = 1
highlight.Adornee = adornee
highlight.Parent = prompt.Parent
interactFrame.Visible = true
local objDisplayName = objName.Value or "Object"
local messageFunc = promptMessages[typeValue]
if messageFunc then
interactText.Text = messageFunc(objDisplayName, cost)
else
interactText.Text = "Press and hold F to interact"
end
end)
ProximityPromptService.PromptHidden:Connect(function(prompt)
local highlight = prompt.Parent:FindFirstChildOfClass("Highlight")
if highlight then
highlight:Destroy()
end
interactFrame.Visible = false
end)
I also made some adjustments following the @Piet edits. I removed the highlight creation and destruction since only one instance is needed. Additionally, I replaced the WaitForChild inside the signal function with FindFirstChild and implemented some condition checks along with it, as it is faster to find instances and avoid yielding the script.
local PlayerService = game:GetService("Players")
local ProximityPromptService = game:GetService("ProximityPromptService")
local player = PlayerService.LocalPlayer
local playerGui = player:WaitForChild("PlayerGui")
local gameHUD = playerGui:WaitForChild("GameHUD")
local interactFrame = gameHUD:WaitForChild("InteractFrame")
local interactText = interactFrame:WaitForChild("InteractText")
local highlight = Instance.new("Highlight")
local promptMessages = {
[1] = function(name, cost) return ("Press and hold F to buy %s for %s"):format(name, cost) end,
[2] = function(_, cost) return ("Press and hold F to spend %s to open the door"):format(cost) end,
[3] = function(name, cost)
return cost ~= 0
and ("Press and hold F to interact with %s for %s"):format(name, cost)
or ("Press and hold F to interact with %s"):format(name)
end,
[4] = function(_, cost) return ("Press and hold F to spend %s to remove the debris"):format(cost) end,
[5] = function(name, cost)
return cost ~= 0
and ("Press and hold F to use %s for %s"):format(name, cost)
or ("Press and hold F to use %s"):format(name)
end,
}
ProximityPromptService.PromptShown:Connect(function(prompt)
local msgType = prompt:FindFirstChild("MessageType")
local objName = msgType and msgType:FindFirstChild("ObjName")
local cost = objName and objName:FindFirstChild("Price")
local adornee = cost and cost:FindFirstChild("HighlightAdornee")
local typeValue = msgType and msgType.Value
local objDisplayName = (objName and objName.Value) or "Object"
local messageFunc = promptMessages[typeValue]
interactFrame.Visible = true
interactText.Text = "Press and hold F to interact"
if adornee then
highlight.FillTransparency = 1
highlight.Adornee = adornee.Value
highlight.Parent = prompt.Parent
end
if cost and messageFunc then
interactText.Text = messageFunc(objDisplayName, cost.Value)
end
end)
ProximityPromptService.PromptHidden:Connect(function(prompt)
highlight.Adornee = nil
highlight.Parent = nil
interactFrame.Visible = false
end)
It is a table that holds functions a table holds an Index then a value, the index is [1] and the value is function(...) example if you want to add another prompt you can do
[6] = function() return ("Hello This Is My Newly Custom Added Function Prompt!") end,
Make sure you add the COMMA after end or else you will see a bunch of red lines.