Your code works perfectly fine, but it can be improved.
The way I fixed it was I added a ScreenGui to StarterGui and added a TextButton to the ScreenGui. Now here's the important part, change the properties of the TextButton to the following:
AnchorPoint = 0.5, 0.5
Position = {0.5, 0},{0.5, 0}
Size = {0, 0},{0, 0}
Then parent your LocalScript to the TextButton and that's it.
Make sure your TextButton background is transparent, so the player can't see the TextButton.
Improved code
local UserInputService = game:GetService("UserInputService")
local TextButton = script.Parent
local function OnInputBegan(Input, GameProcessedEvent)
if Input.KeyCode == Enum.KeyCode.Z then
if not TextButton.Modal and not GameProcessedEvent then
TextButton.Modal = true
return
end
if TextButton.Modal and not GameProcessedEvent then
TextButton.Modal = false
return
end
end
end
UserInputService.InputBegan:Connect(OnInputBegan)
What is GameProcessedEvent?
GameProcessedEvent "indicates whether the game engine internally observed this input and acted on it" -- Developer wiki.
Now what does that mean? For example, if a player was chatting and typed the letter z, it would run the function which is not what we want, so we make sure that GameProcessedEvent is false. Hope you understood.
We don't need that active variable you made, we can save memory.
Why did I add the keyword return?
If I didn't, it would run both of the conditional statements because it won't stop the function from running.
Why did I make a calling function?
Because what you did was create a function every time a player input something. This is bad for performance.