Took a real quick stab at adding in the slip_lateral property now. It feels pretty good I think.
I was able to do a controlled drift for like 20meters or so around a bend, and recover fine. Still needs work though probably.
//vehicle script file
//see http://xtrac.outerra.com/index.fcgi/wiki/vehicle for example and documentation
/*
* Vehicle script file
* Copyright (C) 2013 Matt Lichy
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
//*******ENGINE Template/Code by ZeosPantera of Outerra Forum. *********
//invoked only the first time the model is loaded, or upon reload
function init_chassis(){
var wheelparam =
{
radius: 0.34, //<-- edit this to 0.3 (remember our wheel radius of 30cm!)
width: 0.15, //<-- edit this to 0.2 (this represents the height parameter in 3d max of 20cm!)
suspension_max: 0.3,
suspension_min: -0.1,
suspension_stiffness: 25,
damping_compression: 0.1,
damping_relaxation: 0.3,
slip: 1.30, //0.8
slip_lateral_coef: 0.80,
roll_influence: 0.1,
rotation: -1.0
};
var wheelparam_Rear =
{
radius: 0.34, //<-- edit this to 0.3 (remember our wheel radius of 30cm!)
width: 0.15, //<-- edit this to 0.2 (this represents the height parameter in 3d max of 20cm!)
suspension_max: 0.3,
suspension_min: -0.1,
suspension_stiffness: 21,
damping_compression: 0.1,
damping_relaxation: 0.3,
slip: 1.25, //0.8
slip_lateral_coef: 0.72,
roll_influence: 0.1,
rotation: -1.0
};
//http://www.outerra.com/forum/index.php?topic=1561.msg17833#msg17833
//Wheelbase 115"
//Length 195.6"
//V8 Bel Air with Powerglide as being 0-60 mph in 12.9 seconds
this.add_wheel('wheel_rf_L0',wheelparam); //<-- the name "wheel_FR" is the name you used for your wheel in 3d max
this.add_wheel('wheel_lf_L0',wheelparam);
//this.add_wheel_swing('suspension_rf_L0', 'wheel_rf_L0', wheelparam);
//this.add_wheel_swing('suspension_lf_L0', 'wheel_lf_L0', wheelparam);
this.add_wheel('wheel_rr_L0',wheelparam_Rear);
this.add_wheel('wheel_lr_L0',wheelparam_Rear);
this.load_sound("belair_startup.ogg"); //startup
this.load_sound("belair_onidle.ogg"); //idle
this.load_sound("e90_offlow.ogg"); //off
this.load_sound("e90_onlow.ogg"); //on
this.basepitch = [ 0.3, 0.95, 0.20, 0.20 ]; //base pitch for start, idle, throttle
this.add_sound_emitter("bonnet_L0");
//engine properties -- modify these to change the engine behaviour
this.wheelRadius = 0.34;
this.torquePoints = [ { rpm: 0, torque: 1080},
{ rpm: 1000, torque: 1120},
{ rpm: 2000, torque: 1235},
{ rpm: 3000, torque: 1380},
{ rpm: 4000, torque: 1400},
{ rpm: 5000, torque: 1415},
{ rpm: 6000, torque: 1400},
{ rpm: 7000, torque: 0},
{ rpm: 8000, torque: 0},
{ rpm: 9000, torque: 0 } ];
this.forwardGears = [ { ratio: 4.00, shiftUp: 5000, shiftDown: -1 },
{ ratio: 3.00, shiftUp: 5000, shiftDown: 2500 },
{ ratio: 2.00, shiftUp: 5000, shiftDown: 3000 },
{ ratio: 1.50, shiftUp: 5000, shiftDown: 3000 },
{ ratio: 1.00, shiftUp: -1, shiftDown: 3000 } ];
this.reverseGears = [ { ratio: 4.20, shiftUp: -1, shiftDown: -1 } ];
this.finalRatio = 4;
this.torqueMultiplier = 1.45; //2.25
this.maximumSpeed = -1; // speed in m/s. a value < 0 means there's no maximum speed
this.engineBrakeCoefficient = 0.1;
this.breakingForce = 3800.0;
this.pitchMultiplier = 0.6;
//end of engine properties
this.maxPowerTP = this.torquePoints[0];
this.maxRPM = 5800;
var maxPw = 0;
for (var i = 1; i < this.torquePoints.length; ++i) {
var tp = this.torquePoints[i];
if (tp.rpm * tp.torque > maxPw) {
this.maxPowerTP = tp;
}
if (tp.rpm > this.maxRPM) {
this.maxRPM = tp.rpm;
}
}
this.neutroGear = { ratio: 0.0, shiftUp: -1, shiftDown: -1, index: 0 };
var prev = null;
for (var i = 0; i < this.forwardGears.length; ++i) {
var gear = this.forwardGears[i];
if (prev)
prev.next = gear;
gear.prev = prev;
gear.index = i + 1;
prev = gear;
}
prev = null;
for (var i = 0; i < this.reverseGears.length; ++i) {
var gear = this.reverseGears[i];
if (prev)
prev.next = gear;
gear.prev = prev;
gear.index = -i - 1;
prev = gear;
}
this.torque = engineTorque;
return {mass:1570, steering:1.0, steering_ecf:10000, centering: 2.0, centering_ecf: 10, com:{y:0.2, z:-0.15}};
}
//invoked for each new instance of the vehicle
function init_vehicle() {
this.set_fps_camera_pos({x:-0.32,y:-0.38,z:0.67});
this.geom = this.get_geomob(0)
this.swheel = this.geom.get_joint("steering_Wheel_center_L0");
this.speedometer = this.geom.get_joint("speed_Needle_L0");
this.gearNeedle = this.geom.get_joint("gear_Needle_L0");
this.snd = this.sound();
this.snd.set_ref_distance(0, 9.0);
this.started = false;
this.gear = this.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 = this.torquePoints.length - 1;
if (rpm > this.torquePoints[max].rpm || rpm < this.torquePoints[min].rpm)
return 0;
while (max - min > 1) {
var mid = Math.floor(min + (max - min) / 2);
var tp = this.torquePoints[mid];
if (tp.rpm == rpm) {
return tp.torque;
} else if (tp.rpm > rpm) {
max = mid;
} else {
min = mid;
}
}
var minTp = this.torquePoints[min];
var maxTp = this.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.65;
this.steer(-2, steering);
var steerAngle = steering *= 10.05;
this.geom.rotate_joint_orig(this.swheel, steerAngle, {x:0,y:0,z:1});
var absSpeed = Math.abs(this.speed());
var khm = absSpeed * 3.6;
var wheels = absSpeed / (this.wheelRadius * (2 * Math.PI));
//this.log_inf("Khm" + khm);
//Rotate Spedometer Needle
var spedo = (absSpeed / 8.35) / 1.6; //Divide to get into 0-120 rotation range, then divide to convert Kmh to MPH roughly.
if (spedo < 201) //roughly 120 MPH
{
this.geom.rotate_joint_orig(this.speedometer,spedo,{x:0,y:0,z:-1});
}
//automatic gear shifting
var rpm = wheels * this.gear.ratio * this.finalRatio * 60;
if (rpm < 5 && this.gear.index != 0) {
this.gear = this.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 = this.forwardGears[0];
// this.log_inf("forward, gear " + this.gear.index);
} else if (this.direction == -1.0) {
this.gear = this.reverseGears[0];
// this.log_inf("reverse, gear " + this.gear.index);
}
rpm = wheels * this.gear.ratio * this.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 * this.finalRatio * 60;
if (this.maximumSpeed < 0 || this.speed < this.maximumSpeed) {
var force = engine * this.torque(rpm) * this.torqueMultiplier * this.gear.ratio;
this.wheel_force(2, force);
this.wheel_force(3, force);
}
//From Torcs engine code
var static_friction = 0.1;
var engineBrake = this.maxPowerTP.torque * this.engineBrakeCoefficient * this.torqueMultiplier * this.gear.ratio *
(static_friction + (1.0 - static_friction) * rpm / this.maxRPM);
brake *= this.breakingForce;
this.wheel_brake(-1, brake + engineBrake);
this.animate_wheels();
//Move Gear Needle into spot based on engine
//this.log_inf("Gear " + this.gear.index);
if (this.gear.index >= 1) //Drive
{
this.geom.rotate_joint_orig(this.gearNeedle,0.55,{x:0,y:0,z:1});
}
if (this.gear.index == -1) //Reverse
{
this.geom.rotate_joint_orig(this.gearNeedle,1.10,{x:0,y:0,z:1});
}
if (rpm < 5 && this.gear.index == 0) //Neutral
{
this.geom.rotate_joint_orig(this.gearNeedle,0.35,{x:0,y:0,z:1});
}
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 = this.pitchMultiplier * rpm / this.maxRPM;
this.snd.set_pitch(0, pitch + this.basepitch[this.sound]);
}