{Press E to open door

Hello Devs! I am trying to make a door which will open only if the player presses E and close automatically after 5 seconds.
I don’t have any idea about it,can you guys tell me how to do it?

6 Likes

I couldn’t figure out how to make it to close after few seconds. But I found with keybind E and it opens! https://www.youtube.com/watch?v=Zqa10ImXCRs

5 Likes

You would have to use UserInputService to check if a player has clicked E then also check how far they are from the door using magnitude. For it to close, you would just put a Wait(5) then make the door close however you like. If you don’t know anything about UserInputService or magnitude I recommend you learn what it does. This could help you:

3 Likes

You can use Enum.KeyCode to detect when the user presses E and other checks (ie being close to the door). Both of these below will help you and work.

https://developer.roblox.com/en-us/api-reference/class/UserInputService
https://developer.roblox.com/en-us/api-reference/enum/KeyCode

What I would do is handle the proximity checks locally and on the server. The client has a local script with all the doors in either a table or can be fetched with collection service. Then the client loops through all the doors and checks if their distance is within a certain range.

local Players = game:GetService("Players")
local Workspace = game:GetService("Workspace")
local UserInputService = game:GetService("UserInputService")

local Player = Players.LocalPlayer
local Doors = {} --alternatively use collection service

local MaximumProximity = 10

local function OnInputBegan(InputObject, GameProcessedEvent)
    if InputObject.KeyCode ~= Enum.KeyCode.E then return end --stop the function if the key code is not e
    for i, Door in ipairs(Doors) do
        local DistanceFromCharacter = Player:DistanceFromCharacter(Door.Position)
        if math.floor(DistanceFromCharacter) <= MaximumProximity then
            --fire server to open
            return --so it won't open more than one door.
        end
    end
end

UserInputService.InputBegan:Connect(OnInputBegan)

Then the server would get the client’s request to open the door. Do additional checks if the client was really in range with the door then process their request to open. For every request recieved, there would be a 5 second delay like you mentioned, then the door would close.

9 Likes

Woah I didn’t know DistanceFromCharacter was a thing! Thanks for this.

1 Like

Detecting Doors

To make detecting doors easy, I’ll use CollectionService. The CollectionService manages groups (collections) of instances with tags.

Adding tags is easy. You can either do it by code:

--CollectionService:AddTag(Instance Door, String TagName)
CollectionService:AddTag(workspace.DoorModel, "Door")

Or using a plugin. (I recommend the Tag-Editor made by Sweetheartichoke.)

To get all the instances tagged with “Door”, use the :GetTagged() function of CollectionService.

local Doors = CollectionService:GetTagged("Door") -- Returns a table with all of the doors.

Detecting User's Input

You can either use UserInputService to get user’s input or bind a open-door function to any key with ContextActionService. We’ll use UserInputService instead.

local UserInputService = game:GetService("UserInputService")

UserInputService.InputBegan:Connect(function(input, gameProcessedEvent)
	if not gameProcessedEvent and input.KeyCode == Enum.KeyCode.E then
		-- Continue
	end
end)

input = InputObject, which contains information about the user’s input, such as, state, type, position, delta, and the KeyCode.
gameProcessedEvent = Boolean, it’ll be true/false depending if the user was focused on a TextBox (such as the chat) when the input event was fired.

Opening/Closing the Door

Okay, we know how to get the doors, and how to get the user’s input. It’s time to open and close the door.

local CollectionService = game:GetService("CollectionService")
local UserInputService = game:GetService("UserInputService")
local PlayersService = game:GetService("Players")

local Doors = CollectionService:GetTagged("Door") -- Table, Getting the doors using CollectionService
local LocalPlayer = PlayersService.LocalPlayer
local Distance = 5 -- The maximum distance a door can be opened in Studs

UserInputService.InputBegan:Connect(function(input, gameProcessedEvent)
	if not gameProcessedEvent and input.KeyCode == Enum.KeyCode.E then
		for Index, Door in pairs(Doors) do -- Looping through each door.
			if (LocalPlayer.Character.PrimaryPart.Position - Door.Position).Magnitude <= Distance then
				-- Open/Close your door. 
				--[[
					Note that you'll need to use a RemoteEvent / RemoteFunction if you want the door to open for everyone, since this is a LocalScript and any changes you make will not replicate to other players.
				--]]
			end
		end
	end
end)

You can read more about Magnitude here.

The script I made will open multiple doors if you are within the 5 studs range (even through walls). To fix that, you’ll have to use Rays. Basically, checking if anything (walls, parts etc.) is blocking you from opening the door.

local CollectionService = game:GetService("CollectionService")
local UserInputService = game:GetService("UserInputService")
local PlayersService = game:GetService("Players")

local Doors = CollectionService:GetTagged("Door") -- Table, Getting the doors using CollectionService
local LocalPlayer = PlayersService.LocalPlayer
local Distance = 15 -- The maximum distance a door can be opened in Studs

UserInputService.InputBegan:Connect(function(input, gameProcessedEvent)
	if not gameProcessedEvent and input.KeyCode == Enum.KeyCode.E then
		for Index, Door in pairs(Doors) do -- Looping through each door.
			local DoorRay = workspace:FindPartOnRay(Ray.new(LocalPlayer.Character.PrimaryPart.Position, (Door.Position - LocalPlayer.Character.PrimaryPart.Position) * 10), LocalPlayer.Character)
			if (LocalPlayer.Character.PrimaryPart.Position - Door.Position).Magnitude <= Distance and DoorRay and DoorRay == Door then
				-- Open/Close your door. 
			end
		end
	end
end)

Now your doors cannot be opened through walls. (I’ll personally do these checks on the server as well since exploiters can bypass them on the client)

But, if there are multiple doors within the X studs range, the client will be able to open all of them. I made a function for you to get the closest door only.

function getClosestDoor(doorArray, playerCharacter)
	if not doorArray or not playerCharacter then return false end
	local closestDoor, closestMagnitude, temporaryVariable
	
	for Index, Door in pairs(doorArray) do
		if closestDoor and closestMagnitude then
			temporaryVariable = (Door.Position - playerCharacter.PrimaryPart.Position).Magnitude
			
			if temporaryVariable < closestMagnitude then
				closestDoor = Door
				closestMagnitude = temporaryVariable
			end
		else
			closestDoor = Door
			closestMagnitude = (Door.Position - playerCharacter.PrimaryPart.Position).Magnitude
		end
	end
	return {closestDoor, closestMagnitude}
end

Your final code should look like this:

local CollectionService = game:GetService("CollectionService")
local UserInputService = game:GetService("UserInputService")
local PlayersService = game:GetService("Players")

local Doors = CollectionService:GetTagged("Door") -- Table, Getting the doors using CollectionService
local LocalPlayer = PlayersService.LocalPlayer
local Distance = 15 -- The maximum distance a door can be opened in Studs

function getClosestDoor(doorArray, playerCharacter)
	if not doorArray or not playerCharacter then return false end
	local closestDoor, closestMagnitude, temporaryVariable
	
	for Index, Door in pairs(doorArray) do
		if closestDoor and closestMagnitude then
			temporaryVariable = (Door.Position - playerCharacter.PrimaryPart.Position).Magnitude
			
			if temporaryVariable < closestMagnitude then
				closestDoor = Door
				closestMagnitude = temporaryVariable
			end
		else
			closestDoor = Door
			closestMagnitude = (Door.Position - playerCharacter.PrimaryPart.Position).Magnitude
		end
	end
	return {closestDoor, closestMagnitude}
end

UserInputService.InputBegan:Connect(function(input, gameProcessedEvent)
	if not gameProcessedEvent and input.KeyCode == Enum.KeyCode.E then
		for Index, Door in pairs(Doors) do -- Looping through each door.
			local DoorRay = workspace:FindPartOnRay(Ray.new(LocalPlayer.Character.PrimaryPart.Position, (Door.Position - LocalPlayer.Character.PrimaryPart.Position) * 10), LocalPlayer.Character)
			if (LocalPlayer.Character.PrimaryPart.Position - Door.Position).Magnitude <= Distance and DoorRay and DoorRay == Door and getClosestDoor(Doors, LocalPlayer.Character)[1] == Door then
				print("Opened " ..Door.Name)
			end
		end
	end
end)
31 Likes

No, because this category isn’t for asking others to write systems for you. You can ask for directions or make an attempt yourself first. That being said, you’re lucky enough that people have actually gone the mile to supply sample code, but in the future please do not ask for others to make things for you here.

7 Likes

A great answer even though the OP was breaking a rule of this category. You should post this in #resources:community-resources and I know some people might benefit a lot from it.

4 Likes