Advanced Physics Features
Babylon.js 7 includes support for advanced physics simulations:
Create physics-based vehicles with wheel constraints:
// This example uses Ammo.js which supports advanced vehicle physics
// Note: Vehicle physics implementation depends on the physics engine used
// Create a vehicle chassis
const chassisWidth = 2;
const chassisHeight = 0.6;
const chassisLength = 4;
const chassis = BABYLON.MeshBuilder.CreateBox("chassis", {
width: chassisWidth,
height: chassisHeight,
depth: chassisLength
}, scene);
chassis.position.y = 4;
// Create wheels
const wheelRadius = 0.4;
const wheelWidth = 0.3;
const wheelPositions = [
new BABYLON.Vector3(chassisWidth/2, -chassisHeight/2, chassisLength/2 - wheelRadius), // front right
new BABYLON.Vector3(-chassisWidth/2, -chassisHeight/2, chassisLength/2 - wheelRadius), // front left
new BABYLON.Vector3(chassisWidth/2, -chassisHeight/2, -chassisLength/2 + wheelRadius), // rear right
new BABYLON.Vector3(-chassisWidth/2, -chassisHeight/2, -chassisLength/2 + wheelRadius) // rear left
];
const wheels = [];
for (let i = 0; i < 4; i++) {
const wheel = BABYLON.MeshBuilder.CreateCylinder(`wheel${i}`, {
diameter: wheelRadius * 2,
height: wheelWidth,
tessellation: 24
}, scene);
wheel.rotation.z = Math.PI / 2; // Rotate to correct orientation
wheel.position = chassis.position.add(wheelPositions[i]);
wheels.push(wheel);
}
// Add physics
chassis.physicsImpostor = new BABYLON.PhysicsImpostor(
chassis,
BABYLON.PhysicsImpostor.BoxImpostor,
{ mass: 800, friction: 0.5, restitution: 0.2 },
scene
);
// Configure vehicle physics (Ammo.js specific)
// Note: Implementation details vary by physics engine
if (scene.getPhysicsEngine().getPhysicsPluginName() === "AmmoJSPlugin") {
const vehicle = new BABYLON.AmmoJSPlugin.Vehicle(chassis, scene);
// Add wheels to vehicle
for (let i = 0; i < 4; i++) {
const isFront = i < 2;
vehicle.addWheel(
wheels[i],
wheelPositions[i],
new BABYLON.Vector3(0, -1, 0), // Down direction
new BABYLON.Vector3(0, 0, 1), // Forward direction
0.6, // Suspension rest length
wheelRadius,
isFront // Steering wheel?
);
}
// Configure vehicle properties
vehicle.setSteeringValue(0.0); // Initial steering
vehicle.applyEngineForce(0.0); // Initial engine force
vehicle.setBrake(0.0); // Initial brake force
// Vehicle control with keyboard
scene.onKeyboardObservable.add((kbInfo) => {
const key = kbInfo.event.key;
const isDown = kbInfo.type === BABYLON.KeyboardEventTypes.KEYDOWN;
switch (key) {
case "w":
vehicle.applyEngineForce(isDown ? 1000 : 0);
break;
case "s":
vehicle.applyEngineForce(isDown ? -500 : 0);
break;
case "a":
vehicle.setSteeringValue(isDown ? 0.3 : 0);
break;
case "d":
vehicle.setSteeringValue(isDown ? -0.3 : 0);
break;
case " ":
vehicle.setBrake(isDown ? 50 : 0);
break;
}
});
}
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()
);
});