Rotation by Dragging

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

I want to rotate an Area2D around its pivot according to how far it was dragged. Essentially, the rotate tool in many image editing softwares. Kind of like this. Imgur: The magic of the Internet

extends Area2D
func _input(event):
	if event is InputEventMouseButton:
		if event.button_index == BUTTON_RIGHT:
			if event.is_action_released("right_click"):
				state = NONE
			else:
				if mouseOnMe:
					get_parent().set_selected(self)
					initialOrientation = rotation 
					#Can I use this somehow?
					state = ROTATING

func _process(_delta):
    if state == ROTATING:
    	var vector = get_global_mouse_position() - global_position
    	var angle = vector.angle()
        rotation = angle

This works perfectly only when I select the right side of the Area2D, but when I select the left side of it, it rotates 180 degrees, and only then follows the behavior I want (Same for any other value that isn’t 0 degrees). Notice in the video I sent, the rotation happens according to the initial reference point of the first click.

   

did you solve your problem?

ramazan | 2022-01-05 11:05

No, my method that I have listed only works if you select the right side of the Area2D… I’m not sure how to make it rotate depending on the mouse movement and not just “face the mouse”.

CollyBlargle | 2022-01-05 16:49

:bust_in_silhouette: Reply From: chesse

Hello CollyBlargle,

take a look at this YouTube Video

Godot Mouse Drag Rotate Tutorial
from Game Designer Online

I think that should help

This behavior is not quite similar to what I want. While this system’s rotation is dependent on the mouse’s x position, I want both the x and y values to be considered to make a “polar coordinate” rotation system, similar to how it is in many image editing softwares.

CollyBlargle | 2022-01-05 21:04

I know that it wasn’t exakt your request, but the math should be the same.

You need

  1. the start rotation of your object = A
  2. the angle to the start drag point = B
  3. the angle to the current mouse drag point = C

you calculate the new rotaion of the object X by

X = C - B + A

With C - B you calculate your delta rotation while you drag and than you add the delta to A, so basicly the rotation bevor drag + the drag delta

Here is the code, i deactivted get_parent().set_selected(self) just for the example, because i got an error and didnt know what you tried to accomplish

extends Area2D
var mouseDragStartAngle = 0
func _input(event):
	if event is InputEventMouseButton:
		if event.button_index == BUTTON_RIGHT:
			if event.is_action_released("right_click"):
				state = NONE
			else:
				if mouseOnMe:
					#get_parent().set_selected(self)
					initialOrientation = rotation 
					#Can I use this somehow?
					mouseDragStartAngle = (get_global_mouse_position() - global_position).angle()
					state = ROTATING

func _process(_delta):
	if state == ROTATING:
		var vector = get_global_mouse_position() - global_position
		var mouseDragCurrentAngle = vector.angle()
		rotation = (mouseDragCurrentAngle - mouseDragStartAngle) + initialOrientation

you can see i only added mouseDragStartAngle and changed the calculation of rotation

chesse | 2022-01-05 22:05

Ah! I see. I implemented A without B, and implemented B without A before, and was frustrated that they didn’t work individually. Thank you!

CollyBlargle | 2022-01-06 04:22

:bust_in_silhouette: Reply From: ld2studio

Hi, my solution uses local coordinates instead of global coordinates of mouse cursor → method CanvasItem.get_local_mouse_position(); it is more consistent with the rotation of an object.
In addition, I use the event InputEventMouseMotion to update the rotation of the Area2D node, instead of the _process() function.

The line get_local_mouse_position().rotated(rotation) retrieves the position vector of the mouse pointer in the local space, which must be rotated by the rotation angle of Area2D node.

extends Area2D
enum { NONE, ROTATING}

var state = NONE
var mouse_on_me: bool = false
var initial_mouse_pos: Vector2
var initial_angle: float

func _input(event: InputEvent) -> void:
	if event is InputEventMouseButton:
		if event.button_index == BUTTON_RIGHT:
			if event.pressed: # press button
				if mouse_on_me:
					initial_angle = rotation
					initial_mouse_pos = get_local_mouse_position().rotated(rotation)
					state = ROTATING
			else: # release button
				state = NONE
				
				
	if event is InputEventMouseMotion:
		if state == ROTATING:
			var current_mouse_pos: Vector2 = get_local_mouse_position().rotated(rotation)
			var angle = initial_mouse_pos.angle_to(current_mouse_pos)
			rotation = angle + initial_angle

func _on_Area2D_mouse_entered() -> void:
	mouse_on_me = true

func _on_Area2D_mouse_exited() -> void:
	mouse_on_me = false