//vehicle script file
//see
http://xtrac.outerra.com/index.fcgi/wiki/vehicle for example and documentation
var chassis={};
//invoked only the first time the model is loaded, or upon reload
function init_chassis(){
var wheelparam = {
radius: 0.42,
width: 10,
suspension_max: 0.1,
suspension_min: -0.1,
suspension_stiffness: 20.0,
damping_compression: 0.5,
damping_relaxation: 0.2,
slip: 5,
roll_influence: 0.01,
rotation: -1
};
var wheelparam2 = {
radius: 0.64,
width: 100,
suspension_max: 0.1,
suspension_min: -0.3,
suspension_stiffness: 15.0,
damping_compression: 0.5,
damping_relaxation: 0.2,
slip: 5,
roll_influence: 0.01,
rotation: 1
};
this.add_wheel('AV_G', wheelparam);
this.add_wheel('AV_D', wheelparam);
this.add_wheel('AR_G', wheelparam2);
this.add_wheel('AR_D', wheelparam2);
this.load_sound("EngineStart.ogg"); //startup
this.load_sound("EngineIdle.ogg"); //idle
this.load_sound("EngineOff.ogg"); //off
this.load_sound("EngineLow.ogg"); //on
chassis.basepitch = [ 0.2, 0.6, 0.6, 0.4 ]; //base pitch for start, idle, throttle
this.add_sound_emitter("AR_G");
//engine properties -- modify these to change the engine behaviour
chassis.wheelRadius = 0.53;
chassis.torquePoints = [ { rpm: 0, torque: 180},
{ rpm: 1000, torque: 120},
{ rpm: 2000, torque: 80},
{ rpm: 3000, torque: 60},
{ rpm: 4000, torque: 20},
{ rpm: 5000, torque: 0},
{ rpm: 6000, torque: 0},
{ rpm: 7000, torque: 0},
{ rpm: 8000, torque: 0},
{ rpm: 9000, torque: 0 } ];
chassis.forwardGears = [ { ratio: 4.20, shiftUp: 8000, shiftDown: -1 },
{ ratio: 2.49, shiftUp: 8000, shiftDown: 4500 },
{ ratio: 1.66, shiftUp: 8000, shiftDown: 5000 },
{ ratio: 1.24, shiftUp: 8000, shiftDown: 6000 },
{ ratio: 1.00, shiftUp: -1, shiftDown: 6000 } ];
chassis.reverseGears = [ { ratio: 4.20, shiftUp: -1, shiftDown: -1 } ];
chassis.finalRatio = 1;
chassis.torqueMultiplier = 40;
chassis.maximumSpeed = -1; // speed in m/s. a value < 0 means there's no maximum speed
chassis.engineBrakeCoefficient = 0.2;
chassis.breakingForce = 50000.0;
chassis.pitchMultiplier = 1;
//end of engine properties
chassis.maxPowerTP = chassis.torquePoints[0];
chassis.maxRPM = 0;
var maxPw = 0;
for (var i = 1; i < chassis.torquePoints.length; ++i) {
var tp = chassis.torquePoints
;
if (tp.rpm * tp.torque > maxPw) {
chassis.maxPowerTP = tp;
}
if (tp.rpm > chassis.maxRPM) {
chassis.maxRPM = tp.rpm;
}
}
chassis.neutroGear = { ratio: 0.0, shiftUp: -1, shiftDown: -1, index: 0 };
var prev = null;
for (var i = 0; i < chassis.forwardGears.length; ++i) {
var gear = chassis.forwardGears;
if (prev)
prev.next = gear;
gear.prev = prev;
gear.index = i + 1;
prev = gear;
}
prev = null;
for (var i = 0; i < chassis.reverseGears.length; ++i) {
var gear = chassis.reverseGears;
if (prev)
prev.next = gear;
gear.prev = prev;
gear.index = -i - 1;
prev = gear;
}
chassis.torque = engineTorque;
return {mass:1500, com:{y:0, z:-0.82}, steering:10, steering_ecf:60, centering: 30.6, centering_ecf: 40};
}
//invoked for each new instance of the vehicle
function init_vehicle() {
this.set_fps_camera_pos({x:-0.33,y:-0.25,z:1.15});
this.snd = this.sound();
this.snd.set_ref_distance(0, 9.0);
this.started = false;
this.gear = chassis.neutroGear;
this.direction = 0;
}
//invoked when engine starts or stops
function engine(start) {
if (start) {
this.started = true;
this.sound = 0;
this.snd.play(0, 0, false, false);
}
}
function engineTorque(rpm) {
var min = 0;
var max = chassis.torquePoints.length - 1;
if (rpm > chassis.torquePoints[max].rpm || rpm < chassis.torquePoints[min].rpm)
return 0;
while (max - min > 1) {
var mid = Math.floor(min + (max - min) / 2);
var tp = chassis.torquePoints[mid];
if (tp.rpm == rpm) {
return tp.torque;
} else if (tp.rpm > rpm) {
max = mid;
} else {
min = mid;
}
}
var minTp = chassis.torquePoints[min];
var maxTp = chassis.torquePoints[max];
var TM = maxTp.torque;
var Tm = minTp.torque;
var RM = maxTp.rpm;
var Rm = minTp.rpm;
var a = (TM - Tm) / (RM - Rm);
return rpm * a + Tm - Rm * a;
}
function sign(x) {
return (x > 0.0 ? 1 : (x < 0.0 ? -1 : 0));
}
//invoked each frame to handle the inputs and animate the model
function update_frame(dt, engine, brake, steering) {
if (!this.started)
return;
if (this.sound == 0 && this.snd.is_playing(0)) { // still starting up
return;
}
steering *= 0.2;
this.steer(0, steering);
this.steer(1, steering);
var absSpeed = Math.abs(this.speed());
var khm = absSpeed * 3.6;
var wheels = absSpeed / (chassis.wheelRadius * (2 * Math.PI));
//automatic gear shifting
var rpm = wheels * this.gear.ratio * chassis.finalRatio * 60;
if (rpm < 10 && this.gear.index != 0) {
this.gear = chassis.neutroGear;
this.direction = 0;
// this.log_inf("neutro");
}
if (engine != 0.0 && sign(engine) != this.direction) {
this.direction = sign(engine);
if (this.direction == 1.0) {
this.gear = chassis.forwardGears[0];
// this.log_inf("forward, gear " + this.gear.index);
} else if (this.direction == -1.0) {
this.gear = chassis.reverseGears[0];
// this.log_inf("reverse, gear " + this.gear.index);
}
rpm = wheels * this.gear.ratio * chassis.finalRatio * 60;
}
if (rpm > this.gear.shiftUp && this.gear.next) {
this.gear = this.gear.next;
// this.log_inf("gear up " + this.gear.index);
} else if (rpm < this.gear.shiftDown && this.gear.prev) {
this.gear = this.gear.prev;
// this.log_inf("gear down " + this.gear.index);
}
rpm = wheels * this.gear.ratio * chassis.finalRatio * 60;
if (chassis.maximumSpeed < 0 || this.speed < chassis.maximumSpeed) {
var force = engine * chassis.torque(rpm) * chassis.torqueMultiplier * this.gear.ratio;
this.wheel_force(0, force*0.5);
this.wheel_force(1, force*0.5);
this.wheel_force(2, force);
this.wheel_force(3, force);
}
//From Torcs engine code
var static_friction = 0.1;
var engineBrake = chassis.maxPowerTP.torque * chassis.engineBrakeCoefficient * chassis.torqueMultiplier * this.gear.ratio *
(static_friction + (1.0 - static_friction) * rpm / chassis.maxRPM);
brake *= chassis.breakingForce;
this.wheel_brake(-1, brake + engineBrake);
this.animate_wheels();
if (this.gear.index == 0 && (!this.snd.is_playing(0) || this.sound != 1)) {
this.snd.stop(0);
this.snd.play(0, 1, true, false);
this.sound = 1;
} else if (this.gear.index != 0 && engine == 0 && (!this.snd.is_playing(0) || this.sound != 2)) { //idle
this.snd.stop(0);
this.snd.play(0, 2, true, false);
this.sound = 2;
} else if (this.gear.index != 0 && engine != 0 && (!this.snd.is_playing(0) || this.sound != 3)) { //throttle
this.snd.stop(0);
this.snd.play(0, 3, true, false);
this.sound = 3;
}
var pitch = chassis.pitchMultiplier * rpm / chassis.maxRPM;
this.snd.set_pitch(0, pitch + chassis.basepitch[this.sound]);
}
This is a fixed script from another vehicle, notice the var chassis at the beginning...