Custom ProximityPrompt

Greetings, I have created a custom Proximity Prompt. But I have 2 issues.

First one is, that the Proximity Prompts won’t list up on each other like normal ones would do. So when I add more than 1 Proximity Prompts they start being overlapped, with that one comes the second problem. Only a single Prompt is showing up at time, even when the Keyboard Key Codes are different.

Design
This is what they look like right now.

https://gyazo.com/54fc1b350eab76b79df5ad5a3b621bec.mp4

Conclusion
First off all thank you for reading my post. I would appreciate any help or suggestions how to improve this system.

The client script:

local ProximityPromptService = game:GetService("ProximityPromptService")
local UserInputService = game:GetService("UserInputService")
local Players = game:GetService("Players")
local TweenService = game:GetService("TweenService")
local RunService = game:GetService("RunService")

local Player = Players.LocalPlayer
local PlayerGui = Player:WaitForChild("PlayerGui", 30)

local PromptGui = PlayerGui:WaitForChild("Prompt", 30)

--- CONFIGURATION ---
local touchIcon = "rbxassetid://7898432686"
local basicColor = Color3.fromRGB(255, 255, 255)
local holdColor = Color3.fromRGB(122, 122, 122)

local PromptTweenInfo = TweenInfo.new(0.3, Enum.EasingStyle.Quad, Enum.EasingDirection.Out)
local PromptHoldTweenInfo = TweenInfo.new(0.5, Enum.EasingStyle.Quint, Enum.EasingDirection.Out)
--- END ---

local GamepadButtonImage = {
	[Enum.KeyCode.ButtonX] = "rbxasset://textures/ui/Controls/xboxX.png",
	[Enum.KeyCode.ButtonY] = "rbxasset://textures/ui/Controls/xboxY.png",
	[Enum.KeyCode.ButtonA] = "rbxasset://textures/ui/Controls/xboxA.png",
	[Enum.KeyCode.ButtonB] = "rbxasset://textures/ui/Controls/xboxB.png",
	[Enum.KeyCode.DPadLeft] = "rbxasset://textures/ui/Controls/dpadLeft.png",
	[Enum.KeyCode.DPadRight] = "rbxasset://textures/ui/Controls/dpadRight.png",
	[Enum.KeyCode.DPadUp] = "rbxasset://textures/ui/Controls/dpadUp.png",
	[Enum.KeyCode.DPadDown] = "rbxasset://textures/ui/Controls/dpadDown.png",
	[Enum.KeyCode.ButtonSelect] = "rbxasset://textures/ui/Controls/xboxmenu.png",
	[Enum.KeyCode.ButtonL1] = "rbxasset://textures/ui/Controls/xboxLS.png",
	[Enum.KeyCode.ButtonR1] = "rbxasset://textures/ui/Controls/xboxRS.png",
}

local buttonDown
local holdBeganConnection
local holdEndedConnection
local triggeredConnection
local triggerEndedConnection

local function Tween(tweenInfo, instances, properties)
    pcall(function()
        for _, instance in ipairs(instances) do
            local TweenInstance = TweenService:Create(instance, tweenInfo, properties)
            TweenInstance:Play()
        end
    end)
end

local function onShown(prox, input, Prompt)
    if input == Enum.ProximityPromptInputType.Touch then
        Prompt.ActivateButton.Text = ""
    elseif input == Enum.ProximityPromptInputType.Keyboard then
		local text = UserInputService:GetStringForKeyCode(prox.KeyboardKeyCode)
		local objtext = prox.ObjectText
		Prompt.ActivateButton.Text = text
		Prompt.ObjectText.Text = objtext

        if text == "" then
            warn("ProximityPrompt \"" .. prox.Name .. "\" has unsupported Keyboard KeyCode for rendering.")

            Prompt.ActivateButton.Text = "?"
		end
		if objtext == "" then
			warn("ProximityPrompt \"" .. prox.Name .. "\" has unsupported Object Text for rendering.")

			Prompt.ActivateButton.Text = "%ERROR%"
		end
    elseif input == Enum.ProximityPromptInputType.Gamepad then
		Prompt.ActivateButton.Text = ""
		Prompt.Textlabel.Text = ""

        local success = pcall(function()
			Prompt.ActivateButton.Icon.Image = GamepadButtonImage[prox.GamepadKeyCode]
        end)

        if not success then
            warn("ProximityPrompt \"" .. prox.Name .. "\" has unsupported Gamepad KeyCode for rendering.")

			Prompt.ActivateButton.Text = "?"
			
			warn("ProximityPrompt \"" .. prox.Name .. "\" has unsupported Object Text for rendering.")

			Prompt.ActivateButton.Text = "%ERROR%"
		end
    end

    Prompt.ActivateButton.InputBegan:Connect(function(input)
        if (input.UserInputType == Enum.UserInputType.Touch or input.UserInputType == Enum.UserInputType.MouseButton1) and input.UserInputState ~= Enum.UserInputState.Change then
            buttonDown = true
            prox:InputHoldBegin()
        end
    end)

    Prompt.ActivateButton.InputEnded:Connect(function(input)
        if input.UserInputType == Enum.UserInputType.Touch or input.UserInputType == Enum.UserInputType.MouseButton1 then
            if buttonDown then
                buttonDown = false
                prox:InputHoldEnd()
            end
        end
    end)

    Prompt.Adornee = prox.Parent

    Tween(PromptTweenInfo, { Prompt.ActivateButton }, { TextTransparency = 0 })
	Tween(PromptTweenInfo, { Prompt.ActivateButton.Icon }, { ImageTransparency = 0 })
	Tween(PromptTweenInfo, {Prompt.ObjectText}, { TextTransparency = 0 })

    if prox.HoldDuration > 0 then
        holdBeganConnection = prox.PromptButtonHoldBegan:Connect(function()
			if Prompt:FindFirstChild("ActivateButton") then
				script.Sound:Play()
				Tween(PromptHoldTweenInfo, { Prompt.ActivateButton }, { Position = UDim2.fromScale(0, 0.2), })
				Tween(PromptHoldTweenInfo, { Prompt.ActivateButton.Icon}, { ImageColor3 = holdColor})
            end
        end)

        holdEndedConnection = prox.PromptButtonHoldEnded:Connect(function()
            if Prompt:FindFirstChild("ActivateButton") then
				Tween(PromptHoldTweenInfo, { Prompt.ActivateButton }, { Position = UDim2.fromScale(0, 0), })
				Tween(PromptHoldTweenInfo, { Prompt.ActivateButton.Icon}, { ImageColor3 = basicColor})
            end
        end)
    end

    triggeredConnection = prox.Triggered:Connect(function()
		if Prompt:FindFirstChild("ActivateButton") then
			script.Sound:Play()
			Tween(PromptHoldTweenInfo, { Prompt.ActivateButton }, { Position = UDim2.fromScale(0, 0.2), })
			Tween(PromptHoldTweenInfo, { Prompt.ActivateButton.Icon}, { ImageColor3 = holdColor})
        end
    end)

    triggerEndedConnection = prox.TriggerEnded:Connect(function()
        if Prompt:FindFirstChild("ActivateButton") then
			Tween(PromptHoldTweenInfo, { Prompt.ActivateButton }, { Position = UDim2.fromScale(0, 0), })
			Tween(PromptHoldTweenInfo, { Prompt.ActivateButton.Icon}, { ImageColor3 = basicColor})
        end
    end)
end

local function onHidden(pr)
    Tween(PromptTweenInfo, { pr.ActivateButton }, { TextTransparency = 1 })
	Tween(PromptTweenInfo, { pr.ActivateButton.Icon }, { ImageTransparency = 1 })
	Tween(PromptTweenInfo, { pr.ObjectText}, { TextTransparency = 1 })

    if holdBeganConnection and holdEndedConnection then
        holdBeganConnection:Disconnect()
        holdEndedConnection:Disconnect()
    end

    triggerEndedConnection:Disconnect()
    triggeredConnection:Disconnect()

    wait(0.3)

    pr:Destroy()
end

ProximityPromptService.PromptShown:Connect(function(prompt, inputType)
    if prompt.Style == Enum.ProximityPromptStyle.Default then
        return
    end

    local Prompt = PromptGui:Clone()
    Prompt.Name = "DisplayPrompt"
    Prompt.Parent = PlayerGui

    onShown(prompt, inputType, Prompt)

    prompt.PromptHidden:Wait()

    onHidden(Prompt)
end)
3 Likes

“ProximityPrompt” instances can only be triggered in server scripts.

1 Like

Don’t worry the ProximityPrompt works fine, the only problem I have is the listing of multiple ProximityPrompts.

You need to configure it with a Server Script via proximity prompt service i believe

Have you tried using UIListLayout so they don’t overlap?

Yes I tried that already but as it’s 2 separated BillboardGUIs it won‘t work.

That fixed my first issue, but the listing of multiple BillboardGUIs still does not work.

do multiple different prompts then, are you trying to combine 3 in 1 proximity prompt?

Hello, do you think you could make this open sourced like in a game, I like this might want to code over it.