UNPKG

cannon-es-control

Version:

A lightweight 3D physics engine written in JavaScript with control system tools

205 lines (174 loc) 6.68 kB
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <title>cannon.js - RigidVehicle</title> <link rel="stylesheet" href="css/style.css" type="text/css" /> <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0" /> </head> <body> <script type="module"> import * as CANNON from '../dist/cannon-es-control.js' import { Demo } from './js/Demo.js' const demo = new Demo() demo.addScene('Car', () => { const world = setupWorld(demo) // Build the car chassis const chassisShape = new CANNON.Box(new CANNON.Vec3(5, 0.5, 2)) const chassisBody = new CANNON.Body({ mass: 1 }) const centerOfMassAdjust = new CANNON.Vec3(0, -1, 0) chassisBody.addShape(chassisShape, centerOfMassAdjust) demo.addVisual(chassisBody) // Create the vehicle const vehicle = new CANNON.RigidVehicle({ chassisBody, }) const mass = 1 const axisWidth = 7 const wheelShape = new CANNON.Sphere(1.5) const wheelMaterial = new CANNON.Material('wheel') const down = new CANNON.Vec3(0, -1, 0) const wheelBody1 = new CANNON.Body({ mass, material: wheelMaterial }) wheelBody1.addShape(wheelShape) vehicle.addWheel({ body: wheelBody1, position: new CANNON.Vec3(-5, 0, axisWidth / 2).vadd(centerOfMassAdjust), axis: new CANNON.Vec3(0, 0, 1), direction: down, }) const wheelBody2 = new CANNON.Body({ mass, material: wheelMaterial }) wheelBody2.addShape(wheelShape) vehicle.addWheel({ body: wheelBody2, position: new CANNON.Vec3(-5, 0, -axisWidth / 2).vadd(centerOfMassAdjust), axis: new CANNON.Vec3(0, 0, -1), direction: down, }) const wheelBody3 = new CANNON.Body({ mass, material: wheelMaterial }) wheelBody3.addShape(wheelShape) vehicle.addWheel({ body: wheelBody3, position: new CANNON.Vec3(5, 0, axisWidth / 2).vadd(centerOfMassAdjust), axis: new CANNON.Vec3(0, 0, 1), direction: down, }) const wheelBody4 = new CANNON.Body({ mass, material: wheelMaterial }) wheelBody4.addShape(wheelShape) vehicle.addWheel({ body: wheelBody4, position: new CANNON.Vec3(5, 0, -axisWidth / 2).vadd(centerOfMassAdjust), axis: new CANNON.Vec3(0, 0, -1), direction: down, }) vehicle.wheelBodies.forEach((wheelBody) => { // Some damping to not spin wheels too fast wheelBody.angularDamping = 0.4 // Add visuals demo.addVisual(wheelBody) }) vehicle.addToWorld(world) // Add the ground const sizeX = 64 const sizeZ = sizeX const matrix = [] for (let i = 0; i < sizeX; i++) { matrix.push([]) for (let j = 0; j < sizeZ; j++) { if (i === 0 || i === sizeX - 1 || j === 0 || j === sizeZ - 1) { const height = 6 matrix[i].push(height) continue } const height = Math.sin((i / sizeX) * Math.PI * 7) * Math.sin((j / sizeZ) * Math.PI * 7) * 6 + 6 matrix[i].push(height) } } const groundMaterial = new CANNON.Material('ground') const heightfieldShape = new CANNON.Heightfield(matrix, { elementSize: 300 / sizeX, }) const heightfieldBody = new CANNON.Body({ mass: 0, material: groundMaterial }) heightfieldBody.addShape(heightfieldShape) heightfieldBody.position.set( (-(sizeX - 1) * heightfieldShape.elementSize) / 2, -15, ((sizeZ - 1) * heightfieldShape.elementSize) / 2 ) heightfieldBody.quaternion.setFromEuler(-Math.PI / 2, 0, 0) world.addBody(heightfieldBody) demo.addVisual(heightfieldBody) // Define interactions between wheels and ground const wheel_ground = new CANNON.ContactMaterial(wheelMaterial, groundMaterial, { friction: 0.3, restitution: 0, contactEquationStiffness: 1000, }) world.addContactMaterial(wheel_ground) // Keybindings // Add force on keydown document.addEventListener('keydown', (event) => { const maxSteerVal = Math.PI / 8 const maxSpeed = 10 const maxForce = 100 switch (event.key) { case 'w': case 'ArrowUp': vehicle.setWheelForce(maxForce, 2) vehicle.setWheelForce(-maxForce, 3) break case 's': case 'ArrowDown': vehicle.setWheelForce(-maxForce / 2, 2) vehicle.setWheelForce(maxForce / 2, 3) break case 'a': case 'ArrowLeft': vehicle.setSteeringValue(maxSteerVal, 0) vehicle.setSteeringValue(maxSteerVal, 1) break case 'd': case 'ArrowRight': vehicle.setSteeringValue(-maxSteerVal, 0) vehicle.setSteeringValue(-maxSteerVal, 1) break } }) // Reset force on keyup document.addEventListener('keyup', (event) => { switch (event.key) { case 'w': case 'ArrowUp': vehicle.setWheelForce(0, 2) vehicle.setWheelForce(0, 3) break case 's': case 'ArrowDown': vehicle.setWheelForce(0, 2) vehicle.setWheelForce(0, 3) break case 'a': case 'ArrowLeft': vehicle.setSteeringValue(0, 0) vehicle.setSteeringValue(0, 1) break case 'd': case 'ArrowRight': vehicle.setSteeringValue(0, 0) vehicle.setSteeringValue(0, 1) break } }) }) demo.start() function setupWorld(demo) { const world = demo.getWorld() world.gravity.set(0, -30, 0) // Sweep and prune broadphase world.broadphase = new CANNON.SAPBroadphase(world) // Adjust the global friction world.defaultContactMaterial.friction = 0.2 return world } </script> </body> </html>