Proximity Code Interactive

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.

image


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

image

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.

  1. 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"
  1. 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.

  2. Honorable mentions
    The Anser_Key will be the correct code.
    The View_Distance will be the farthest away you can be from the prompt that is visible.
    The Remote_Connector_Name is the name of the RemoteEvent you wish to connect to this system.

The result of all this/seeing it work

https://streamable.com/8hs6al

Code could be less messy smh

5 Likes