0 votes

I have a small problem. I have two objects in my scene, which I can move with the mouse, drag and place them wherever I want. However, I can not figure out how to be able to pick up one object, and not pick up the other whilst still holding to the other one.

Here is the problem I am facing: https://gyazo.com/81b58c370c25c3abf23394e38a082fad

Item.gd:

extends KinematicBody2D


# Variables that make it work
onready var spawner = get_node("/root/Scene/Player/Spawner")
onready var player = get_node("/root/Scene/Player")
onready var mouseRotation = 0

# True or False Variables
onready var canDrag = false
onready var isDragging = false


# Sound Nodes
onready var itemDelete = get_node("/root/Scene/Player/Sounds/ItemDelete")
onready var itemRotate = get_node("Sounds/Rotate")

# Stats
onready var GRAVITY = 200.0
var velocity = Vector2()

func _process(delta):
    # In order to move the object, you have to click it.

    var devMode = checkBoxNode.devCheckBox

    if (Input.is_action_pressed("ui_grabItem") && canDrag == true && devMode == true):
        dragItem()

    # Once let go, it will lock.
    if (Input.is_action_just_released("ui_grabItem")):
        canDrag = false
        isDragging = false

# This has the ability to rotate items
func _input(event):

    if event is InputEventMouseButton:

        var devMode = checkBoxNode.devCheckBox

        if event.button_index == BUTTON_WHEEL_UP && isDragging == true && devMode == true:
            rotateRight()
        if event.button_index == BUTTON_WHEEL_DOWN && isDragging == true && devMode == true:
            rotateLeft()


# These are basic functions that have no need for changing.


func rotateRight():
            mouseRotation += 5
            itemRotate.play()

            self.set_rotation_degrees(mouseRotation)

func rotateLeft():
            mouseRotation -= 5
            itemRotate.play()

            self.set_rotation_degrees(mouseRotation)

func dragItem():
    isDragging = true

    var mousePos = get_global_mouse_position()
    self.set_position(mousePos)

    if (Input.is_action_just_pressed("ui_deleteOnItem")):
        itemDelete.play()

# If the mouse is hovering over the object, it can pick it up.
func _on_Item_mouse_entered():
    canDrag = true

func _on_Item_mouse_exited():
    canDrag = false
    var devMode = checkBoxNode.devCheckBox

    if (Input.is_action_pressed("ui_grabItem") && devMode == true):
        canDrag = true

    if (Input.is_action_pressed("ui_grabItem") && devMode == false):
        canDrag = false
in Engine by (163 points)

1 Answer

0 votes
Best answer

You end up dragging the other item for two reasons:

1) because you are starting to drag in _process, while your drag action is not supposed to start every frame, right? is_action_pressed tells you if the button is held, not if it has just been pressed.

2) you are not checking if you are dragging an item already, so even if you used _input to listen for the click event as it happens, you would potentially start dragging the two items because they could be under your mouse (though I didn't test that situation, I could be wrong)

by (28,982 points)
selected by

Thank you Zylann for your answer, and I have moved my chunk of code into _input. However, could you please give me an example of how to avoid the problem? I can't think of any way.

I tried the following, which works fine, except for point 2) which I had to workaround using groups:

extends KinematicBody2D

var _dragging = false

func _input(event):
    if event is InputEventMouseMotion:
        if _dragging:
            position += event.relative

func _on_Item_input_event( viewport, event, shape_idx ):
    if event is InputEventMouseButton:
        if event.pressed:
            if event.button_index == BUTTON_LEFT:
                if get_tree().get_nodes_in_group("dragged").empty():
                    add_to_group("dragged")
                    _dragging = true
        elif _dragging:
            remove_from_group("dragged")
            _dragging = false

The group usage is a bit hacky, in a more "standard" input approach, we should be able to mark the input event as handled (so it would not propagate to further items), which doesn't seem to be possible at the moment.

Other approaches exist, such as picking stuff from a unique script instead of delegating that task to every item.

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 Frequently asked questions and 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 [email protected] with your username.