Can you use a PinJoint2D to connect two CharacterBody2Ds?

Godot Version

4.2.1.stable

Question

I’m trying to use a PinJoint2D to connect two CharacterBody2Ds, but it doesn’t seem like Godot allows that. I can connect a CharacterBody2D to a RigidBody2D, I can connect a RigidBody2D to a StaticBody2D, I can connect two RigidBody2Ds, but I cannot figure out how to connect two CharacterBody2Ds, even though it should completely work as far as I know? A PinJoint2D just wants two physics bodies and a CharacterBody2D IS A PHYSICS BODY.

What I’m actually trying to do is have two CharacterBody2Ds get effected by gravity, but when I hold left click, I want the left CharacterBody to freeze and lock in place, then I want the same to happen to the right CharacterBody when I hold right click. Then I want both CharacterBodies to be pinned together so when one CharacterBody is locked in place, the other will swing like a pendulum, and the player can freely swap between locking the right and left CharacterBodies. As far as I know, both nodes that lock and freeze in place need to be CharacterBodies, because RigidBodies are weird when trying to freeze them (but if there is a way to properly freeze and unfreeze RigidBodies that I’m just missing, then that’d fix all my problems I think?)

What is happening right now is I have the two CharacterBodies and on scene start up they both just start falling (this is intended). I can hold left click to freeze the left body, I can hold right click to freeze the right body (this is also intended). But they are not tethered/pinned together at all. They act as if the PinJoint2D does not exist at all, even though I CAN SEE THE PIN IN GAME WITH DEBUG MODE AND THE TWO NODES ARE SET PROPERLY. Does the order of “node A” and “node B” for the PinJoint2D matter? Would I need to actively change each “node A/B” depening on which CharacterBody2D is frozen?

This is what my scene tree looks like:
Godot_v4.2.1-stable_win64_ssBxUuPulC

My one PinJoint2D is connected to the “LHand” and “RHand” nodes. (LHand is node A)

The LHand script looks like this (the RHand script looks the same, but the input is looking for “grabR” instead of “grabL”.):

extends CharacterBody2D

var gravity = ProjectSettings.get_setting("physics/2d/default_gravity")

func _process(delta):
	velocity.y += gravity * delta
	
	if Input.is_action_pressed("grabL"):
		velocity = Vector2.ZERO
	
	move_and_slide()

This is what the “Main” script looks like (the script attached to the uppermost node):

extends Node2D

var gravity = ProjectSettings.get_setting("physics/2d/default_gravity")

@onready var LHand = $LHand
@onready var RHand = $RHand
@onready var PinJoint = $LHand/PinJoint2D

func _ready():
	get_tree().paused = true

func _process(delta):
	if Input.is_action_just_pressed("grabL") or Input.is_action_just_pressed("grabR"):
		get_tree().paused = false
	
	# left hand stuffs
	if Input.is_action_just_pressed("grabL"):
		PinJoint.reparent(LHand)
	
	if Input.is_action_pressed("grabL"):
		PinJoint.position = Vector2.ZERO
	
	# right hand stuffs
	if Input.is_action_just_pressed("grabR"):
		PinJoint.reparent(RHand)
		
	if Input.is_action_pressed("grabR"):
		PinJoint.position = Vector2.ZERO

I hope that’s enough info? Thank you in advance! :slight_smile:
(Is it usual to send the entire project file? Cause I don’t mind doing that if needed.)

I figured it out (kinda)!

I couldn’t pin two character bodies together but I did achieve my original goal of having two objects swing off eachother by having either object freeze at the press of a button.

What I did was, instead of using two character bodies, I used two rigid bodies. I originally thought this wasn’t possible because directly setting position was jank. At least I thought it was jank until I learned about the _integrate_forces func which is exactly made for what I wanted!!

So my scene layout still looks the same, just now they’re rigid bodies instead of character bodies. This is what the main block of code looks like now (i’m also changing the node_a and node_b properties on the pin joint, not sure if that’s needed though):

extends Node2D

var gravity = ProjectSettings.get_setting("physics/2d/default_gravity")

@onready var LHand = $LHand
@onready var RHand = $RHand
@onready var PinJoint = $LHand/PinJoint2D

func _process(delta):
	# left hand stuffs
	if Input.is_action_just_pressed("grabL"):
		PinJoint.reparent(LHand)
		PinJoint.node_a = LHand.get_path()
		PinJoint.node_b = RHand.get_path()
	
	if Input.is_action_pressed("grabL"):
		PinJoint.position = Vector2.ZERO
	
	# right hand stuffs
	if Input.is_action_just_pressed("grabR"):
		PinJoint.reparent(RHand)
		PinJoint.node_a = RHand.get_path()
		PinJoint.node_b = LHand.get_path()
		
	if Input.is_action_pressed("grabR"):
		PinJoint.position = Vector2.ZERO

And the scripts on the rigid bodies now look like this:

extends RigidBody2D

var c_pos

func _integrate_forces(state):
	if Input.is_action_just_pressed("grabL"):
		c_pos = position
	
	if Input.is_action_pressed("grabL"):
		position = c_pos
		linear_velocity = Vector2.ZERO

Not sure if I should label this as solved because my original question hasn’t been answered, but for now I’ll just say it’s solved! Thank you to anyone who tried to help (if there was anyone? lol).

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.