Make a simple E-to-Interact door

Welcome, this tutorial will be going over on how you can make your own simple and easy-to-understand E-to-interact door. This can be done with anything, but this tutorial will be going over it with a door, and with the basics of ContextActionService and UserInputService, along with CollectionService. This tutorial will also use TweenService to show progress.

This tutorial assumes you know basic usage of all 4 services, but if not, don’t worry. They are simple to use, and it’s easy to understand them. Maybe you can even understand how they work and how you can use them while you scroll through this tutorial. Now let’s get on with it.


We will start off by inserting a Billboard Gui into the StarterGui, adding a frame in it, and setting its Adornee to a door that we want to apply this one. You can place this wherever you want, but this tutorial goes over with it being in the StarterGui, because we’re only going over one door. It’s better to place it in the doors if you’re going over multiple ones.

Ignore the other scripts, we’ll be going over that later. You might find some obvious if you’re experienced with things like these.

Now you’ll want to make a duplicate of the frame you’ve just made and call it “fill” or whatever you want I guess, then place it into the frame you made earlier. Make a TextLabel like shown above and name it whatever you want, as long as it’s accessible. The UICorner is obviously optoinal, I just wanted to make the GUI look good.

Oh yeah, forgot to mention, fill’s background color should be slightly darker than the original frame, and should be slightly transparent to where the textlabel can still be seen, we will be using this to show progress when the player holds E to interact with the door.

Now insert a LocalScript into StarterCharacterScripts and name it whatever you want, I’ll name mine doorHandler. We’ll start off by indexing a few necessary things.

Once that’s done, let’s create a tween for our fill frame.

I’m declaring the door variable early so we can define what door we’re talking about later on for the kicking part, so that we can access it easily.

Tip: Treat the x and y coordinates of UDim2 as percentages. For example, 0.5 is 50%, in decimals.

Now let’s begin using UserInputService.


Oh, you know how to use UserInputService already, so you’re now getting ahead of the tutorial? Hang on. We wouldn’t want the entire thing to start when the player is doing something else with their keyboard like typing into a textbox, or chatting. Let’s check if the input is game-processed first. Of course, this is an optional task.


Got rid of that issue in just a few easy lines. No wthat that’s out of the way, let’s start with the real thing. We’ll want to check if the player is actually within the MaxDistance of the BillBoard Gui, and check if they are actually pressing the text of the button (like E).

Now, what the hell is cs:HasTag(door,"door") you ask? Well, if you know what CollectionService is (which I clearly linked up above and explained that we will be using it in this tutorial), you’ll know what’s going on. But if you don’t, remember the “doortags” script in ServerScriptService earlier up above? Yeah, wer’re adding tags to doors now.

We’ll basically want to put the door(s) in a folder that you could call whatever you want for easy access.


Then the doortags script,

But this is just really optional, of course unless you have multiple doors you want to do this with.

Now let’s return to the doorHandler script (or whatever you’ve called it).

Since we are talking about a Hold-E-to-Interact and not a Press-E-to-Interact (unless that’s what you want), you wouldn’t really want it to progress even when the player isn’t holding E anymore, wouldn’t you?

Optionally, in order to prevent them from moving away from the door as they hold E, you can set the humanoid walkspeed to 0, and AutoRotate to false.

(If you want to rather reset the progress, use Tween:Cancel()).


Yeah, this isn’t really required, but I like kicking doors. Ignore this part if you want, and try to make your own way of opening the door. But I think kicking is cool.

Well, since the event tween.Completed exists, we should probably make use of it in this situation, and bind the action to kick once the tween has completed.

And also make the function that we are binding the action to so that Roblox’s syntax highlighting stops screaming about it.

Oh yeah, you might be intimidated by the FireServer part if you don’t know what RemoteEvents are. Eh, just look it up. I am too lazy to explain, plus others would do a better job than me at explaining what they are.

Anyways, we’d want to unbind the action after the door has been kicked, because we wouldn’t really need to kick it again after it’s already down, would we? Let’s unbind the action using the action name (or you can actually use the action parameter if you’re all about being fancy). Also, don’t remember to disable the Billboard Gui. No use in having it enabled after it’s down now.

All right, how about we add a remote event in ReplicatedStorage and call it whatever we want for the kicking part? And set kickEvent's value to it before you get confused on why there’s an error.

Oh, yeah, and add a kick script for the kickEvent receiver. kickEvent has no use if we don’t.

(For security reasons, it’s recommended that you check if the door has the “Door” tag with CollectionService in order to prevent exploiters from taking down anything).

Now into the kick script,

I’m pretty certain we fired the remote event from the client with the client’s humanoidrootpart’s look vector multiplied by 3 and the door as arguments, we’ll be using those here as parameters.

And here, we have a “kicking effect” for our door, you should be proud. Now you’ve made your own very simple e-to-interact door, which you get to kick it. The first thing you do with a door you see is kick it, remember that.

Now let us forget that I ever made that cringey “punchline” or whatever you call it. Thanks for actually spending time reading this tutorial, stay hydrated, have a good weekend, peace.


Thanks! It helped =). It would be great if you made more tutorials like this.


There are some security issues I see here mainly the server event. An exploiter can send whatever part he wanted init. So maybe the baseplate or a tree. It would update all clients and destroying the game.


While you are correct, I think this post was more intended as a general tutorial for interactions. Of course if you are to use that script, you would want some proper checks done.

1 Like

You said:

if not (door ~= nil) then return end

But couldn’t you just do:

if not door then return end
if door == nil return end

Still a great tutorial


yeah, it’s just me making things complicated so that i look like i know what i’m doing, which, i don’t

1 Like

Yeah, that’s what CollectionService is for, perhaps.

Thank you so much! You should make some more tutorials like this in the future.

By the way, what font do you use? I want that font lol

1 Like

Credits to BlackShibe, the man, the fox, the doge, the legend. It’s the Bahnschrift font.

1 Like

other than the userinputservice part why is the rest of the code on client… Its very easy for exploiters to exploit your code that way.

Let’s say that instead of a door we fired the map. Because we unanchor on the server it will happen for everybody.

Pretty certain I added tags on things using CollectionService. Once the RemoteEvent is fired, on the server, we can check if the door we’re “kicking” has the door tag, if not, then it can’t be affected. That is honestly what I meant

No??? It’s why we’re using CollectionService to check if the door has a tag named “Door” (or whatever it was named). Using exploits to add a tag would only work on them and not the entire game.

Doing this returns “Unable to cast Value to Object”. Anyone know why? Everything’s the same except I have an or statement also allowing unions.

remove the “isUnlocked” part, and the isabasepart part, we don’t really need those if you aren’t putting anything else in the door folder

1 Like

It’s still returning that same error. Is anyone else having the same issue?

Thanks a lot! I can not explain to you how much I needed something like this!

Are you sure what you’re checking is actually an instance?

Yes. I’m trying to add the tag to a union. This is my code:

local cans = game.Workspace.TrashCans:GetChildren()

local cs = game:GetService("CollectionService")

for _, door in ipairs(cans) do
1 Like

Oh, you’re doing cs:AddTag("Door"), instead of implementing in the cans as the first argument. Do:

for _, door in ipairs(cans) do
    cs:AddTag(door, "Door");