You can write your topic however you want, but you need to answer these questions:
What do you want to achieve? Keep it simple and clear!
So, I’m trying to make arrow key navigation on a gui.
What is the issue? Include screenshots / videos if possible!
When I use ContextActionService, I always see this error: ContextActionService: Unexpected error while invoking callback:Players.SonicFrontiers011.PlayerGui.Interface.Main.Scripture.TitleScreen:220: attempt to call missing method ‘Select’ of string
What solutions have you tried so far? Did you look for solutions on the Developer Hub?
As of right now, I have not found a solution to this yet.
Here is the code:
local function NavigateArrowKeys(GuiService, slot)
GuiService:Select(slot)
end
task.spawn(function()
while true do
task.wait()
for i, slot in pairs(SaveSlotsList) do
ContextActionService:BindAction("NavigateKeys", NavigateArrowKeys, false, Enum.KeyCode.Down)
end
end
end)
Why are you taking GuiService as a parameter to your bound action? The name of the action, a string, is actually getting stored there, not GuiService. You need some other way to access the things you want to access.
Parameters given by :BindAction() to the callback:
actionName: string
inputState: Enum.UserInputState
inputObject: InputObject
Example of bound action:
local guiService = game:GetService("GuiService")
local cas = game:GetService("ContextActionService")
local selectedObjects = --[[objects you want to use the GuiService:Select() method with]]
local function onAction(_actionName: string, _state: Enum.UserInputState, _inputObj: InputObject)
guiService:Select(selectedObjects)
end
cas:BindAction("ActionNameHere", onAction, true, Enum.KeyCode.E)
Yes. Remember, variables are just pointers to locations in memory. If the variable is assigned to in a higher scope than the bound action or is created as a global, it’ll be accessible and changed accordingly.
--for example...
local x = 0
local function foo(num: number)
x += num
end
foo(3)
foo(5)
print(x) --> 8
Yes. If you define x outside of the function, it will be incremented as expected. If you define it inside of the function, it’s not accessible by any greater scope level, e.g. the rest of the script, so attempting to use it would give you editor warning “Unknown global” and errors like “Attempt to perform arithmetic (add) on nil and number”.
Also, how can I check if like the player is going up or down?
I’m not sure if this would work:
local function NavigateArrowKeys(input)
if input.UserInputType == Enum.UserInputType or Enum.UserInputType.Gamepad1 then
if input.KeyCode == Enum.KeyCode.Up then
-- selectButton(buttons[table.find(buttons, selected_button) + 1])
elseif input.KeyCode == Enum.KeyCode.Down then
--selectButton(buttons[table.find(buttons, selected_button) - 1])
end
end
end
Looks like they used a table for holding their buttons, using user input to change the selection appropriately. That kind of system works, if you don’t want to manually make a table you could tag your buttons and use CollectionService:GetTagged().
It looks like it might be better to use UserInputService instead of ContextActionService, but both can be used because both provide an InputObject holding the KeyCode.
I’m pretty sure Roblox already provides a built-in navigation system for PC, using the # key to toggle it.
print(GuiService.SelectedObject)
--or, for the ancestry:
print(GuiService.SelectedObject:GetFullName())
Edit (in response to your edit):
Try printing it out after using the Roblox navigator (# or \ key). If it still comes out as nil, you might need to make your own custom system.