• 2D
  • Can't figure out how to reposition PinJoint2D to change the center of gravity on a picked object

I'm losing my mind. I've been trying to figure this out for two weeks now, and I'm not making any progress at all.

I have a system where I can pick up an object via a dynamic handle connected to a parent object with a pin joint.

You can click inside the parent object to establish the point of click, a signal gets emitted to the world scene for the sake of delegation, and the child handle can be dragged around the screen. The parent's physics remains intact. I use a little bit of trig to make sure where you click on the parent object is where you pick it up.

I want that click to update the position of my pin joint in the child to change the center of gravity of the selection. I've tried adding a handle scene, setting the pin location, then adding an instance as a child. I've tried to integrate forces on the handle to update the position, and nothing happens.

The pin joint is always at the center of the scene. I know the position can be changed. I can set the position to something other than the center in the editor, but I can't make it budge dynamically.

The code:

The parent senses the click and delegates the handle to the world scene.

extends RigidBody2D

signal clicked
signal dropped

var held = false
var local_offset = Vector2.ZERO
var rotated_offset = Vector2.ZERO

func _input_event(viewport, event, shape_idx):
	if event.is_action_pressed("click"):
		local_offset = get_local_mouse_position()
		rotated_offset = rotate(local_offset)
		emit_signal("clicked", $Pin)

func _input(event):
	if event.is_action_released("click"):
		emit_signal("dropped", $Pin)

func rotate(coords):
	var x2 = cos(rotation)*coords.x - sin(rotation)*coords.y
	var y2 = sin(rotation)*coords.x + cos(rotation)*coords.y
	return Vector2(x2,y2)

Delegates to the world scene which communicates back to the "handle" child.

extends Node2D

var held_object = null

func _ready():
	for node in get_tree().get_nodes_in_group("pickable"):
		node.connect("clicked", self, "_on_pickable_clicked")
		node.connect("dropped", self, "_on_pickable_released")

func _on_pickable_clicked(object):
	if !held_object:
		held_object = object
		held_object.pickup()
		
func _on_pickable_released(object):
	if held_object:
		held_object.drop(Input.get_last_mouse_speed())
		held_object = null

My current child code. Trying to update the position of itself and hoping the PinJoint2D position will follow. _integrate_forces(state) isn't making it move.

extends RigidBody2D

var held = false
onready var parent = get_parent()

var reset_state = false
var location = Vector2.ZERO

func _physics_process(delta):
	if held:
		global_transform.origin = compute_offset_vector()
		
func _integrate_forces(state):
	if reset_state:
		var xform = state.get_transform()
		xform.origin = parent.local_offset
		state.set_transform(xform)
		reset_state = false
		

func pickup():
	if held:
		return
	mode = RigidBody2D.MODE_STATIC
	held = true
	reset_state = true


func drop(impulse=Vector2.ZERO):
	if held:
		mode = RigidBody2D.MODE_RIGID
		apply_central_impulse(impulse)
		held = false
		location = Vector2.ZERO
		reset_state = true
		
func compute_offset_vector():
	return Vector2(get_global_mouse_position().x - parent.rotated_offset.x, get_global_mouse_position().y - parent.rotated_offset.y)

This code drags the parent around correctly (as the gif above indicates). I'm happy with that. I want the to move the center of gravity, but I'm so incredibly lost. I would love any insight anyone could provide.

I'll give the collision shape workaround a shot. Right now, I can't even instantiate my scene and change the position of my center of mass without manually setting it up that way in the editor before runtime. Thanks for the link. I appreciate it.