Creating a "E to interact" with multiple models

I’m currently working on a “e to interact” script, but the way it works currently is it only works with one model (a wardrobe) to make it open and close. What I want is the script to work with every wardrobes in the workspace without having to make a script for every single one of them.
This is what I have so far : (sorry for the messed up code)

local HumanoidRootPart = game.Players.LocalPlayer.Character:WaitForChild(“HumanoidRootPart”)
local UIS = game:GetService(“UserInputService”)
local Part = game.Workspace.wardrobe.Detector
local tweenService = game:GetService(“TweenService”);
local open = false

if keycode.keyCode == Enum.KeyCode.E then

local tweenInfo =
1, – time
Enum.EasingStyle.Linear, – style
Enum.EasingDirection.Out, – direction
0, – repeat count
false, – reverses
0 – delaytime

  if (Part.Position - HumanoidRootPart.Position).magnitude < 20 then
  	if open == false then
  		open = true
  	 local tween = tweenService:Create(Part.Parent.Door1, tweenInfo, {CFrame =   Part.Parent.Door1Open.CFrame});
  		open = false
  	local tween = tweenService:Create(Part.Parent.Door1, tweenInfo, {CFrame = Part.Parent.Door1Closed.CFrame});


As you can see the “Part” value is one of the wardrobes, it’s probably inefficient and I’d like it to take in account all of the models called “wardrobe”


Try using iterations to get every wardrobes, and find the closest one.
To find all models named wardrobe, use something like workspace:GetChildren(), then iterate all of them and check if model.Name == "wardrobe"
I’d add a BoolValue to the Wardrobe model for convinence.
Something like this

if (keycode.keyCode == Enum.KeyCode.E) then
	local closest_wardrobe;
	local closest_distance;
	for (model in wardrobes) do
		local part = model.Detector;
		local distance = (part.Position - HumanoidRootPart).magnitude;
		if (distance < math.min(20, closest_distance)) then
			closest_wardrobe = part;
			closest_distance = distance;
	if (closest_wardrobe) then
		local tween = tweenService:Create(Part.Parent.Door1, tweenInfo, { CFrame =  part.Open and Part.Parent.Door1Open.CFrame or Part.Parent.Door1Closed.CFrame });
		part.Open = not part.Open;

“if open == true then” and “if open == false then” is redundant, I recommend “if not open then” and “if open then”.


What kind of value is “wardrobes”, that you used at line 4. I’m kind of confused as how to use it, sorry if this sounds dumb, I’m just quite inexperienced with scripting

This approach is good, but it can be improved a lot by using tags! If your game starts to get big and you have ten thousands of instances in the workspace, iterating through all of them simply to find a couple wardrobes is very inefficient. If you instead use tags, you can assign the same tag to all wardrobes and use this line of code instead to get them all:

local wardrobes = game:GetService("CollectionService"):GetTagged("YourTagHere")
1 Like

To add onto what @Zomebody said, heres an example of how you can use it with killbricks, of course, you’ll change it to fit your needs :+1:

The video proved to be useful, I modified it to look like this:

for model in pairs(CS:GetTagged(“Wardrobe”)) do

But the value I get from the model is a number, so it seems like I’ve done something wrong, any help would be appreciated.

That’s because the first variable in a for loop is the index, you’ll have to get the object with the second variable by doing this:

for _, model in pairs(CS:GetTagged(“Wardrobe”)) do

Hope this helped!

Thought I’d give my input here. I use an interaction system like the one you’re looking to build on a lot of my games. By far the best way is definitely using CollectionService. Now when making a system like this you need to remember that you may want to add different keys for different items, more than one tag, etc so it’s always best to make it very scale-able. The way I personally do it is by creating a folder within ReplicatedStorage, you can call it whatever you want. From there, I place ModuleScripts inside it and name each ModuleScript a CollectionService tag. Within each ModuleScript, I usually put the associated key that goes with the tag, and the function that should be run locally when that key is pressed and the interaction is available.

Here’s an example:

ReplicatedStorage [Service]
       InteractionKeys [Folder]
              doorTag [ModuleScript]
              wardrobeTag [ModuleScript]

Now in the LocalScript that handles finding the closest interaction object, I loop through the folder that holds my CollectionService tags and fetches each tag, find all the objects with those tags, calculate the closest object, and then display whatever I want on the client to let them know they can interact. Then when the player presses a key, it checks if that key is connected to the object they can interact with, if it is, it will run the connected function in the ModuleScript.

Here’s some code example:

local ReplicatedStorage = game:GetService('ReplicatedStorage');
local RunService = game:GetService('RunService');
local InteractionKeys = ReplicatedStorage:FindFirstChild('InteractionKeys');
local interactionObject;
local interactionKey;
    local closestObject;
    local closestDistance = math.huge;
     -- Loop through keys here,
     -- Check distance from player, if is within radius, check if its closer than the closest distance
     -- If it is, set the value of closestObject to it, and update the closestDistance
     -- Outside of the loop, once it's done, set the variables.

-- InputService.InputEnded callback function here
-- If interactionObject exists and so does interactionKey
-- If both exist, check if the player is typing, if not check if key is the interactionKey
-- If so, fire the function in the key's module script.

^ Would NOT work in studio, this just gives you an example.

if you’d like a full in-depth example, feel free to contact me in messages on the forum, or on discord.

I hope this helped!