Hey, so I just finished working on this ProximityPrompt type GUI and I’d thought I would share it because I thought it was interesting and was looking for some feedback on how to make it better.
GUI
Alright here is the Gui that you will see when it pops up.

Scripting/Organization
Since I might release this for everyone to use eventually I will just include the code here.
Scripting
Main Client Code
--v
local GUI = script.Parent;
local MAIN_FRAME = GUI.MainFrame;
local CONFIG_FOLDER = GUI.Configuration;
local ADORNEE_VALUE = CONFIG_FOLDER.Adornee;
local CONFIG_MODULE = require(CONFIG_FOLDER.MainConfig);
local PROGRESS_BAR = MAIN_FRAME.Progress;
local KEY_BOX = MAIN_FRAME.TextBox;
local TEXT_BOX_FOCUS_BUTTON = MAIN_FRAME.GuiButton;
local CASE_SENSITIVE = CONFIG_MODULE.Case_Sensitive;
local ANSER_KEY = CONFIG_MODULE.Answer_Key;
local SHOW_PROGRESS = CONFIG_MODULE.Show_Progress;
local VIEW_DISTANCE = CONFIG_MODULE.View_Distance;
local REMOTE_CONNECTION_NAME = CONFIG_MODULE.Remote_Connector_Name;
local PLAYER = game:GetService("Players").LocalPlayer;
local MOUSE = PLAYER:GetMouse()
local CHARACTER = PLAYER.Character or PLAYER.CharacterAppearanceLoaded:Wait();
local HUMANOID_ROOT_PART = CHARACTER:WaitForChild("HumanoidRootPart");
local CAMERA = workspace.CurrentCamera
local REPLICATED_STORAGE = game:GetService("ReplicatedStorage");
local USER_INPUT_SERVICE = game:GetService("UserInputService");
local TWEEN_SERVICE = game:GetService("TweenService")
local RUN_SERVICE = game:GetService("RunService");
local USER_IS_TYPING = false;
local USER_CAN_TYPE = true;
local FOUND_CONNECTOR = false;
local REMOTE_CONNECTOR = nil;
--Create BillboardGui
--[[
local NEW_BILLBOARD_GUI = Instance.new("BillboardGui", GUI);
NEW_BILLBOARD_GUI.Size = UDim2.new(0,200,0,50);
]]
GUI.Adornee = ADORNEE_VALUE.Value;
--[[
NEW_BILLBOARD_GUI.AlwaysOnTop = true;
MAIN_FRAME.Parent = NEW_BILLBOARD_GUI;
MAIN_FRAME.Position = UDim2.new(0.5,0,0.5,0);
MAIN_FRAME.Size = UDim2.new(1,0,1,0);
script.Parent = NEW_BILLBOARD_GUI;
CONFIG_FOLDER.Parent = NEW_BILLBOARD_GUI;
]]
--Locate remote
for i,v in pairs(REPLICATED_STORAGE:GetDescendants()) do
if v:IsA("RemoteEvent") then
if v.Name == REMOTE_CONNECTION_NAME then
REMOTE_CONNECTOR = v;
break
end
end
end
if REMOTE_CONNECTOR == nil then
for i,v in pairs(game:GetDescendants()) do
local S,E = pcall(function()
if v.Name == REMOTE_CONNECTION_NAME then
REMOTE_CONNECTOR = v;
end
end)
end
if REMOTE_CONNECTOR ~= nil then
warn("Remote Event found. Please move it to [game.ReplicatedStorage] for better script efficiency.");
else
warn('The RemoteEvent['..REMOTE_CONNECTION_NAME..'] was not found. Please make one and parent it under [game.ReplicatedStorage].');
end
else
--print("Remote Found");
end
--Some more checks
--if NEW_BILLBOARD_GUI.Parent ~= nil and REMOTE_CONNECTOR ~= nil then
--FOUND_CONNECTOR = true;
--USER_CAN_TYPE = true;
--end
--The functions
local function PromptProgressAdjust(String)
if SHOW_PROGRESS == true then
local POINT_VALUE = 1 / #ANSER_KEY
if CASE_SENSITIVE == false then
local LOWERED_ANSWER_KEY = string.lower(ANSER_KEY)
local LOWERED_STRING = string.lower(String)
local ANSWERED_PART_OF_KEY = string.sub(LOWERED_ANSWER_KEY,1,#String)
--print("Made progress")
--warn(tostring(#ANSWERED_PART_OF_KEY).."/"..tostring(#ANSER_KEY))
if LOWERED_ANSWER_KEY ~= LOWERED_STRING then
local NEW_TWEEN = TWEEN_SERVICE:Create(
PROGRESS_BAR,
TweenInfo.new(0.1, Enum.EasingStyle.Quad,Enum.EasingDirection.InOut),
{BackgroundColor3 = Color3.fromRGB(255, 154, 66);
Size = UDim2.new(POINT_VALUE * #ANSWERED_PART_OF_KEY,0,0.075,0)
}
)
NEW_TWEEN:Play()
else
local NEW_TWEEN = TWEEN_SERVICE:Create(
PROGRESS_BAR,
TweenInfo.new(0.1, Enum.EasingStyle.Quad,Enum.EasingDirection.InOut),
{BackgroundColor3 = Color3.fromRGB(145, 255, 133);
Size = UDim2.new(POINT_VALUE * #ANSWERED_PART_OF_KEY,0,0.075,0)
}
)
NEW_TWEEN:Play()
end
else
local ANSWERED_PART_OF_KEY = string.sub(ANSER_KEY,1,#String)
if String ~= ANSER_KEY then
local NEW_TWEEN = TWEEN_SERVICE:Create(
PROGRESS_BAR,
TweenInfo.new(0.1, Enum.EasingStyle.Quad,Enum.EasingDirection.InOut),
{BackgroundColor3 = Color3.fromRGB(255, 154, 66);
Size = UDim2.new(POINT_VALUE * #ANSWERED_PART_OF_KEY,0,0.075,0)
}
)
NEW_TWEEN:Play()
else
local NEW_TWEEN = TWEEN_SERVICE:Create(
PROGRESS_BAR,
TweenInfo.new(0.1, Enum.EasingStyle.Quad,Enum.EasingDirection.InOut),
{BackgroundColor3 = Color3.fromRGB(145, 255, 133),
Size = UDim2.new(POINT_VALUE * #ANSWERED_PART_OF_KEY,0,0.075,0)
}
)
NEW_TWEEN:Play()
end
end
end
end
local function ProcessAnswer(input)
--warn("Got")
if CASE_SENSITIVE == false then
local L_AK = string.lower(ANSER_KEY)
local L_CU = string.lower(input)
if L_CU == L_AK then
REMOTE_CONNECTOR:FireServer(ADORNEE_VALUE.Value)
--print("Correct!")
end
else
if input == ANSER_KEY then
REMOTE_CONNECTOR:FireServer(ADORNEE_VALUE.Value)
--print("Correct!")
end
end
end
MOUSE.Button1Down:Connect(function()
wait()
if USER_IS_TYPING then
USER_IS_TYPING = false
KEY_BOX:ReleaseFocus()
ProcessAnswer(KEY_BOX.Text)
--print("L")
local NEW_TWEEN = TWEEN_SERVICE:Create(
PROGRESS_BAR,
TweenInfo.new(0.1, Enum.EasingStyle.Quad,Enum.EasingDirection.InOut),
{BackgroundColor3 = Color3.fromRGB(255, 154, 66);
Size = UDim2.new(1,0,0.075,0)
}
)
NEW_TWEEN:Play()
end
end)
TEXT_BOX_FOCUS_BUTTON.MouseButton1Down:Connect(function()
--print("E")
if not USER_IS_TYPING then
USER_IS_TYPING = true
KEY_BOX:CaptureFocus()
if SHOW_PROGRESS then
local NEW_TWEEN = TWEEN_SERVICE:Create(
PROGRESS_BAR,
TweenInfo.new(0.1, Enum.EasingStyle.Quad,Enum.EasingDirection.InOut),
{BackgroundColor3 = Color3.fromRGB(255, 154, 66);
Size = UDim2.new(#KEY_BOX.Text,0,0.075,0)
}
)
NEW_TWEEN:Play()
end
end
end)
KEY_BOX:GetPropertyChangedSignal("Text"):Connect(function()
PromptProgressAdjust(KEY_BOX.Text)
--warn("ad")
end)
KEY_BOX.FocusLost:Connect(function()
if USER_IS_TYPING then
USER_IS_TYPING = false
KEY_BOX:ReleaseFocus()
ProcessAnswer(KEY_BOX.Text)
local NEW_TWEEN = TWEEN_SERVICE:Create(
PROGRESS_BAR,
TweenInfo.new(0.1, Enum.EasingStyle.Quad,Enum.EasingDirection.InOut),
{BackgroundColor3 = Color3.fromRGB(255, 154, 66);
Size = UDim2.new(1,0,0.075,0)
}
)
NEW_TWEEN:Play()
end
end)
GUI:GetPropertyChangedSignal("Adornee"):Connect(function()
if GUI.Adornee == nil then
MAIN_FRAME.Visible = false
KEY_BOX:ReleaseFocus()
KEY_BOX.Text = ""
local NEW_TWEEN = TWEEN_SERVICE:Create(
PROGRESS_BAR,
TweenInfo.new(0.1, Enum.EasingStyle.Quad,Enum.EasingDirection.InOut),
{BackgroundColor3 = Color3.fromRGB(255, 154, 66);
Size = UDim2.new(1,0,0.075,0)
}
)
NEW_TWEEN:Play()
else
MAIN_FRAME.Visible = true
end
end)
Billboard GUI organization code
local player = game:GetService("Players").LocalPlayer
local character = player.Character or player.CharacterAppearanceLoaded:Wait()
local hrp = character:WaitForChild('HumanoidRootPart')
local g = script.Parent
while wait(0.1) do
pcall(function()
for i,v in pairs(g:GetDescendants()) do
if v:IsA('BillboardGui') then
local dist = require(v.Configuration.MainConfig).View_Distance
local adv = v.Configuration.Adornee.Value
if ((hrp.Position - adv.Position).Magnitude <= dist) then
v.Enabled = true
--print("t")
else
v.Enabled = false
--print("f")
end
end
end
end)
end
Example of use case code
Credit to radiogamer for the code used to open the door.
DoorValue = 0 -- Variables used
Door = script.Parent
Door1 = Door.DoorPart1
Door2 = Door.DoorPart2
Door.PlayerCheck.Size = Door.Parent.Configuration.PlayerCollisionRange.Value
function open() -- Run when a player approaches the door
DoorValue = DoorValue + 1 -- Add count how many players are near the door
script.Open.Value = true
Door1.PrismaticConstraint.TargetPosition = -10
Door2.PrismaticConstraint.TargetPosition = -10
end
function close() -- Run when a player goes away from the door
DoorValue = DoorValue - 1 -- Lower count how many players are near the door. If no more players are nearby, close the door
if DoorValue < 0 then
DoorValue = 0
end
if DoorValue == 0 then
script.Open.Value = false
Door1.PrismaticConstraint.TargetPosition = 0
Door2.PrismaticConstraint.TargetPosition = 0
end
end
function onTouched(hit) -- When a player is near the door
local humanoid = hit.Parent:FindFirstChildWhichIsA("Humanoid")
if (humanoid and humanoid.RootPart == hit) then
open()
end
end
function onEnded(hit) -- When a player is going away from the door
local humanoid = hit.Parent:FindFirstChildWhichIsA("Humanoid")
if (humanoid and humanoid.RootPart == hit) then
close()
end
end
game.ReplicatedStorage:WaitForChild('UI-prompt-remote-connect').OnServerEvent:Connect(function(Player, Gui_Ado_Obj)
if Gui_Ado_Obj == workspace.la then
print("y")
open()
wait(2)
close()
end
end)
--Door.PlayerCheck.Touched:connect(onTouched)
--Door.PlayerCheck.TouchEnded:connect(onEnded)
Config module
local c={
Case_Sensitive = false; --if you enter (ABdgH), it will return as (abdgh)
Answer_Key = "a_darkwatcher"; --the answer to the code
Show_Progress = true; --shows the progress of you filling in the
View_Distance = 13; -- the max distance away from the Adornee that will allow to be visible
Remote_Connector_Name = "UI-prompt-remote-connect"; --the name of the remote that the script will connect to
}
return c
Organization
Client setup

All server code will be written by the user when integrating this system into their game.
The handler script checks through all the BillboardGuis to see if the player in reach with them. All this system needs to set up the remote event is the name of it. First, it will look in the ReplicatedStorage, if it is not there it will look through the entire game to find it. I only made it this way to make it easier for people to configure and set up this. Some of the code could use some optimization to make it a lot more efficient.
Features
As mentioned in the Config Module, there are some different things you can change to this.
-
Case_Sensitivity.
It is pretty self-explanatory, any case type of letter will be accepted.
Case_Sensitive = false;
local tpe = "XXxX"
tpe = "xxxx"
Case_Sensitive = true;
local tpe = "XXxX"
tpe = "XXxX"
-
Show progress
This is also a little self-explanatory. As will be shown in the video below, the orange bar will show how much you have done so far. Getting the answer correct will make the bar turn green and it will be full. -
Honorable mentions
TheAnser_Keywill be the correct code.
TheView_Distancewill be the farthest away you can be from the prompt that is visible.
TheRemote_Connector_Nameis the name of theRemoteEventyou wish to connect to this system.
The result of all this/seeing it work
Code could be less messy smh