[Lua + Ts] Controller Cursor (OpenSource)

Introducing, Controller Cursor!
If you’ve ever tried to make your interface’s compatible for players using controllers, you understand that it’s not easy to do. If you’re a player, you understand that it’s hard to navigate UI in many games. This allows players to move a virtual cursor around the screen to select UI, just like players on PC do.

This style of navigation can be found in many AAA titles, most notably Call of Duty and Destiny.

Download
Simply take this module from the catalog and place it in somewhere in the client.

If you prefer syncing the Repository into your game using Rojo, here’s the Repository!

Special thanks to @DanzLua for porting the module to Roblox-ts! This port can be found here

Setup
The module must be required from some LocalScript on the client. To listen to the modules events, you must require the module in a LocalScript.

local ControllerCursor = require(script.ControllerCursor)

--Example event listener
ControllerCursor.GuiObjectSelectionStarted:Connect(function(guiObject)

end)

API Documentation:

function ControllerCursor:ShowCursor()

Shows the cursor, begins polling to update cursor position every frame.

Returns

  • nil
function ControllerCursor:HideCursor()

Hides the cursor, stops polling.

Returns

  • nil
Event ControllerCursor.CursorActivated

Fired when the cursor is activated i.e player pressed Select Button or a third-party LocalScript calls the method ControllerCursor:ShowCursor()

Arguments

  • none
Event ControllerCursor.CursorDeactivated

Fired when the cursor is deactivated i.e player pressed Select Button while Cursor was enabled, or a third-party LocalScript calls the method ControllerCursor:HideCursor()

Arguments

  • none
Event ControllerCursor.GuiObjectSelectionStarted

Fired when the cursor is selecting a GuiObject.

Arguments

  • SelectedObject [GuiObject]
    The GuiObject the player is currently selecting
Event ControllerCursor.GuiObjectSelectionEnded

Fired when the cursor stops selecting a GuiObject.
Arguments

  • PreviouslySelectedObject [GuiObject] or nil
    The GuiObject the player was selecting before selection stopped

End
Thanks for chekcing this out! If it helps you, please drop a heart! Let me know if you have and issues, questions or recommendations!

Testimonials

134 Likes

This is extremely helpful, as the GuiService features don’t seem to actually work in any meaningful way, making my menus nearly impossible to navigate.

I’ve modified and implemented this into my upcoming game Enclosure, and it works great!

The events let my custom controls know when to halt movement, the external functions let me pause it while dragging a slider, etc. Truly a useful and versatile system.

35 Likes

GuiService is pure garbage. It’s not useful at all, and there really needs to be a better alternative.

6 Likes

Well, now we have this as a better alternative. :smiley:

7 Likes

This isn’t the first time something like this has existed, but I’ll be damned if this isn’t the best version of it. I’m probably going to implement it later.

5 Likes

Hello, I got a question, what’s the difference between this module and this script which does the same function?:

Because honestly, I feel that it’s much more easier to insert a script than using modules. Well, that’s why I want to ask you what’s the difference between the two scripts.

3 Likes

I’ve seen that one before. My module is super organized and is more reliable than that module. It’s super easy to implement mine, just simple insert my module into a LocalScript somewhere on the client, and just call the require() global

require(script.CursorModule)

This initiate the controller module. Module scripts can be manipulated from other places on the client, unlike LocalScripts. If you don’t already extensively use modules, you will the more you learn!

Edit: My module also controls everything itself, without the requirement of outside modules. The one you linked is messy and shouldn’t be trusted.

2 Likes

ModuleScript > LocalScript, especially when it comes to creating a service, and amplified when inserting other people’s code into your game.

This module can be required from any of your scripts, allowing you to have them all interact with it and its state. It has events and APIs like a Service, and a LocalScript could offer none of that.

If we look at my example above, it’s only possible with a module.

I have to call :HideCursor() and :ShowCursor() when the user wants to drag a slider setting.
I have to connect to the .CursorActivated and .CursorDeactivated events to know when to halt the custom movement.
I have to connect to the .GuiObjectSelectionStarted event to display the button icon next to the hovered gui.

All of those are crucial, and they work right out of the box with this module.

4 Likes

Wow! That’s so cool!

This isn’t really related, but could someone pls explain to me what a “testimonial” is?

1 Like

It’s when someone gives thanks / endorses someone or something.

3 Likes

This looks amazing and very useful, great job.

3 Likes

Nice job!
That is really helpful, and I’ll make sure to implement it.

2 Likes

Could you explain me that and how it works? :slight_smile:

2 Likes

This module’s APIs are clearly documented in OP.

local GamepadCursor = require(script.GamepadCursor)

GamepadCursor:HideCursor()
wait(3)
GamepadCursor:ShowCursor()

You just call those functions when your state requires it, like when a player begins dragging a slider.

3 Likes

100% Scrolling Frame support aswell? :thinking:

2 Likes

Natively! This module simply sets the GuiService’s selected object automatically, meaning default game pad keybinds automatically work.

4 Likes

Interesting. I’m trying it here, doesn’t seem to be scrolling all the way down to the bottom (using a Scrolling Frame with a UIListLayout along with multiple buttons):
https://gyazo.com/66060c8c6c2aaaa6c2a380d0b028b2a8

(fantastic contribution btw)

1 Like

Hmm. I’ll look into that. I remember running into that issue and fixing it a while ago. Probably got lost in the open sourcing.

2 Likes

I don’t require outside modules… lol. Pretty sure that’s not even possible anymore.

How can it not be trusted if all of the code required is there…

Please do your research before making such claims.

As for your module, I’ve got to admit that it does allow a lot more control than mine does, but it doesn’t appeal to the basic developer. My system is more of a one-size-fits-most approach.

2 Likes

I just tested in studio and scrolling frames seem to be working perfect. You have to use the right thumbstick as that’s roblox’s default keybind. If this doesn’t work, I don’t know what the issue is :frowning:

2 Likes