Hi all, I'm new to Godot "Novice" and I'm wondering if anyone can help or point me in the right direction.

I want to setup a cursor icon to act as a virtual mouse and use either/or the hardware mouse or gamepad (xbox controller) auto select. This is for UI menu and also Inventory control.

You can use the function warp_mouse either on Viewport (for a 3D game) or Control (on a 2D game or UI).

You can also use the function warp_mouse_position on Input, which will work globally. Here is an example.

extends Node2D

onready var cursor = get_node("Cursor")
var mouse_pos = Vector2()
var mouse_speed = 3.0

func _ready():
	Input.set_mouse_mode(Input.MOUSE_MODE_HIDDEN)

func _process(delta):
	var mouse_rel = Vector2.ZERO
	if Input.is_action_pressed("mouse_up"):
		mouse_rel += Vector2.UP * mouse_speed
	if Input.is_action_pressed("mouse_down"):
		mouse_rel += Vector2.DOWN * mouse_speed
	if Input.is_action_pressed("mouse_left"):
		mouse_rel += Vector2.LEFT * mouse_speed
	if Input.is_action_pressed("mouse_right"):
		mouse_rel += Vector2.RIGHT * mouse_speed
	if mouse_rel != Vector2.ZERO:
		Input.warp_mouse_position(mouse_pos + mouse_rel)
	cursor.position = get_global_mouse_position()

func _input(event):
	if event is InputEventMouseMotion:
		mouse_pos = event.position

Here the node "Cursor" is a sprite of a mouse cursor, and the input mapping for "mouse_up" is the up arrow on the keyboard, "mouse_left" is the left arrow, etc.

Hi cyberreality, thanks for the code. I'm still having a few issues I'll post a screenshot so you can see. I'm a GDscript noob...

The script needs to be on the node above the Cursor (so Menu in this case). Then also change the top line to extends Control

That worked thanks.

Something else I've noticed is, when I test (I have 3 Buttons). When I use the Hardware Mouse I can Highlight them and click, but when I use the controller I can highlight each button but when I click on anyone of them or in an open space on the screen the last Hardware Mouse clicked button is the one that works.

Sorry for asking for more help....

Megalomaniak Thanks for the link I'll have a read and see if I can sort it out. I just expected the controller to behave the same as the mouse. The mouse can select and click on any button at any time.

    Mick I just expected the controller to behave the same as the mouse. The mouse can select and click on any button at any time.

    In that case disregard the above link. It's relevant for if you want to use the dpad directional buttons to navigate menu buttons or UI elements.

    For a emulated mouse cursor you'd have to feed the analog input into a 2D element which could deal with either collision or doing a raycast. But for those to work your buttons would probably also need collision shapes of their own or areas to overlap. There's probably better ways...


    There is a warp_mouse() on control base class that might be useful perhaps? There's also a warp_mouse_position in the Input class.

    then again... InputEventMouseMotion does have a speed property that has a setter... I've never tried it but you could maybe hack it to move the mouse cursor.

    and someone has already covered mouse clicking via input event parsing in here:
    https://godotengine.org/qa/39531/how-do-i-simulate-a-left-mouse-click-godot-3-1-beta

    Note that you can assign a custom icon to the mouse cursor via couple of ways.

    TL;DR: You are better off actually controlling the real mouse cursor and events via code using the output of the 'InputEventJoypadMotion' and 'InputEventJoypadButton' than building a custom mouse emulator via Node2D or Control classes.

    I just tried my code with a button and it seems to work fine. Can you explain more about your setup?

    I just upload a YouTube to show what happens. The first 16 second are mouse control, then I change to a Ps4 controller. From 16 seconds it shows the cursor as not smooth and unable to select on buttons, although they highlight.

    I tried to fix it, but I don't have time tonight. The trick is to generate an input event when you press the gamepad button (not using the UI input mapping).

    func _input(event):
    	if event is InputEventMouseMotion:
    		mouse_pos = event.position
    	if event.is_action_pressed("pad_click"):
    		var ev = InputEventMouseButton.new()
    		ev.button_index = 0
    		ev.pressed = true
    		ev.global_position = get_global_mouse_position()
    		Input.parse_input_event(ev)

    But I couldn't get it to work, maybe I can check tomorrow or you can try to figure it out.

    • Mick replied to this.

      cybereality Thanks for the code I'll have a look when I get home tonight and see if I can figure it out. Will let you know...

      I found some code, which I've modified to try and get smoother Cursor Movement. Next I'll try to add to the original Cursor code...

      But then back to the X button click issue.....

      Make sure to do input processing in _input(): rather than _process(): unless absolutely necessary so that input events can happen and be process in between frames being rendered too.

      • Mick replied to this.

        cybereality

        Sorry I've not had much time due to work etc, I found the buttons still don't click to activate and lockup using the controller. I tried some changes below, but I still cant get the buttons to activate like using the hardware mouse. Just wondering if you had anymore ideas ?