#

API Docs for: 0.6.1
Show: Inherited Protected Private Deprecated

# File: src/objects/RigidVehicle.js

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