hello, I’ve been in roblox studio for a while but I don’t know many things, and I’m looking for how I can make a door that has a password and is random to the players, but that a guide tells you the numbers one at a time … someone can help ?
Hello there! Creating something like this is quite simple, I have created an example for you that you can edit as you please, and I will explain how it works so that you can create your own if you’d like!
The door we have needs to have two main outcomes:
- The user gets the password correct, open the door for them.
https://gyazo.com/4dc792b325137250eccf1c8045b502bd
- The user gets the password incorrect, you shall not pass!
https://gyazo.com/efab7aa22c205e74971135b492927741
In my version, I have a local script handling the door opening and closing.
Why did I do this?
If we allow the door to be local, it means that only the players who know the password can get in, since the door will only open for their client and not everyone on the server.
First what I did was create the tweens, which is what moves the door in a smooth way, without all the math of doing manual CFrame calculations.
-- Setup Door Tween
local OriginalPosition = Door.CFrame
local OpenPosition = Door.CFrame * CFrame.new(-4.5,0,0)
local OpenGoal = {}
local CloseGoal = {}
OpenGoal.CFrame = OpenPosition
CloseGoal.CFrame = OriginalPosition
local Info = TweenInfo.new(1, Enum.EasingStyle.Bounce)
local DoorOpen = TweenService:Create(Door,Info,OpenGoal)
local DoorClose = TweenService:Create(Door,Info,CloseGoal)
Once we have this, we can actually generate our random code, this part is pretty simple since we want a random four-digit code we can just tell the compiler to generate us a random four-digit number.
local Code = math.random(1111,9999)
Sweet! Now that we have our code we can handle the button presses and user input, I even added a 3D effect to the buttons to simulate realistic button presses!
-- Setup Button Presses
for i,v in pairs(Buttons:GetChildren()) do
v.ClickDetector.MouseClick:Connect(function()
local OriginalCFrame = v.CFrame -- Store the original position of the button.
local ButtonInput = v.Hint.TextLabel.Text -- Get which button we are pressing.
v.CFrame = v.CFrame * CFrame.new(0,0,-0.1) -- Move the button to create a 3D effect.
for i=1,10 do
RunService.Stepped:Wait() -- Wait around 10 frames, or 1/6 of a second.
end
v.CFrame = OriginalCFrame -- Move the button back to it's original position.
if string.lower(ButtonInput) == "enter" then -- If the user presses the enter button, check the code.
if CurrentInput == tostring(Code) then -- If the code is correct, let them in.
Display.TextLabel.Text = "CORRECT"
CurrentInput = ""
DoorOpen:Play()
for i=1,360 do
RunService.Stepped:Wait()
end
Display.TextLabel.Text = ""
DoorClose:Play()
elseif CurrentInput ~= tostring(Code) then -- If the code is wrong, tell them to go away.
Display.TextLabel.TextColor3 = Color3.fromRGB(255, 95, 84)
Display.TextLabel.Text = "INCORRECT"
CurrentInput = ""
for i=1,60 do
RunService.Stepped:Wait()
end
Display.TextLabel.Text = ""
Display.TextLabel.TextColor3 = Color3.fromRGB(85, 255, 127)
end
elseif string.len(CurrentInput) < 4 then
CurrentInput = CurrentInput..ButtonInput
Display.TextLabel.Text = CurrentInput
end
end)
end
If you don’t understand what’s going on basically we are detecting the button that the player is pressing, getting the value that that button has attached to it, i.e { 1, 2, 3, etc. } and then concatenating that value to our current input variable.
I also didn’t forget the guide to the code! There are four panels that are in order that tell the user what the code is.
When we put it all together we have a fantastic door system that protects anything that our hearts desire, well at least as long as they don’t find out the code.
Here is a place file you can edit to your needs, and if you need any further explanation or help, don’t hesitate to send me a message!
KeyCodeDoor.rbxl (188.5 KB)
I’ve got a lot of fine improvements to offer! Two, actually. Check 'em out.
Optimisation Tip
Tip for you and others who are decently versed with Lua: a microoptimisation to be made here, as well as a good practice, is to construct your table with the elements already present rather than to add them later.
local OpenGoal = {CFrame = OpenPosition}
local CloseGoal = {CFrame = OriginalPosition}
When you create a table with your elements already in, it will be constructed with a predefined size based on how many elements there are and it essentially allows your table to be templated. When you don’t add your elements on table construction but do it later, it forces the table to resize and reallocate (for knowledge’s sake, that relates to memory consumption).
Coding Tip for 4-Number Passwords
If you’re going to run tostring on the inputted password and on the required password for the sake of comparison, you can actually generate a 4 number password that begins with 0s.
-- Recommended to use Random API instead
local Code = math.random(0, 9999)
From here, since the Code is most likely going to be static and unlikely to change in any way, you can format the string for the sake of later comparison against the user inputted code. Why format the string? Because we work with numbers below 0.
local CodeString = string.format("%.4i", Code)
What does this do? This will insert as many 0s at the beginning as required if your number falls below the threshold described by the point. The formatted number is expected to be 4 digits, so any missing digits are filled by 0s at the start. Here is a table of what will happen if you meet a certain generation.
Generated Code | String of Code |
---|---|
5 | 0005 |
50 | 0050 |
500 | 0500 |
5000 | 5000 |
As such, you can now have codes up to 0000. No constraining codes to be at 1111 minimum (though if you had a 0 input, it could’ve been 1000 if you were unaware of this format technique).
What would be the advantages of using the Random API instead of math.random
?
Last time I checked they use the same algorithm?
The only difference I notice is that math.random
works with 32 bit integers.
math.random(0x7FFFFFFF)
-- works fine
math.random(0x80000000)
--errors
It depends on your case. math.random was changed to use the same algorithm as Random.new so at a fundamental level, you can still use either one. The difference comes down to your use case:
- Discrete state
- Nicer API (math.random also requires math.randomseed for generating new seeds, while Random pulls from a entropy source)
- Allowing deterministic results by passing the same seeds
- Branching (Random has clone)
In the case of a password door, for example, you might want to have randomly generated passwords but still have deterministic results depending on what type of approach you’re taking to your game that involves password doors.
If ya don’t care about any of that, you can continue using math.random and change “recommended” to “my personal recommendation”.
thanks you but to place it in a ScreenGui, not in SurfaceGui ?
It is in ScreenGui because it is a LocalScript, another place it can be in is StarterPlayerScripts.
thanks you … and the code, how can I change it to letters or words?
You can create a charset table of all letters and then choose a random index of that table to make a code with letters.
You can then change the buttons to have letters, although you would need a lot more of them.
Theoretically, if you wanted to forego the actual buttons (since a keyboard made of parts would be somewhat tricky to fit on a door), couldn’t you bind a ContextActionService action to when a user clicks a button/input field on the door, and then check UserInputService inputs to detect key presses?
Also, love the username! lol
Yes, you can, actually.
And if you wanted to keep it as a string comparator, all you would have to do is convert the KeyCode Enum to a string and then use a substring starting at 14 and ending at the length of the string ( Since the end of “Enum.KeyCode.” is the 14th index. ) to return only the letter pressed as a string value. The problem though is you would have to omit mouse presses and other key presses that are not letters.
Please don’t do that. EnumItems have a name property which returns the name of the item without the Enum path attached. Substring is reinventing the wheel for accessing the name property.
print(Enum.KeyCode.A.Name) -- A
Did not know that property existed, thanks for the information!