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()
    );
});