Ragdoll Physics
Create articulated character physics for realistic reactions:
// Create a simple ragdoll character
function createRagdoll(position) {
// Create body parts
const parts = {};
// Torso
parts.torso = BABYLON.MeshBuilder.CreateBox("torso", {
width: 1, height: 1.5, depth: 0.5
}, scene);
parts.torso.position = position.clone();
// Head
parts.head = BABYLON.MeshBuilder.CreateSphere("head", {
diameter: 0.7
}, scene);
parts.head.position = position.clone();
parts.head.position.y += 1;
// Upper arms
parts.leftUpperArm = BABYLON.MeshBuilder.CreateCylinder("leftUpperArm", {
height: 0.8, diameter: 0.25
}, scene);
parts.leftUpperArm.rotation.z = Math.PI / 2;
parts.leftUpperArm.position = position.clone();
parts.leftUpperArm.position.x -= 0.8;
parts.leftUpperArm.position.y += 0.4;
parts.rightUpperArm = BABYLON.MeshBuilder.CreateCylinder("rightUpperArm", {
height: 0.8, diameter: 0.25
}, scene);
parts.rightUpperArm.rotation.z = Math.PI / 2;
parts.rightUpperArm.position = position.clone();
parts.rightUpperArm.position.x += 0.8;
parts.rightUpperArm.position.y += 0.4;
// Lower arms
parts.leftLowerArm = BABYLON.MeshBuilder.CreateCylinder("leftLowerArm", {
height: 0.8, diameter: 0.2
}, scene);
parts.leftLowerArm.rotation.z = Math.PI / 2;
parts.leftLowerArm.position = position.clone();
parts.leftLowerArm.position.x -= 1.6;
parts.leftLowerArm.position.y += 0.4;
parts.rightLowerArm = BABYLON.MeshBuilder.CreateCylinder("rightLowerArm", {
height: 0.8, diameter: 0.2
}, scene);
parts.rightLowerArm.rotation.z = Math.PI / 2;
parts.rightLowerArm.position = position.clone();
parts.rightLowerArm.position.x += 1.6;
parts.rightLowerArm.position.y += 0.4;
// Upper legs
parts.leftUpperLeg = BABYLON.MeshBuilder.CreateCylinder("leftUpperLeg", {
height: 1, diameter: 0.3
}, scene);
parts.leftUpperLeg.position = position.clone();
parts.leftUpperLeg.position.x -= 0.3;
parts.leftUpperLeg.position.y -= 1;
parts.rightUpperLeg = BABYLON.MeshBuilder.CreateCylinder("rightUpperLeg", {
height: 1, diameter: 0.3
}, scene);
parts.rightUpperLeg.position = position.clone();
parts.rightUpperLeg.position.x += 0.3;
parts.rightUpperLeg.position.y -= 1;
// Lower legs
parts.leftLowerLeg = BABYLON.MeshBuilder.CreateCylinder("leftLowerLeg", {
height: 1, diameter: 0.25
}, scene);
parts.leftLowerLeg.position = position.clone();
parts.leftLowerLeg.position.x -= 0.3;
parts.leftLowerLeg.position.y -= 2;
parts.rightLowerLeg = BABYLON.MeshBuilder.CreateCylinder("rightLowerLeg", {
height: 1, diameter: 0.25
}, scene);
parts.rightLowerLeg.position = position.clone();
parts.rightLowerLeg.position.x += 0.3;
parts.rightLowerLeg.position.y -= 2;
// Add physics impostors to all parts
for (const [name, part] of Object.entries(parts)) {
part.physicsImpostor = new BABYLON.PhysicsImpostor(
part,
BABYLON.PhysicsImpostor.BoxImpostor, // Use box for better performance
{ mass: name === "torso" ? 3 : 1, friction: 0.5, restitution: 0.3 },
scene
);
}
// Create joints to connect the body parts
// Neck joint
const neckJoint = new BABYLON.PhysicsJoint(
BABYLON.PhysicsJoint.BallAndSocketJoint, {
mainPivot: new BABYLON.Vector3(0, 0.75, 0),
connectedPivot: new BABYLON.Vector3(0, -0.35, 0)
}
);
parts.torso.physicsImpostor.addJoint(parts.head.physicsImpostor, neckJoint);
// Shoulder joints
const leftShoulderJoint = new BABYLON.PhysicsJoint(
BABYLON.PhysicsJoint.BallAndSocketJoint, {
mainPivot: new BABYLON.Vector3(-0.5, 0.5, 0),
connectedPivot: new BABYLON.Vector3(0.4, 0, 0)
}
);
parts.torso.physicsImpostor.addJoint(parts.leftUpperArm.physicsImpostor, leftShoulderJoint);
const rightShoulderJoint = new BABYLON.PhysicsJoint(
BABYLON.PhysicsJoint.BallAndSocketJoint, {
mainPivot: new BABYLON.Vector3(0.5, 0.5, 0),
connectedPivot: new BABYLON.Vector3(-0.4, 0, 0)
}
);
parts.torso.physicsImpostor.addJoint(parts.rightUpperArm.physicsImpostor, rightShoulderJoint);
// Elbow joints
const leftElbowJoint = new BABYLON.PhysicsJoint(
BABYLON.PhysicsJoint.HingeJoint, {
mainPivot: new BABYLON.Vector3(-0.4, 0, 0),
connectedPivot: new BABYLON.Vector3(0.4, 0, 0),
mainAxis: new BABYLON.Vector3(0, 0, 1),
connectedAxis: new BABYLON.Vector3(0, 0, 1)
}
);
parts.leftUpperArm.physicsImpostor.addJoint(parts.leftLowerArm.physicsImpostor, leftElbowJoint);
const rightElbowJoint = new BABYLON.PhysicsJoint(
BABYLON.PhysicsJoint.HingeJoint, {
mainPivot: new BABYLON.Vector3(0.4, 0, 0),
connectedPivot: new BABYLON.Vector3(-0.4, 0, 0),
mainAxis: new BABYLON.Vector3(0, 0, 1),
connectedAxis: new BABYLON.Vector3(0, 0, 1)
}
);
parts.rightUpperArm.physicsImpostor.addJoint(parts.rightLowerArm.physicsImpostor, rightElbowJoint);
// Hip joints
const leftHipJoint = new BABYLON.PhysicsJoint(
BABYLON.PhysicsJoint.BallAndSocketJoint, {
mainPivot: new BABYLON.Vector3(-0.3, -0.75, 0),
connectedPivot: new BABYLON.Vector3(0, 0.5, 0)
}
);
parts.torso.physicsImpostor.addJoint(parts.leftUpperLeg.physicsImpostor, leftHipJoint);
const rightHipJoint = new BABYLON.PhysicsJoint(
BABYLON.PhysicsJoint.BallAndSocketJoint, {
mainPivot: new BABYLON.Vector3(0.3, -0.75, 0),
connectedPivot: new BABYLON.Vector3(0, 0.5, 0)
}
);
parts.torso.physicsImpostor.addJoint(parts.rightUpperLeg.physicsImpostor, rightHipJoint);
// Knee joints
const leftKneeJoint = new BABYLON.PhysicsJoint(
BABYLON.PhysicsJoint.HingeJoint, {
mainPivot: new BABYLON.Vector3(0, -0.5, 0),
connectedPivot: new BABYLON.Vector3(0, 0.5, 0),
mainAxis: new BABYLON.Vector3(1, 0, 0),
connectedAxis: new BABYLON.Vector3(1, 0, 0)
}
);
parts.leftUpperLeg.physicsImpostor.addJoint(parts.leftLowerLeg.physicsImpostor, leftKneeJoint);
const rightKneeJoint = new BABYLON.PhysicsJoint(
BABYLON.PhysicsJoint.HingeJoint, {
mainPivot: new BABYLON.Vector3(0, -0.5, 0),
connectedPivot: new BABYLON.Vector3(0, 0.5, 0),
mainAxis: new BABYLON.Vector3(1, 0, 0),
connectedAxis: new BABYLON.Vector3(1, 0, 0)
}
);
parts.rightUpperLeg.physicsImpostor.addJoint(parts.rightLowerLeg.physicsImpostor, rightKneeJoint);
return parts;
}
// Create a ragdoll
const ragdoll = createRagdoll(new BABYLON.Vector3(0, 10, 0));
// Add button to apply explosion force
const explodeButton = document.createElement("button");
explodeButton.textContent = "Apply Force";
explodeButton.style.position = "absolute";
explodeButton.style.top = "10px";
explodeButton.style.left = "10px";
document.body.appendChild(explodeButton);
explodeButton.addEventListener("click", () => {
// Apply random impulse to torso
ragdoll.torso.physicsImpostor.applyImpulse(
new BABYLON.Vector3(
(Math.random() - 0.5) * 20,
Math.random() * 10,
(Math.random() - 0.5) * 20
),
ragdoll.torso.getAbsolutePosition()
);
});