Ideas on how to lock an object's movement and position to a circle area but allow drag and drop within that space?

Godot Version

` Godot 4.4

Question

Using drag and drop, want to make a appendage go around a body like how the chainchomps are in SuperMario. I am sort of trying to make functionality like a top down perspective and you can drag the chain chomp head around but it is stuck to the area around the post.

I have tried googling and found some stuff about clamping, but that locks me to the 2 axis and I can’t get it to be a radial distance. I have also tried setting a radial point as the center of the object and then converting that point to a length and the updated point to a length and checking if the distance between those points was greater than a max length but that also locked me to x and y axis. This is what I have so far, only logic about dragging and dropping:

func _on_input_event(viewport: Node, event: InputEvent, shape_idx: int) → void:
if event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_LEFT:
if event.is_pressed():
is_dragging = true
radial_point = global_position
mouse_offset = get_global_mouse_position() - global_position
elif event.button_index == MOUSE_BUTTON_LEFT and !event.pressed:
is_dragging = false
else:
is_dragging = false

func _physics_process(delta: float) → void:
velocity.y = velocity.y + gravity

if is_dragging:
	var new_posish = get_global_mouse_position() - mouse_offset
	velocity = (new_posish - global_position) / delta

move_and_slide()

Thank you for checking this out!

The usual trick for something like this is normalizing the vector. If you haven’t run into the term, what it means is, take a vector and scale it so it’s length is 1.0.

So you can do something like:

const ORBIT_RADIUS = 20.0

var origin = global_position
var vector = get_mouse_global_position() - origin
var orbit_pos: Vector2

if vector.length() < 0.01: # Zero vector, use a placeholder...
    orbit_pos = Vector2.UP * ORBIT_RADIUS
else:
    orbit_pos = vector.normalized() * ORBIT_RADIUS

That gets a vector from your position to the mouse, normalizes it (so it’s length 1.0) and scales that vector (and thus it’s length) to ORBIT_RADIUS.

You can play with that as well; say you wanted a minimum and maximum distance but wanted the fireball right on the mouse if it was within a ring:

const ORBIT_INNER_RADIUS = 15.0
const ORBIT_OUTER_RADIUS = 25.0

var origin = global_position
var vector = get_mouse_global_position() - origin
var veclen = vector.length()
var orbit_pos: Vector2

if veclen < ORBIT_INNER_RADIUS: # Too close!
    if veclen < 0.01: vector = Vector2.UP
    orbit_pos = vector.normalized() * ORBIT_INNER_RADIUS
elif veclen > ORBIT_OUTER_RADIUS: # Too far!
    orbit_pos = vector.normalized() * ORBIT_OUTER_RADIUS
else: # Just right!
    orbit_pos = vector
1 Like

make it a child of a node and rotate the node increasing its distance from the parent node.

1 Like

Or move the parent node when you drag it.

1 Like

Thank you very much. I am looking forward to implementing your solution and messing around with it.

I have come across the normalize function, but my pea sized brain wouldn’t even begin to wrap my head around the thought process necessary to come to the conclusion you provided me with.

Must sign off for while, but you are appreciated!

Thank you for responding!