UNPKG

cannon

Version:

A lightweight 3D physics engine written in JavaScript.

221 lines (189 loc) 6.18 kB
var Body = require('./Body'); var Sphere = require('../shapes/Sphere'); var Box = require('../shapes/Box'); var Vec3 = require('../math/Vec3'); var HingeConstraint = require('../constraints/HingeConstraint'); module.exports = RigidVehicle; /** * Simple vehicle helper class with spherical rigid body wheels. * @class RigidVehicle * @constructor * @param {Body} [options.chassisBody] */ function RigidVehicle(options){ this.wheelBodies = []; /** * @property coordinateSystem * @type {Vec3} */ this.coordinateSystem = typeof(options.coordinateSystem)==='undefined' ? new Vec3(1, 2, 3) : options.coordinateSystem.clone(); /** * @property {Body} chassisBody */ this.chassisBody = options.chassisBody; if(!this.chassisBody){ // No chassis body given. Create it! var chassisShape = new Box(new Vec3(5, 2, 0.5)); this.chassisBody = new Body(1, chassisShape); } /** * @property constraints * @type {Array} */ this.constraints = []; this.wheelAxes = []; this.wheelForces = []; } /** * Add a wheel * @method addWheel * @param {object} options * @param {boolean} [options.isFrontWheel] * @param {Vec3} [options.position] Position of the wheel, locally in the chassis body. * @param {Vec3} [options.direction] Slide direction of the wheel along the suspension. * @param {Vec3} [options.axis] Axis of rotation of the wheel, locally defined in the chassis. * @param {Body} [options.body] The wheel body. */ RigidVehicle.prototype.addWheel = function(options){ options = options || {}; var wheelBody = options.body; if(!wheelBody){ wheelBody = new Body(1, new Sphere(1.2)); } this.wheelBodies.push(wheelBody); this.wheelForces.push(0); // Position constrain wheels var zero = new Vec3(); var position = typeof(options.position) !== 'undefined' ? options.position.clone() : new Vec3(); // Set position locally to the chassis var worldPosition = new Vec3(); this.chassisBody.pointToWorldFrame(position, worldPosition); wheelBody.position.set(worldPosition.x, worldPosition.y, worldPosition.z); // Constrain wheel var axis = typeof(options.axis) !== 'undefined' ? options.axis.clone() : new Vec3(0, 1, 0); this.wheelAxes.push(axis); var hingeConstraint = new HingeConstraint(this.chassisBody, wheelBody, { pivotA: position, axisA: axis, pivotB: Vec3.ZERO, axisB: axis, collideConnected: false }); this.constraints.push(hingeConstraint); return this.wheelBodies.length - 1; }; /** * Set the steering value of a wheel. * @method setSteeringValue * @param {number} value * @param {integer} wheelIndex * @todo check coordinateSystem */ RigidVehicle.prototype.setSteeringValue = function(value, wheelIndex){ // Set angle of the hinge axis var axis = this.wheelAxes[wheelIndex]; var c = Math.cos(value), s = Math.sin(value), x = axis.x, y = axis.y; this.constraints[wheelIndex].axisA.set( c*x -s*y, s*x +c*y, 0 ); }; /** * Set the target rotational speed of the hinge constraint. * @method setMotorSpeed * @param {number} value * @param {integer} wheelIndex */ RigidVehicle.prototype.setMotorSpeed = function(value, wheelIndex){ var hingeConstraint = this.constraints[wheelIndex]; hingeConstraint.enableMotor(); hingeConstraint.motorTargetVelocity = value; }; /** * Set the target rotational speed of the hinge constraint. * @method disableMotor * @param {number} value * @param {integer} wheelIndex */ RigidVehicle.prototype.disableMotor = function(wheelIndex){ var hingeConstraint = this.constraints[wheelIndex]; hingeConstraint.disableMotor(); }; var torque = new Vec3(); /** * Set the wheel force to apply on one of the wheels each time step * @method setWheelForce * @param {number} value * @param {integer} wheelIndex */ RigidVehicle.prototype.setWheelForce = function(value, wheelIndex){ this.wheelForces[wheelIndex] = value; }; /** * Apply a torque on one of the wheels. * @method applyWheelForce * @param {number} value * @param {integer} wheelIndex */ RigidVehicle.prototype.applyWheelForce = function(value, wheelIndex){ var axis = this.wheelAxes[wheelIndex]; var wheelBody = this.wheelBodies[wheelIndex]; var bodyTorque = wheelBody.torque; axis.scale(value, torque); wheelBody.vectorToWorldFrame(torque, torque); bodyTorque.vadd(torque, bodyTorque); }; /** * Add the vehicle including its constraints to the world. * @method addToWorld * @param {World} world */ RigidVehicle.prototype.addToWorld = function(world){ var constraints = this.constraints; var bodies = this.wheelBodies.concat([this.chassisBody]); for (var i = 0; i < bodies.length; i++) { world.add(bodies[i]); } for (var i = 0; i < constraints.length; i++) { world.addConstraint(constraints[i]); } world.addEventListener('preStep', this._update.bind(this)); }; RigidVehicle.prototype._update = function(){ var wheelForces = this.wheelForces; for (var i = 0; i < wheelForces.length; i++) { this.applyWheelForce(wheelForces[i], i); } }; /** * Remove the vehicle including its constraints from the world. * @method removeFromWorld * @param {World} world */ RigidVehicle.prototype.removeFromWorld = function(world){ var constraints = this.constraints; var bodies = this.wheelBodies.concat([this.chassisBody]); for (var i = 0; i < bodies.length; i++) { world.remove(bodies[i]); } for (var i = 0; i < constraints.length; i++) { world.removeConstraint(constraints[i]); } }; var worldAxis = new Vec3(); /** * Get current rotational velocity of a wheel * @method getWheelSpeed * @param {integer} wheelIndex */ RigidVehicle.prototype.getWheelSpeed = function(wheelIndex){ var axis = this.wheelAxes[wheelIndex]; var wheelBody = this.wheelBodies[wheelIndex]; var w = wheelBody.angularVelocity; this.chassisBody.vectorToWorldFrame(axis, worldAxis); return w.dot(worldAxis); };