How can I animate a physics-enabled Skeleton2D?

Godot Version

4.5 unstable, with PRs: 1, 2, but that shouldn’t be relevant.

Question

Though I’m a beginner to Godot, I’ve jumped right in and decided to mess with the experimental PhysicalBone2D nodes. While I have found plain ragdoll mode entertaining, I would like a way to animate it, while the physics are active.

The three relevant options I am currently aware of are:

  • Full ragdoll. No predetermined artistic control.
  • Entirely non-physical. No ragdoll physics.
  • Mixed. Some parts ragdoll, others not.

None of these are what I want. I want to have a physics-enabled bone attract toward a specific position, sort of like the muscles are moving it there. And I want to be able to have this follow a whole predetermined (or algorithmical, if I need to) animation.

Is this possible, with the current state of this? Or is it not yet there?

Thank you!

I’ve not tested it but PhysicalBone2D extends RigidBody2D so you should be able to “control” it by applying forces or impulses or by overriding the RigidBody2D._integrate_forces() function and controlling the state directly.

Here’s an example that show how to control a platformer character by overriding _integrate_forces() godot-demo-projects/2d/physics_platformer/player/player.gd at master · godotengine/godot-demo-projects · GitHub

1 Like

Thank you!

Trying to get this solution to work, though, I can’t seem to get it working quite right..

muscular_physical_bone_2d.gd

extends PhysicalBone2D

@export var force_position: Vector2
@export var target_position: Vector2
@export_range(0, 1) var strength: float = 1.0
@export_range(0, 1) var tenseness: float = 0.5

func _integrate_forces(state: PhysicsDirectBodyState2D) -> void:
	var parent_transform_inverse = get_parent().global_transform.affine_inverse()
	var global_force_position: Vector2 = force_position * global_transform.affine_inverse()
	var velocity_at_force: Vector2 = state.get_velocity_at_local_position(force_position)

	var force: Vector2 = (target_position * parent_transform_inverse - global_force_position - velocity_at_force * tenseness) * strength

	state.apply_force(force, global_force_position - position)

    # To preserve Newton's third law of motion:
	get_parent().apply_force(-force, global_force_position - get_parent().position) 
  • force_position: the position the force is exerted, in the PhysicalBone2D’s local space.
  • target_position: the position to bring the force position to, but in the parent’s local space.
  • strength: a factor of how much this affects things.
  • tenseness: how much this accounts for already present motion, to minimize wobbling.

(Should be easy to animate something like this, using Godot’s built-in animation system.)

Configuring this, the skeleton just seems to go crazy! Do you have any idea what I might be doing wrong?

Minimal Reproducible Project (hosted on Proton Drive)

Edit: Added video of problem (from MRP):