0 votes


So I've tinkering with this analog joystick that I found in one of the posts here, but it seems to be that I'm having trouble mapping it to one of the nodes. Specifically to my player character. I tried inserting "if conditions" inside the func isPressed(event), but it doesn't work the way I wanted.

Is there anyway to translate a character's movement based on this joystick? I have no Idea where, or how to implement it in this code. Thanks in advance for all your help, and assistance.

extends Node2D

const INACTIVE_IDX = -1;
export var isDynamicallyShowing = false
export var listenerNodePath = ""
export var name = ""

var ball
var bg 
var animation_player
var parent
var listenerNode

var centerPoint = Vector2(0,0)
var currentForce = Vector2(0,0)
var halfSize = Vector2()
var ballPos = Vector2()
var squaredHalfSizeLenght = 0
var currentPointerIDX = INACTIVE_IDX;

func _ready():
    bg = get_node("bg")
    ball = get_node("ball") 
    animation_player = get_node("AnimationPlayer")
    parent = get_parent();
    halfSize = bg.get_item_rect().size/2;
    squaredHalfSizeLenght = halfSize.x*halfSize.y;

    if (listenerNodePath != "" && listenerNodePath!=null):
        listenerNodePath = get_node(listenerNodePath)
    elif listenerNodePath=="":
        listenerNodePath = null

    isDynamicallyShowing = isDynamicallyShowing and parent extends Control
    if isDynamicallyShowing:
#       hide()

func get_force():
    return currentForce

func _input(event):
    var incomingPointer = extractPointerIdx(event)
    if incomingPointer == INACTIVE_IDX:

    if need2ChangeActivePointer(event):
        if (currentPointerIDX != incomingPointer) and event.is_pressed():
            currentPointerIDX = incomingPointer;
            showAtPos(Vector2(event.x, event.y));

    var theSamePointer = currentPointerIDX == incomingPointer
    if isActive() and theSamePointer:

func need2ChangeActivePointer(event): #touch down inside analog
    var mouseButton = event.type == InputEvent.MOUSE_BUTTON
    var touch = event.type == InputEvent.SCREEN_TOUCH

    if mouseButton or touch:
        if isDynamicallyShowing:
            return get_parent().get_global_rect().has_point(Vector2(event.x, event.y))
            var lenght = (get_global_pos() - Vector2(event.x, event.y)).length_squared();
            return lenght < squaredHalfSizeLenght
     return false

func isActive():
    return currentPointerIDX != INACTIVE_IDX

func extractPointerIdx(event):
    var touch = event.type == InputEvent.SCREEN_TOUCH
    var drag = event.type == InputEvent.SCREEN_DRAG
    var mouseButton = event.type == InputEvent.MOUSE_BUTTON
    var mouseMove = event.type == InputEvent.MOUSE_MOTION

    if touch or drag:
        return event.index
    elif mouseButton or mouseMove:
        return 0
        return INACTIVE_IDX

func process_input(event):
    calculateForce(event.x - self.get_global_pos().x, event.y - self.get_global_pos().y)

    var isReleased = isReleased(event)
    if isReleased:
    var isPressed = isPressed(event)
    if isPressed:
        #print("is pressed")

func reset():
    currentPointerIDX = INACTIVE_IDX
    calculateForce(0, 0)

    if isDynamicallyShowing:

func showAtPos(pos):
    if isDynamicallyShowing:
        animation_player.play("alpha_in", 0.2)

func hide():
    animation_player.play("alpha_out", 0.2) 

#ball position per press
func updateBallPos():
    ballPos.x = halfSize.x * currentForce.x #+ halfSize.x
    ballPos.y = halfSize.y * -currentForce.y #+ halfSize.y

func calculateForce(var x, var y):
    #get direction
    currentForce.x = (x - centerPoint.x)/halfSize.x
    currentForce.y = -(y - centerPoint.y)/halfSize.y

    if currentForce.length_squared()>1:


func sendSignal2Listener():
    if (listenerNodePath != null):
        listenerNodePath.analog_force_change(currentForce, self)

func isPressed(event):
    #print("pressed x")
    #var mouse_pos = get_global_mouse_pos()
    var mouse_pos = get_local_mouse_pos()


    if mouse_pos.x >= 0.1:
        get_node("/root/global").player_direction = "rightm"
    elif mouse_pos.x <= -0.1:
        get_node("/root/global").player_direction = "leftm"
    elif mouse_pos.y <= -0.1:
        get_node("/root/global").player_direction = "upm"
    elif mouse_pos.y >= 0.1:
        get_node("/root/global").player_direction = "downm"


    if event.type == InputEvent.MOUSE_MOTION:
        return (event.button_mask==1)
    elif event.type == InputEvent.SCREEN_TOUCH:
        return event.pressed

func isReleased(event):
    if event.type == InputEvent.SCREEN_TOUCH:
        return !event.pressed
    elif event.type == InputEvent.MOUSE_BUTTON:
        return !event.pressed
in Engine by (44 points)

1 Answer

0 votes

The code looks like it's created out of this plugin...https://github.com/gswashburn/Analog-Stick-Demo/ am i right?
So i did these steps to implement that:

  1. Download & install that plugin via Asset Store
  2. In the Scene you have your Player & UI, create a Control Node (with a defined 'Rectangle'-property, in which the Analog Stick will be showing) then add a instanced child scene from "analog.tscn" and give it properties in the inspector.
  3. Have a look at the "Node" Tab beside the inspector and connect the signal "analogforcechange" with your players code.
  4. The signal passes the vector2D the joystick is pressed, so the receiving function could pass that vector to the movement logic of your player / element you want to move.

I had some errors related to 'global_position' of the event, that might be caused by my Godot Version (3.1.2)...if you encounter that: just change the error lines from 'event.global_position' to 'position' and you should be able to use it.

(Can confirm this plugin works, have implemented & tweaked it for a Twin-Stick-Shooter)

by (39 points)
edited by

Hi Cap, yes I think so.Only that mine's the older version prior to 3.0. I'm currently implementing it to a 2d node and I haven't been successful. I already finished steps one and two. As for step three, I'm not sure yet, but if you could walk me through this, I'd really appreciate it. Perhaps a simple code implementation could really help a lot. Thanks for the reply. Much appreciated.

Welcome to Godot Engine Q&A, where you can ask questions and receive answers from other members of the community.

Please make sure to read How to use this Q&A? before posting your first questions.
Social login is currently unavailable. If you've previously logged in with a Facebook or GitHub account, use the I forgot my password link in the login box to set a password for your account. If you still can't access your account, send an email to webmaster@godotengine.org with your username.