Variants
Variants are like your own custom enums, except that they can contain another value. Let’s take a look at what that means, exactly.
We want to create a couple of related variants at the same time, so we’ll use the map
function:
-- src/client/inputTypes.lua
local InputTypes = Algae.map({
-- doesn't need any extra data, so we pass an empty table
MouseClicked = {},
-- needs to know which key was pressed
KeyPressed = function(key)
return { key = key }
end,
})
Now let’s use them. For the sake of this example, assume that we’re storing the last input command in a table somewhere named state
.
local inputTypes = require(ReplicatedStorage.Client.InputTypes)
local state = ... -- somewhere in the depths of our codebase
UserInputService.InputBegan:Connect(function(inputObject, gameProcessed)
-- something else is using this input, abort!
if gameProcessed then
return
end
-- when the user presses a key on their keyboard
if inputObject.UserInputType == Enum.UserInputType.Keyboard then
-- call the function we created for KeyPressed in our map & pass it the keycode
state.lastProcessedCommand = inputTypes.KeyPressed(inputObject.KeyCode)
-- when the user presses the left mouse button
elseif inputObject.UserInputType == Enum.UserInputType.MouseButton1 then
state.lastProcessedCommand = inputTypes.MouseClicked
end
end)
This is pretty cool already, but let’s take it to the next level.
Matching
Continuing with our example, let’s actually do something with our state when it changes. When lastProcessedCommand
isn’t nil, we’ll print a message depending on what it is. Once that’s done, we’ll clear the value from our state.
We can do this easily with match
:
local state = ...
RunService.Heartbeat:Connect(function()
-- inputProcessed will become whatever is returned from the case that is matched.
-- you don't always need to use the return value, but it can be pretty handy!
local inputProcessed = Algae.match(state.lastProcessedCommand, {
MouseClicked = function()
print("The mouse has been clicked!")
return true
end,
KeyPressed = function(data)
-- `data` is the value we returned from the function we mapped to KeyPressed
print(data.key .. " has been pressed!")
return true
end,
-- the `_` case is the default case
-- the default case is used when the value doesn't match any of the other cases
_ = function()
-- we can't do anything with this value, so return false
return false
end,
})
if inputProcessed then
print("Clearing the previous command")
state.lastProcessedCommand = nil
end
end)
match
can also accept regular enums from Roblox as well. We could technically replace the if/elseif statement in the first example with a match
if we wanted to!
All in all, Algae is a nice tool if you want to use it. It’s not going to make your code 10x more efficient (you won’t see any performance loss, either), but it will make your life a bit easier when you feel like you’ve got a good use case for it. In my current project, I’m using it to map different kinds of user input to commands that can be processed by my game. It makes it easy for me to support multiple input devices when the raw input is filtered through a couple match
functions into something that doesn’t care whether a player is using a mouse or a touch screen.