Godot Version
4.5.1
Question
Hi. I’ve been having a lot of issues trying to get active/full ragdolls to work programmatically using the .Net version of Godot. I have been going round in circles for days using ChatGPT (a last resort) and there is no real documentation to speak of for this. So, I was wandering if anyone here would be able to help me.
I have a method which loads character models (complete with skeletons) as .glb files during loading screens and then sets them up via code. Firstly, they are scaled to the correct height (only the root node is scaled) and then each of the bones are parsed and a custom BoneReference class is created for each, which contains the bone index, name etc.
ScaleCharacterToHeight(_bodyNode, Entity.Identity.AbsoluteHeight);
AssignBoneReferences(Skeleton);
These are the relevant methods which are called:
private void AssignBoneReferences(Skeleton3D skeleton) { Dictionary<string, BoneReference> bones = CollectBones(skeleton); PhysicsSimulator = new PhysicalBoneSimulator3D() { Active = false }; skeleton.AddChild(PhysicsSimulator); foreach(KeyValuePair<string, BoneReference> pair in bones) { *// CreateBonePhysics is called for each relevant bone.* } }private void CreateBonePhysics(Skeleton3D skeleton, Enums.BodyPart bodyPart, BoneReference boneRef, float mass = 10f, float linearDamp = 0.1f, float angularDamp = 0.1f, float radius = 0.05f, float height = 1.0f) { if (boneRef.Index == -1) { GD.Print("ignoring bone: " + boneRef.Name); return; } if (PhysicalBones.ContainsKey(bodyPart)) { return; } Transform3D boneRestLocal = skeleton.GetBoneRest(boneRef.Index); Transform3D boneRestGlobal = skeleton.GlobalTransform \* boneRestLocal; *var* physicalBone = new PhysicalBone3D { Name = "Physical Bone " + boneRef.Name, Mass = mass, LinearDamp = linearDamp, AngularDamp = angularDamp, GlobalTransform = boneRestGlobal }; PhysicsSimulator.AddChild(physicalBone); *// physics collision box sizes are directly copied from hurtboxes for now* CollisionShape3D hurtboxCollision = (CollisionShape3D)Hurtboxes\[bodyPart\].GetNode("col\_" + bodyPart.ToString().ToLower()); Shape3D shape = null; if (hurtboxCollision.Shape is SphereShape3D) { SphereShape3D sphereShape = (SphereShape3D)hurtboxCollision.Shape; shape = new SphereShape3D() { Radius = sphereShape.Radius }; } else { CapsuleShape3D capShape = (CapsuleShape3D)hurtboxCollision.Shape; shape = new CapsuleShape3D() { Radius = capShape.Radius, Height = capShape.Height }; } var collisionShape = new CollisionShape3D { Shape = shape }; physicalBone.AddChild(collisionShape); PhysicalBones.Add(bodyPart, physicalBone); }
Lastly, here is the method which I am manually calling on keyboard input (y key press) while the game is running to test the ragdoll, which is currently only causing the animation to stop with no actual physics taking over:
public void StartRagdoll() { AnimTree.Active = false; AnimPlayer.Active = false; Skeleton.ModifierCallbackModeProcess = Skeleton3D.ModifierCallbackModeProcessEnum.Physics; Skeleton.ForceUpdateTransform(); Entity.Animator.SetActiveState(false); PhysicsSimulator.Active = true; PhysicsSimulator.PhysicalBonesStartSimulation(); Skeleton.SetPhysicsProcess(true); AnimPlayer.SetPhysicsProcess(true); DebugPhysicalBones(); }
And the debug method:
public void DebugPhysicalBones() { foreach (Node child in PhysicsSimulator.GetChildren()) { if (child is PhysicalBone3D pb) { int boneId = pb.GetBoneId(); GD.Print( $"PhysicalBone '{pb.Name}': BoneId = {boneId}, Valid = {boneId >= 0}" ); } } }
Each bone returns with “BoneId = -1, Valid = False” and the character simply freezes, it fall or react physically.
I have not set up the skeletons using the CreatePhysicalSkeleton button in the editor since this is not possible; I am setting all of my characters up programmatically. However, I have heard that this is no longer necessary and that Godot binds Physical bones to skeletal bones automatically now. Hopefully someone will confirm if this is true or not.
Does anyone know what the issue could be, or the location of any documentation?
Edit: sorry about the formatting, the forum editor is so frustratingly “helpful” that I had to just stop fighting it and leave the text it as it was before I had an aneurysm.