Custom movement using context action service


#1

I made a custom inputs system using context action service, but it seems quite long and I was wondering if it could be made shorter?
Note: Some games let you change the controls, I aim to do this so being able to unbind is necessary, since a user may want to change the controls mid way through game (unrealistic but it happens).
This is the whole script in starterplayerscripts (I’m only looking at inputs NOT the actual movement at the moment)

local plr = game:GetService("Players").LocalPlayer
local camera = workspace.CurrentCamera
local cas = game:GetService("ContextActionService")
plr.CameraMode = Enum.CameraMode.LockFirstPerson
local movez = 0
local movex = 0

local movements = {
    ["forw"] = Enum.KeyCode.W,
    ["left"] = Enum.KeyCode.A,
    ["back"] = Enum.KeyCode.S,
    ["righ"] = Enum.KeyCode.D
}

local inputs = {
    forw = false,
    left = false,
    back = false,
    righ = false,
}

local bindFunctions = {}

local function bindControls()
    for name, key in pairs(movements) do
	    bindFunctions[name] = function(_, inputState)
	        if inputState == Enum.UserInputState.Begin then 
		        inputs[name] = true
	        elseif inputState == Enum.UserInputState.End then
		        inputs[name] = false
	        end
        end
        cas:BindAction(name, bindFunctions[name], false, key)
    end
end

local function unbindControls()
    bindFunctions = {}
    for name, key in pairs(movements) do
	    cas:UnbindAction(name)
	    inputs[name] = false
    end
end

bindControls()

local function bTN(v) if v then return 1 else return 0 end end

local function updateDirection()
    movez = bTN(inputs.forw) - bTN(inputs.back)
    movex = bTN(inputs.righ) - bTN(inputs.left)
    print("updated move:", movez, movex, inputs.forw, bTN(inputs.forw))
end

game:GetService("RunService").RenderStepped:Connect(function()
    updateDirection()
    local direction = camera.CFrame.lookVector
end)

#2

ContextActionService passes actionName to the function bounded. I reckon you could make use of this by doing the following:

local function OnInput(actionName, inputState)
    inputs[actionName] = (inputState == Enum.UserInputState.Begin)
end
for name, key in pairs(movements) do
   cas:BindAction(name, OnInput, false, key)
end

This reduces the need for:

  • Multiple functions for each bind (as they all are basically doing the same thing)
  • The bindFunctions table - you seem to have this implemented but it doesn’t really do anything?

It also makes your code a bit simpler, imo.

If you have anything else to query just ask!


#3

Also, instead of storing whether an input is being done as a boolean, you could store it as the number 1 (true) or 0 (false).

This means you would not have to use the following code:

local function bTN(v) if v then return 1 else return 0 end end

And instead for updating the direction you could just do:

local function updateDirection()
    movez = inputs.forw - inputs.back
    movex = inputs.right - inputs.left
    print("updated move:", movez, movex, inputs.forw, bTN(inputs.forw))
end

#4

Thank you