Interactive Object System for Procedural Environments using Proximity Prompts

Greetings, developers!

I’ve crafted a Lua script for ROBLOX that enhances player interaction within procedurally generated environments. This script intelligently manages in-game objects, providing dynamic responses and effects based on player actions.

Core Features:

  • Dynamic Prompts: Objects with a “Species” attribute automatically generate interactive prompts, allowing for a rich, responsive game world.
  • Player Observation: The script tracks player interactions with objects, offering unique responses and triggering custom effects tailored to each encounter.
  • Efficient Messaging: Utilizes a bot processor to display messages, ensuring seamless communication between the game environment and the player.
  • Proximity-Based Interactions: Objects respond when players are near, thanks to proximity prompts that trigger custom behaviors and messages.

Technical Breakdown:

  • Prompt Management: The script clones a pre-defined prompt template and attaches it to relevant objects, enabling player interaction.
  • Connection Handling: It maintains an array of connections to manage object states and interactions efficiently.
  • Observation Logic: An observation array keeps track of player-object interactions, preventing redundant prompts and ensuring a smooth gameplay experience.
  • Message Display: A dedicated function displays messages above the player’s character, enhancing immersion and narrative delivery.

Code Snippet:

Lua

--task.wait()
local plants=workspace.Plants
local TweenService = game:GetService("TweenService")

function plantprompt(plant)	
if plant:FindFirstChild("Species")~=nil then
		script.Prompt:Clone().Parent=plant
		
	end
end
local prompttemplate=script.Prompt

local function formatplant(plant)
		plantprompt(plant)
	-- 
end

local connectionarray={}
local observationarray={}
local playerbot=game.ReplicatedStorage.GlobalSpells.ChatbotAlgorithm.ChatModule.APlayerBot
local botprocessor=game.ReplicatedStorage.GlobalSpells.BindableFunction
local function firemessage(args)
	botprocessor:Invoke("displayString",args)
end
local function displaymessage(player,object,message)
	local displayer=playerbot:Clone()
	local TextLabel=displayer.TextLabel
	displayer.Parent=player.PlayerGui
	displayer.Adornee=player.Character.Head	
	firemessage({TextLabel,message,player.Character})
end

local function observeobject(player,object)
	--local attributes={}
	if observationarray[tostring(player)..object.Species.Value]==nil then
	observationarray[tostring(player)..object.Species.Value]=true	
	local examine=object:GetAttribute("examine")
		
		object.PromptObject.ExaminePrompt.ActionText="Interact"
		if examine then
		--	spawn(function()
				displaymessage(player,object,examine)
		--	end)	
		end
	else
		if observationarray[tostring(player)..object.Species.Value]==true then
			observationarray[tostring(player)..object.Species.Value]=1
		local interact=object:GetAttribute("Interact")
		if interact then
				spawn(function()
					displaymessage(player,object,interact)
				end)	
			end	
		end	
			local efx=object:FindFirstChild("EFX")
			if efx and efx.ClassName=="ModuleScript" then
				local mod=require(efx)
				if mod["EFX"]~=nil then
					mod.EFX(object,player)
				else print(tostring(object).." has no function called EFX.")	
				end		
			end			
		end	
end

local function prompt(ProximityPrompt,object)
	--local debounce = false
	local ProximityPrompt=ProximityPrompt
	connectionarray[object]=ProximityPrompt.Triggered:Connect(function(player)
		local	h = player.Character:findFirstChild("Humanoid") 
		if (h~=nil) then
			--if debounce == false then
			if player.PlayerGui:FindFirstChild("LocalPrompt")==nil then
				script.LocalPrompt:Clone().Parent=player.PlayerGui			
			end
			player.PlayerGui.LocalPrompt.CurrentPrompt.Value=ProximityPrompt
				--debounce = true
				local thisplr = game.Players:findFirstChild(h.Parent.Name)
				if (thisplr~=nil) then
					local stats = thisplr:findFirstChild("leaderstats")
					if (stats~=nil) then
						print("Examine Triggered")
						observeobject(player,object)
					end
			end
			task.delay(3.6,function()
				if player.PlayerGui.LocalPrompt.CurrentPrompt.Value==ProximityPrompt then 	
					player.PlayerGui.LocalPrompt.CurrentPrompt.Value=nil					
				end
			end)
		end
	end)	
end



local function getprompt(object,actiontext,objecttext)
	local prom=object:FindFirstChild("ExaminePrompt")
	if prom==nil then
		prom=script.ProximityPrompt:Clone()
	end	
	if actiontext then
		prom.ActionText=actiontext
	end	
	if objecttext then
		prom.ObjectText=objecttext
	end
	prom.Parent=object
	return prom	
end

local function testarray()
--	return workspace.LowerWallProps:GetChildren()
end
local promptpart=Instance.new("Part")
promptpart.CanTouch=false
promptpart.CanCollide=false
promptpart.Anchored=true
promptpart.Transparency=1
promptpart.Name="PromptObject"
--promptpart.CFrame=object.CFrame:ToWorldSpace(CFrame.new(0,-object.Size.Y/2,0))

local function formatobject(object)
	if object:IsA("BasePart") and object:GetAttribute("examine") and object:FindFirstChild("Species") then
		
		local prom=object:FindFirstChild("ExaminePrompt")
		if prom==nil then 
			local promptpart2=promptpart:Clone()
			promptpart2.CFrame=object.CFrame:ToWorldSpace(CFrame.new(0,-object.Size.Y/2,0))
			promptpart2.Parent=object
			prom=getprompt(promptpart2,nil,object.Species.Value)
			prom.Name="ExaminePrompt"
		end
		prompt(prom,object)
	end	
end
--local promptarray={}
local function formatexamineobjects(array)

	for i,object in array do 
		formatobject(object)
		--table.insert(promptarray,{object=object,prompt=prom})
	end
end
--formatexamineobjects(testarray())

for index,plant in plants:GetChildren() do 
if plant:FindFirstChild("Prompt")==nil then	
		formatplant(plant)	
end		
end
workspace.Furniture.ChildAdded:Connect(formatobject)
workspace.Furniture.ChildRemoved:Connect(function(object)
	if connectionarray[object]~=nil then	
	connectionarray[object]:Disconnect()
		connectionarray[object]=nil
	end	
end)
plants.ChildAdded:Connect(formatplant)
-- Lua code snippet showcasing the dynamic prompt and observation system

This system is designed to be lightweight and adaptable, suitable for various procedural generation scenarios. It’s been a game-changer for my project, and I’m eager to see how it can enhance yours!


Feel free to adjust the technical details to better fit your forum post. This description aims to provide a clear and concise overview of your script’s functionality and its benefits to the ROBLOX development community. :herb::video_game:
image
Example Object: create.roblox.com/store/asset/17357649566
EFX Code Example

local module = {}

function module.EFX(object,player)
	local Spelltable= game.ReplicatedStorage.Spellbook.Spells["Point Attack"]:GetChildren()
	
game.ReplicatedStorage.GlobalSpells.BindableFunction:Invoke("MagicSpell",{object,Spelltable[math.random(1,#Spelltable)],object,0,1})
object.Transparency=1
	local skeleton=game.ReplicatedStorage.Spellbook.SpellAssets.Template:Clone()
	skeleton.Inventory.CustomCharacter.Value="395 - Knight of Strength"
	object.CanCollide=false
	object:Destroy()
	skeleton:SetPrimaryPartCFrame(object.CFrame:ToWorldSpace(CFrame.new(0,0,-3)))
	skeleton.Parent=workspace.Enemys
	skeleton.Humanoid.Died:Connect(function() 
		for i,item in	player.PlayerGui.Bars.Inventory:GetChildren() do
			if item:FindFirstChild("ItemID") and (item.ItemID.Value=="" or item.ItemID.Value==nil) then
				local array={"Strength Ring","Archer Ring","Magic Ring", "DF Ring"}
				item.ItemID.Value=array[math.random(1,4)] 
				break
			end
		end
	end)
end

return module

2 Likes