Now only a cockpit view is missing to complete its awesomeness
Fixed script so that you can spawn more than one. The problem is that 'this' only refers to one vehicle, so any chassis parameters must be stored globally.
Hello Unsurt,
is it possible that you can integrate such an realistic physics to the Tumbler Car like in this Unity3D-Game:
http://nemdrive.com/Demos/Tumbler/ (http://nemdrive.com/Demos/Tumbler/)
Greetings,
Edwin
Request to Cameni:Please put such feature requests into the tracker (http://www.outerra.com/forum/index.php?topic=1211.0). Nobody will find or remember it when it's located somewhere on the forums, especially not if it's like here in the middle of a completely unrelated thread. Or at least make a separate thread in the support board, but the tracker is a better place for this.
The thumbnails for vehicles are stored in Outerra\Anteworld\www\images\pkg at the moment.
So most of people forget about them. Ang currently it is tootal mess in vehicle list.
I know the vehicle installers will solve this, but still would be nice to keep everything (thumbnails and preferably even Plane Engine scripts, flightmodel scripts) in the model folder (or sub-folder).
This would make it much easier and cleaner to backup whole lot of current (installed) vehicles.
As well as sharing them.
And basically the installers won't be needed so much.
//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.40,
width: 20,
suspension_max: 0.5,
suspension_min: -0.2,
suspension_stiffness: 10.0,
damping_compression: 0.1,
damping_relaxation: 0.2,
slip: 0.6,
roll_influence: 0.01,
rotation: -1
};
var wheelparam2 = {
radius: 0.62,
width: 50,
suspension_max: 0.5,
suspension_min: -0.3,
suspension_stiffness: 15.0,
damping_compression: 0.3,
damping_relaxation: 0.5,
slip: 0.8,
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: 200},
{ rpm: 1000, torque: 100},
{ rpm: 2000, torque: 50},
{ rpm: 3000, torque: 20},
{ rpm: 4000, torque: 0},
{ rpm: 5000, torque: 0},
{ rpm: 6000, torque: 0},
{ rpm: 7000, torque: 0},
{ rpm: 8000, torque: 0},
{ rpm: 9000, torque: 0 } ];
chassis.forwardGears = [ { ratio: 6.20, shiftUp: 10600, shiftDown: -1 },
{ ratio: 4.29, shiftUp: 5600, shiftDown: 5000 },
{ ratio: 3.56, shiftUp: 5600, shiftDown: 6000 },
{ ratio: 2.14, shiftUp: 5600, shiftDown: 3000 },
{ ratio: 1.00, shiftUp: -1, shiftDown: 3000 } ];
chassis.reverseGears = [ { ratio: 1.80, shiftUp: -1, shiftDown: -1 } ];
chassis.finalRatio = 1;
chassis.torqueMultiplier = 6;
chassis.maximumSpeed = -1; // speed in m/s. a value < 0 means there's no maximum speed
chassis.engineBrakeCoefficient = 0.2;
chassis.breakingForce = 10000.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[i];
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[i];
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[i];
if (prev)
prev.next = gear;
gear.prev = prev;
gear.index = -i - 1;
prev = gear;
}
chassis.torque = engineTorque;
return {mass:3500, com:{y:-1.05, z:-0.55}, steering:5, steering_ecf:30,
centering: 10.0, centering_ecf: 10};
}
//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.5;
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]);
}
I think the next step is object ramps we can leap off of. Not sure when collisions will be ready.You can always do this:
OK Dokey..
Here are the modified physics.
chassis.torquePoints = [ { rpm: 0, torque: 200},
{ rpm: 1000, torque: 100},
{ rpm: 2000, torque: 50},
{ rpm: 3000, torque: 20},
{ rpm: 4000, torque: 0},
{ rpm: 5000, torque: 0},
{ rpm: 6000, torque: 0},
{ rpm: 7000, torque: 0},
{ rpm: 8000, torque: 0},
{ rpm: 9000, torque: 0 } ];
chassis.forwardGears = [ { ratio: 6.20, shiftUp: 10600, shiftDown: -1 },
{ ratio: 4.29, shiftUp: 5600, shiftDown: 5000 },
{ ratio: 3.56, shiftUp: 5600, shiftDown: 6000 },
{ ratio: 2.14, shiftUp: 5600, shiftDown: 3000 },
{ ratio: 1.00, shiftUp: -1, shiftDown: 3000 } ];
You're making the torque decay very fast as the rpm goes up, it's a tractor, and you're setting a very high shiftUp property of the first gear, which it will never reach as it has no torque to go at more than ~ 3500 rpm (unless it's going down a vertical road), so it's always in first gear.OK Dokey..
Here are the modified physics.
I didn't try it but i think there are some problems with these physics settings:
You're making the torque decay very fast as the rpm goes up, it's a tractor, and you're setting a very high shiftUp property of the first gear, which it will never reach as it has no torque to go at more than ~ 3500 rpm (unless it's going down a vertical road), so it's always in first gear.
(btw, you can just remove the torque points with 0 torque.)
OK Dokey..
Here are the modified physics.
And I also added it as an attachment.
I think the next step is object ramps we can leap off of. Not sure when collisions will be ready.
An attempt to get the Tumbler vaulting.
Outerra & Tumbler (http://www.youtube.com/watch?v=FM63Q5u5NYo#ws)