Active Ragdoll breaks when physics tick is below 60

Godot Version

4.7

Question

The way the active ragdoll works is that force is applied whenever the animation part of the active ragdoll’s skeleton is updated (basically on every frame) and the only time the physics process interacts with the skeleton updated function is to take the delta from it.

Whenever I try to set the tick rate to 30 on 60 fps this ends up happening (even if max fps is set to 30??)

This also happens on a 60 tick rate with 15 fps (30 works fine)

This concerns me a lot due to a possibly of higher fps computers not being able to properly run the game as well as being forced to only use 60+ tick rate

I’ve tried to await for when physics process is done but it didn’t work and I’ve also tried to copy and paste the code onto the physics process but it didn’t work either. They both of the same effect of the active ragdoll randomly flopping around.

Not sure if the code is any use but here it is just in case.

func _physics_process(delta: float) -> void:
	
	current_delta = delta
	animated_skel.position = rigidskele.position
	animated_skel.global_rotation = rigidskele.global_rotation

	RDNode.global_position = physicsBones[0].global_position
	
	if Ragdoll != true and CD.time_left == 0:

		if abs(physicsBones[0].linear_velocity) >= Vector3(5,5,5) or (rigidskele.global_position - physicsBones[0].global_position).length() >= 1.3:
			
				ragdoll_mode(true, 5.0)
	
func _on_skeleton_3d_skeleton_updated() -> void:
	
	if not Ragdoll and Health > 0:
		
		for b:PhysicalBone3D in physicsBones:

			var target_transform: Transform3D = animated_skel.global_transform * animated_skel.get_bone_global_pose(b.get_bone_id())
			var current_transform: Transform3D = physical_bones.global_transform * physical_skel.get_bone_global_pose(b.get_bone_id())
			var rotation_difference: Basis = (target_transform.basis * current_transform.basis.inverse())
			var torque = hookes_law(rotation_difference.get_euler(), b.angular_velocity, angular_spring_stiffness, angular_spring_damping)
			
			if b.name.contains(pb + "toe") or b.name.contains(pb + "foot"):
				b.angular_velocity += (torque * current_delta) * 1.5 #fix for toes folding under foot and foot bending weirdly
			else:
				b.angular_velocity += torque.clampf(-tweenmaxangvelocity, tweenmaxangvelocity) * current_delta
			
		
			
			for thing in partslist:
				if b.name.contains(pb + thing) or b.name == pb + "spine":

					var position_difference : Vector3 = target_transform.origin - current_transform.origin
					var force : Vector3 = hookes_law(position_difference, b.linear_velocity, linear_spring_stiffness, linear_spring_damping)
					b.linear_velocity += force.clampf(-tweenmaxlinvelocity, tweenmaxlinvelocity) * current_delta

Thank you in advance!!

Ok so update on my progress so far. I’ve tried using callback mode process and setting it to physics but it still seems to be out of sync and for some reason makes the active ragdoll ever so slightly sluggish.. My guess to fix this is to find a way to limit the animation’s fps to the physics tick rate?? I really hope this isn’t an engine issue..

So I’ve set the callback mode to manual and set it to update when the physics updates as well. Nothing seemed to changed and it turns out that the skeleton update and physics process function were in sync. The skeleton update function also uses the physics processes delta so there shouldn’t be an issue with too much force BUT when I changed the max linear/angular velocity the spazzing out issue was fixed at the cost of the ragdoll being too floppy. It seems to be an issue with the damping and stiffness but then again the forces shouldn’t be affected by the speed/tickrate of the game in the first place.

Ok new update as I try to get figure it out I get more and more confused. This time I changed the fps to 15 (where I remember issues happening) the reason why it was so shaky was because of the max physics step per frame being too high and had nothing to do with the active ragdoll itself. it plays in slow motion but the active ragdolls are flat out exploding. I genuinely have no idea why It won’t work above and ESPECIALLY below 60 tick speed (tried it on 300 ticks and the active ragdoll seems very stiff and slow). I’m honestly just had a loss for words here I feel like I’ve tried everything but I’m even more confused than I was before.

Update so I asked someone about it and they said that I needed to apply the force in physics process and only use the skeleton update function to get the target poses. I now have it set and it runs fine but it still won’t function properly under 60 ticks. I feel like it has something to do with the delta but I can’t imagine how I could even fix it. I’ve tried to replace the delta with 0.01666666666667 (60 tick delta) and when I ran it on 30 ticks it was still bad but less extreme..

Here’s the script with the bloat removed in case I did something wrong.

func _physics_process(delta: float) -> void:
	
	if not Ragdoll and Health > 0:
		await physical_skel.skeleton_updated
		for b:PhysicalBone3D in physicsBones:
			var ID = physicsBones.find(b)
			rotation_difference = (target_transform[ID].basis * current_transform[ID].basis.inverse())
			torque = hookes_law(rotation_difference.get_euler(), b.angular_velocity, angular_spring_stiffness, angular_spring_damping)
			
			if b.name.contains(pb + "toe") or b.name.contains(pb + "foot"):
				#b.angular_velocity += (torque * current_delta) * 1.5 #fix for toes folding under foot and foot bending weirdly
				b.angular_velocity += (torque * delta) * 1.5
			else:
				b.angular_velocity += (torque.clampf(-tweenmaxangvelocity, tweenmaxangvelocity) * delta)
			
		
			
			for thing in partslist:
				if b.name.contains(pb + thing) or b.name == pb + "spine":

					var force : Vector3 = hookes_law(target_transform[ID].origin - current_transform[ID].origin, b.linear_velocity, linear_spring_stiffness, linear_spring_damping)
					b.linear_velocity += force.clampf(-tweenmaxlinvelocity, tweenmaxlinvelocity) * delta	
					
	
func _on_skeleton_3d_skeleton_updated() -> void:
	
	if not Ragdoll and Health > 0:
		
		for b:PhysicalBone3D in physicsBones:
			
			target_transform.insert(physicsBones.find(b), animated_skel.global_transform * animated_skel.get_bone_global_pose(b.get_bone_id())) 
			current_transform.insert(physicsBones.find(b), physical_bones.global_transform * physical_skel.get_bone_global_pose(b.get_bone_id()))

I couldn’t tell you what the exact problem is as I do not have enough experience using the Skeleton3D class. However, PhysicalBone3D’s documentation clearly states:

linear_velocity

The body’s linear velocity in units per second. Can be used sporadically, but don’t set this every frame, because physics may run in another thread and runs at a different granularity. Use _integrate_forces() as your process loop for precise control of the body state.

As is stated – both here and in other parts of Godot’s documentation – you should make use of _integrate_forces() when you want to directly manipulate the state of a physics object (e.g. setting position, rotation, velocity etc.).

Whether or not following this will fix your problem, I don’t know. You will have to experiment for yourself.


Let us know of any further updates.

Relevant links:

This seems super promising. I’m a bit confused on how to set this up but I’m sure I’ll figure it out. Thanks and I’m REALLY hoping this is the solution!

Ok update I couldn’t find a good way to use the integrate forces function on every physics bone but reading some of the documentations I might be able to recreate it by just contacting the physics server directly? I also changed the delta to what the delta would have been like at 60 ticks and it worked for about half a second before going weird again. Setting the skeleton’s callback mode to physics gives me a super jittery animation but it’s SO close to actually working!!

Here’s what it looks like at 45 physics ticks. Compared to the player that doesn’t have the new active ragdoll script this is a major improvement. Although this is the tick rate when there starts to be a noticeable jitter, everything above 45 works perfectly well. I’m perfectly fine settling with this so thanks a ton for the help Sweatix!

“Solution” for the future people

I directly contacted the physics server, changing the linear and angular velocity there, then I set the delta needed in the active ragdoll forces to 0.01666666666667 (basically 60 ticks), lastly I set the skeleton’s (specifically the ragdoll one) callback mode to physics and got this result. Keep in mind that setting the skeleton’s callback mode to anything but idle will cause slightly more imperfections in the active ragdoll’s movement so you may need to apply a stronger force (the goblin’s hands doesn’t make contact on the clapping part of the animation anymore).