Hello, I am creating a fighting game and want to create an input system that can activate any abilities corresponding to the input. I’m trying to think of a good way to make this but I’m at a loss. I tried having a module store what input does what and keeping a move name, tied remotes, etc. But it seems that doesn’t work.
I also tried making a folder that holds modules for the combat but I don’t know how to continue that as well.
You don’t need to use :WaitForChild on instances that are visible in the Studio Explorer before the game is run! Those are guaranteed to exist before scripts are executed (because they are “static”, i.e. exist from the start of the game and aren’t created through a script).
What does InputHandler look like? I assume that is what you’re struggling with.
It’s empty again atm, but as a basic script for what it might look like. I made this just now because I’m not on studio but this is close of what I have. Keybinds module isn’t made and most of the script isn’t finished or made.
local UserInputService = game:GetService("UserInputService")
--Keybind module used to map what keybinds to what.
--EXAMPLE: MouseButton1 = {'move name', 'move module?'}
local Keybinds = require(module.for.keybinds)
local InputRemote : RemoteEvent
local InputDetection = coroutine.create(function()
UserInputService.InputBegan:Connect(function(input, GPE)
if GPE then return end
... --main code
Keybinds :FireServer(input)
end)
end)
You don’t need a coroutine for event connections like .InputBegan:Connect. Think of them less like loops and more like functions you’ve declared, they don’t block the rest of the script:
local function MyFunction()
wait(5)
end
-- "Hi" is printed even though there is a "wait" in the function because we have not
-- called that function before printing "Hi"
print("Hi!")
-- Event connections are a little different though, it's sort of like speaking to someone
-- without caring about whether you're giving them enough time to understand your words between sentences.
You could have a for-loop that checks through the keybinds module for anything that has the same input like so:
-- I will assume that the module whose code you've given in the main post
-- is the one named "BasicCombat"
local Keybinds = require(script.Parent.Combat.BasicCombat)
UserInputService.InputBegan:Connect(function(Input, ShouldIgnore)
-- Also called "GameProcessedEvent", "ShouldIgnore" will be `true` when the user
-- is interacting with other things like a textbox, and we of course want to ignore that.
if ShouldIgnore then
return
end
for _, Keybind in Keybinds.BasicCombat do
if Keybind.Input == Input.KeyCode or Keybind.Input == Input.UserInputType then
-- The user has pressed a keybind with an associated RemoteEvent, fire it.
-- You look like you've forgotten to give a name to the RemoteEvent
-- in the dictionary, but I'll just write this assuming you've assigned it to "Remote".
Keybind.Remote:FireServer()
end
end
end
I wasted a significant amount of time writing up a detailed explanation on dictionaries, only to realize you already knew what they were and had just written a typo. Whoops!
Would firing the server when specific inputs are activated hurt the server?
local UserInputService = game:GetService("UserInputService")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local InputModule = require(ReplicatedStorage:WaitForChild("Libraries"):WaitForChild("Input"))
local Keybinds = require(script:WaitForChild("Keybinds"))
local InputRemote = ReplicatedStorage:WaitForChild("Events"):WaitForChild("Shared"):WaitForChild("Inputs"):WaitForChild("Inputs")
local plr = game:GetService("Players").LocalPlayer
UserInputService.InputBegan:Connect(function(Input : InputObject, GPE : boolean)
if GPE then return end
--Gives an input
local PlayerInput = nil do
--print(Input.UserInputType, Input.KeyCode)
if Input.KeyCode == Enum.KeyCode.Unknown then
PlayerInput = Input.UserInputType
elseif Input.UserInputType == Enum.UserInputType.None or Input.UserInputType == Enum.UserInputType.Keyboard then
PlayerInput = Input.KeyCode
end
end
for Keys, _ in pairs(Keybinds) do
if Keys == PlayerInput then
print("MATCH")
--InputRemote:FireServer(PlayerInput.Name, false)
else continue
end
end
local Move = Keybinds[Input]
InputRemote:FireServer(PlayerInput.Name, true)
end)
UserInputService.InputEnded:Connect(function(Input : InputObject, GPE : boolean)
if GPE then return end
--Gives an input
local PlayerInput = nil do
--print(Input.UserInputType, Input.KeyCode)
if Input.KeyCode == Enum.KeyCode.Unknown then
PlayerInput = Input.UserInputType
elseif Input.UserInputType == Enum.UserInputType.None or Input.UserInputType == Enum.UserInputType.Keyboard then
PlayerInput = Input.KeyCode
end
end
for Keys, _ in pairs(Keybinds) do
if Keys == PlayerInput then
print("END")
--InputRemote:FireServer(PlayerInput.Name, false)
else continue
end
end
end)
If you are able to give more information on what type of Framework you are look for it would allow us to further help you. (Classes, Different Combat Types, Tools, etc.)
If you are worried about using up network resources, for this case you shouldn’t be. It’s only when you start firing several remote events many times a second per player.
But personally, I would recommend the keybinds be connected to functions instead of remote events, because those function could handle extra visual effects and reduce “input delay” and then also fire a remote event to tell the server to actually perform the combat action.