Help with optimization

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)
2 Likes

Could you explain what promptMessages is? I’ve never seen anything like that before.

(Also thanks for the help)

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.

Okay, and the variables in function() can be called upon in the text with the %s?

1 Like

%s in lua is a placeholder for string you could also do

("Press and hold F to use ".. name .. " for ".. cost)

but in my opinion the %s looks better!

1 Like

Awesome, thanks for informing me!

1 Like