How do I drag an object from the place where I picked it up?

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By happyfork

Hello, I’m sorry if this question is vague.

I’m making a game where one of the mechanics is to drag platforms out of the way. I want the platform to move along with the mouse as long as the mouse is clicked, but I also want the platform to be able to collide with other objects, so I’m using move_and_collide.

Additionally, I am hoping to be able to reuse this script for all platforms regardless of how they are rotated, so I tried to account for the rotation in the code. But now, both rotated and non-rotated platforms are broken, and in different ways? Something about sin or cos equaling 0 pulls the platform towards specific points in the game space and I’m not smart enough to figure out why.

The commented out line for offset works when the platform has no rotation, to give you an idea of what I’m trying to do.

extends KinematicBody2D

var dragging = false
var offset : Vector2

func _on_Area2D_input_event(viewport: Node, event: InputEvent, shape_idx: int) -> void:
	if event is InputEventMouseButton:
		if event.button_index == BUTTON_LEFT:
			print( "Mouse Position: " +
				str( get_local_mouse_position() ) +
				"\nDistance to Middle of platform: " +
				str( get_local_mouse_position().distance_to( self.position ) ) ) 

			offset = Vector2( get_local_mouse_position().distance_to( self.position ) * cos(rotation),
				get_local_mouse_position().distance_to( self.position ) * sin(rotation) )
				
			#offset = get_local_mouse_position()
			dragging = event.pressed

func _input(event: InputEvent) -> void:
	if event is InputEventMouseButton:
		if event.button_index == BUTTON_LEFT and !event.pressed:
			dragging = false

func _physics_process(delta: float) -> void:
	if dragging:
		var new_position = get_viewport().get_mouse_position() - offset
		move_and_collide( new_position - position )

Edit:

Okay, I got my code to kind of do what I want it to (it still snaps the platform to the mouse, but at least it centers the mouse in the grab-able Area2D). My problem now is that I just don’t understand WHY it works. Is there something weird about how the local mouse position translates to the global mouse position?

New code:

extends KinematicBody2D

var dragging = false
var offset : Vector2

func _on_Area2D_input_event(viewport: Node, event: InputEvent, shape_idx: int) -> void:
	if event is InputEventMouseButton:
		if event.button_index == BUTTON_LEFT:
			print( "Mouse Position: " +
				str( get_local_mouse_position() ) +
				"\nDistance to Middle of platform: " +
				str( get_local_mouse_position().distance_to( self.position ) ) ) 

			offset = Vector2( get_local_mouse_position().distance_to( self.position ) * cos(rotation),
				get_local_mouse_position().distance_to( self.position ) * sin(rotation) )
			if( get_local_mouse_position().x < self.position.x ):
				offset = Vector2( offset.x * -1, offset.y )
			if( get_local_mouse_position().y < self.position.y ):
				offset = Vector2( offset.x, offset.y * -1)
				
			#offset = get_local_mouse_position()
			dragging = event.pressed

func _input(event: InputEvent) -> void:
	if event is InputEventMouseButton:
		if event.button_index == BUTTON_LEFT and !event.pressed:
			dragging = false

func _physics_process(delta: float) -> void:
	if dragging:
		var new_position = get_viewport().get_mouse_position() - offset/4
		move_and_collide( new_position - position )
:bust_in_silhouette: Reply From: Bernard Cloutier

Vector2 get_local_mouse_position ( ) const
Get the mouse position relative to this item’s position.

You are getting position relative to your platform. So if the mouse is 10 pixel to the left and 35 pixels above your platform, get_local_mouse_position will return the following Vector2: (-10, -35).

If the mouse is 50 pixels to the right and at the same height, you’ll get (50, 0).

So you don’t need to do all that offset calculation, you can just do this:

var mouse_dir = get_local_mouse_position().normalized()

Then just move like so:

move_and_collide(mouse_dir * dragging_speed)

Not sure if I did it right, but now the platforms just move to the left while the mouse is clicked, they don’t stick to the mouse position at all. Code:

extends KinematicBody2D

var dragging = false
var mouseDir : Vector2

func _on_Area2D_input_event(viewport: Node, event: InputEvent, shape_idx: int) -> void:
	if event is InputEventMouseButton:
		if event.button_index == BUTTON_LEFT:
			mouseDir = get_local_mouse_position().normalized()
			dragging = event.pressed

func _input(event: InputEvent) -> void:
	if event is InputEventMouseButton:
		if event.button_index == BUTTON_LEFT and !event.pressed:
			dragging = false

func _physics_process(delta: float) -> void:
	if dragging:
		move_and_collide( mouseDir * 10 )

happyfork | 2020-09-30 22:17

Well mouse_dir is only set when the button is first clicked. If you want the direction to update as you move the mouse around, you should do this instead:

extends KinematicBody2D

var dragging = false
var mouseDir : Vector2

func _on_Area2D_input_event(viewport: Node, event: InputEvent, shape_idx: int) -> void:
    if event is InputEventMouseButton:
        if event.button_index == BUTTON_LEFT:
            dragging = event.pressed

func _input(event: InputEvent) -> void:
    if event is InputEventMouseButton:
        if event.button_index == BUTTON_LEFT and !event.pressed:
            dragging = false

func _physics_process(delta: float) -> void:
    if dragging:
        mouseDir = get_local_mouse_position().normalized()
        move_and_collide( mouseDir * 10 )

You’ll need to smooth out the movement when the mouse is inside the shape, but it’ll follow your mouse as long as you’re holding left click.

Bernard Cloutier | 2020-09-30 23:42

Oh, I think I phrased the question wrong. Your code works, but it brings the origin of the platform towards the mouse, rather than the point that I click on.

Also, I abandoned this method and just used a PathFollow2D, since I want the platform to stay on tracks anyway.

Thank you though!

happyfork | 2020-10-01 00:23

:bust_in_silhouette: Reply From: angstyloop