Hi, I’ve made a simple unlock mini puzzle, where the game generates a secret 4 digit number, and it lights up the blocks in that order. Here’s a short video demonstration:
Here’s the structure and how the logic works:
Each blue pad (Unlocker1, Unlocker2, etc.) contains a ModuleScript which fires an event whenever it is touched by a character:
local onTouch1 = {} -- it is named onTouch2, onTouch3 for each pad and so on. The code is exactly the same.
local bindableEvent = Instance.new("BindableEvent")
onTouch1.Hit = bindableEvent.Event
local unlockerPart = script.Parent
local debounce = true
local function onTouch(touchedPart)
local partParent = touchedPart.parent
local humanoid = partParent:FindFirstChild("Humanoid")
if humanoid then
if(debounce) then
unlockerPart.Color = Color3.fromRGB(10, 40, 210)
bindableEvent:Fire()
debounce = false
end
end
end
function onTouch1.resetDebounce()
debounce = true
end
function onTouch1.lockDebounce()
debounce = false
end
unlockerPart.Touched:Connect(onTouch)
return onTouch1
Then, the ModuleScript “UnlockerModule” in the Unlocker model handles these events shot by each of the pads to create a userInput string via concatenation. It then compares it with the secret it generated:
local unlockerModule = {}
local Unlocker1 = script.Parent.Unlocker1
local Unlocker2 = script.Parent.Unlocker2
local Unlocker3 = script.Parent.Unlocker3
local Unlocker4 = script.Parent.Unlocker4
local unlocker1Hit = require(script.Parent.Unlocker1.ModuleScript)
local unlocker2Hit = require(script.Parent.Unlocker2.ModuleScript)
local unlocker3Hit = require(script.Parent.Unlocker3.ModuleScript)
local unlocker4Hit = require(script.Parent.Unlocker4.ModuleScript)
local bindableEvent = Instance.new("BindableEvent")
unlockerModule.authenticate = bindableEvent.Event
local userInput = ""
local function generateSecret()
local secret = ""
local secretTable = {"1","2","3","4"}
for i=1, 4 do
local randomIndex = math.random(#secretTable)
local randomElement = secretTable[randomIndex]
secret = secret .. randomElement
table.remove(secretTable, randomIndex)
end
return secret
end
local generatedSecret = generateSecret()
print("secret: "..generatedSecret)
local function authenticate()
if(string.len(userInput) == 4) then
if(userInput == generatedSecret) then
bindableEvent:Fire(true)
else
bindableEvent:Fire(false)
end
end
end
local function animatePart(c)
local unlockPart
if c == "1" then unlockPart = Unlocker1
elseif c == "2" then unlockPart = Unlocker2
elseif c == "3" then unlockPart = Unlocker3
else unlockPart = Unlocker4
end
unlockPart.Color = Color3.fromRGB(10, 40, 210)
wait(0.5)
unlockPart.Color = Color3.fromRGB(237, 234, 234)
wait(0.5)
end
local function animateSecret(number)
for i=1, #number do
local c = number:sub(i,i)
animatePart(c)
end
end
animateSecret(generatedSecret)
function unlockerModule.reset()
userInput = ""
Unlocker1.Color = Color3.fromRGB(237, 234, 234)
Unlocker2.Color = Color3.fromRGB(237, 234, 234)
Unlocker3.Color = Color3.fromRGB(237, 234, 234)
Unlocker4.Color = Color3.fromRGB(237, 234, 234)
lockPads()
generatedSecret = generateSecret()
print("secret: "..generatedSecret)
wait(1)
animateSecret(generatedSecret)
unlockPads()
end
function lockPads()
unlocker1Hit.lockDebounce()
unlocker2Hit.lockDebounce()
unlocker3Hit.lockDebounce()
unlocker4Hit.lockDebounce()
end
function unlockPads()
unlocker1Hit.resetDebounce()
unlocker2Hit.resetDebounce()
unlocker3Hit.resetDebounce()
unlocker4Hit.resetDebounce()
end
unlocker1Hit.Hit:Connect(function()
userInput = userInput.."1"
print("userInput: "..userInput)
authenticate()
end)
unlocker2Hit.Hit:Connect(function()
userInput = userInput.."2"
print("userInput: "..userInput)
authenticate()
end)
unlocker3Hit.Hit:Connect(function()
userInput = userInput.."3"
print("userInput: "..userInput)
authenticate()
end)
unlocker4Hit.Hit:Connect(function()
userInput = userInput.."4"
print("userInput: "..userInput)
authenticate()
end)
return unlockerModule
However, this method doesn’t really seem scalable and I find it quite redundant. First, I have to duplicate the ModuleScripts for all the blue pads (it is fine with 4 pads, but not very efficient if I have a lot of pads). Then in UnlockerModule, I also have to handle all of the similar events separately, which adds extra lines.
Is there a better way to structure this, such that we can eliminate duplicate ModuleScripts and event handlers? Would like to hear your opinions, thank you!