I am without words.. What a contribution! And to get the visuals in-game.
EDIT: I set the Engine Power to 150 300 in the script and it shows it off a bit better. Will mess with gearing. SOUNDS GREAT!
EDIT2: Played around and decided on these tweaks.
// !!! not optimized for multiple vehicles in scene !!!
const PI = Math.PI;
const PI_2 = PI / 2.0;
const DEG2RAD = PI / 180.0;
const RAD2DEG = 180.0 / PI;
// dashboard
const MAX_RPM = 9000.0
const MAX_SPEED = 180.0
const MAX_ANGLE = 270.0
const MS2KMH2RAD = 3.6 * MAX_ANGLE / MAX_SPEED * DEG2RAD;
const HOURS2RAD = 360.0 / 12 * DEG2RAD;
const MIN2RAD = 360.0 / 60 * DEG2RAD;
const RPM2RAD = MAX_ANGLE / MAX_RPM * DEG2RAD
// engine
const EK = 300;
const BK = 2000;
// 1 2 3 4 5 R(not work now)
const gears = [4.124, 2.641, 1.88, 1.40, 1.05, -5.224];
const ratio = 3.0;
// 16 samples
const rpm_val = [756,
859, 984, 1126, 1289, 1476, 1690, 1935, 2215,
2536, 2904, 3324, 3806, 4358, 4989, 5712, 6540,
9999];
const sound_path = "sound_v8/";
const rpm_num = rpm_val.length - 2;
const RPM_IDLE2RAD = rpm_val[0] / MAX_RPM * MAX_ANGLE * DEG2RAD;
/*
// V4
var rpm_val = [ 756,
1052, 1126, 1205, 1289, 1380, 1476, 1579,
1690, 1808, 1935, 2070, 2215, 2370, 2536,
2714, 2904, 3107, 3324, 3557, 3806, 4073,
4358, 4663, 4989, 5338, 5712, 6112, 6540,
9999 ];
// V8
var rpm_val = [ 756,
859, 919, 984,
1052, 1126, 1205, 1289, 1380, 1476, 1579,
1690, 1808, 1935, 2070, 2215, 2370, 2536,
2714, 2904, 3107, 3324, 3557, 3806, 4073,
4358, 4663, 4989, 5338, 5712, 6112, 6540,
9999 ];
// V12
var rpm_val = [ 756,
803, 859, 919, 984, 1052, 1126, 1205,
1289, 1380, 1476, 1579, 1690, 1808, 1935,
9999 ];
*/
var rpm_vol = [];
var rpm_pit = [];
var rpm_snd = [];
var rpm_snd_load = [];
var rpm_src = [];
var rpm_src_load = [];
for (var i = 0; i < rpm_val.length; i++) {
rpm_vol[i] = 0;
rpm_pit[i] = 0;
rpm_snd[i] = 0;
rpm_snd_load[i] = 0;
rpm_src[i] = 0;
rpm_src_load[i] = 0;
}
function process_engine_sound(rpm)
{
if (rpm <= rpm_val[1]) {
// only first sample
rpm_pit[1] = rpm / rpm_val[1];
rpm_vol[1] = 1.0;
for (var i = 2; i <= rpm_num; i++)
rpm_vol[i] = 0.0;
} else if (rpm <= rpm_val[rpm_num]) {
// mix 2 samples
for (var i = 1; i <= rpm_num; i++) {
if (rpm > rpm_val[i+1] || rpm <= rpm_val[i-1]) {
rpm_vol[i] = 0.0;
} else {
if (rpm > rpm_val[i]) {
var rpm_d = rpm_val[i+1] - rpm_val[i];
var vol_l = (rpm_val[i+1] - rpm) / rpm_d;
var vol_h = (rpm - rpm_val[i]) / rpm_d;
// sin
rpm_vol[i] = Math.sin(vol_l * PI_2);
rpm_vol[i+1] = Math.sin(vol_h * PI_2);
rpm_pit[i] = rpm / rpm_val[i];
rpm_pit[i+1] = rpm / rpm_val[i+1];
}
}
}
} else {
// only last sample
rpm_pit[rpm_num] = rpm / rpm_val[rpm_num];
rpm_vol[rpm_num] = 1.0;
for (var i = 1; i < rpm_num; i++)
rpm_vol[i] = 0.0;
}
}
// equalizer mesh init
var band = [];
for (var i = 0; i < 16; i++) {
band[i] = 0;
}
//invoked only the first time the model is loaded, or upon reload
function init_chassis()
{
this.log_inf("don't forget to assign ShiftUp and ShiftDown keys");
var wheelparam_left = {
radius: 0.365,
width: 0.220,
suspension_max: 0.1,
suspension_min: -0.25,
suspension_stiffness: 18.0,
damping_compression: 0.4,
damping_relaxation: 0.12,
slip: 0.6,
slip_lateral_coef: 1.5,
rotation: -1
};
var wheelparam_right = {
radius: 0.365,
width: 0.220,
suspension_max: 0.1,
suspension_min: -0.25,
suspension_stiffness: 18.0,
damping_compression: 0.4,
damping_relaxation: 0.12,
slip: 0.75,
slip_lateral_coef: 1.3,
rotation: 1
};
var vehicle_params = {
mass: 1100.0,
steering: 2.0,
steering_ecf: 60.0,
centering: 3.0,
centering_ecf: 40.0,
com: {x: 0.0, y: 0.0, z: -0.0}
};
this.add_wheel("wfl", wheelparam_left);
this.add_wheel("wfr", wheelparam_right);
this.add_wheel("wrl", wheelparam_left);
this.add_wheel("wrr", wheelparam_right);
//sounds
for (var i = 1; i <= rpm_num; i++) {
rpm_snd[i] = this.load_sound("" + sound_path + rpm_val[i] + ".ogg");
rpm_src[i] = this.add_sound_emitter("snd_engine");
rpm_snd_load[i] = this.load_sound("" + sound_path + rpm_val[i] + "_P.ogg");
rpm_src_load[i] = this.add_sound_emitter("snd_engine_load");
};
this.log_inf("loaded " + rpm_num*2 + " engine sound samples");
return vehicle_params;
}
//invoked for each new instance of the vehicle
function init_vehicle()
{
this.started = 0;
this.speed_old = 0;
this.gear_idx = 0;
this.body = this.get_geomob(0);
var cam_fps = this.body.get_joint_local_pos(this.body.get_joint("cam_fps"));
this.set_fps_camera_pos(cam_fps);
this.arrow_speed = this.body.get_joint("arrow_speed");
this.arrow_rpm = this.body.get_joint("arrow_rpm");
this.arrow_hour = this.body.get_joint("arrow_clock_hour");
this.arrow_min = this.body.get_joint("arrow_clock_min");
this.arrow_1 = this.body.get_joint("arrow_1");
this.arrow_2 = this.body.get_joint("arrow_2");
this.arrow_3 = this.body.get_joint("arrow_3");
this.arrow_4 = this.body.get_joint("arrow_4");
this.arrow_5 = this.body.get_joint("arrow_5");
// sounds
this.snd = this.sound();
for (var i = 1; i <= rpm_num; i++) {
this.snd.set_ref_distance(rpm_src[i], 5.0);
this.snd.set_ref_distance(rpm_src_load[i], 5.0);
};
// "equalizer" meshes
for (var i = 0; i < 16; i++) {
band[i] = this.body.get_joint("band" + (i+1));
}
}
//invoked when engine starts or stops
function engine(start)
{
if (start) {
this.started = 1;
for (var i = 1; i <= rpm_num; i++) {
rpm_vol[i] = 0.0;
this.snd.play_loop(rpm_src[i], rpm_snd[i]);
this.snd.play_loop(rpm_src_load[i], rpm_snd_load[i]);
}
} else {
this.started = 0;
for (var i = 1; i <= rpm_num; i++) {
rpm_vol[i] = 0.0;
this.snd.stop(rpm_src[i]);
this.snd.stop(rpm_src_load[i]);
}
}
}
function action(k, v, dt)
{
switch(k) {
case AShiftUp: {
if (v)
this.gear_idx = this.gear_idx < 4 ? this.gear_idx + 1 : 4;
break;
}
case AShiftDown: {
if (v)
this.gear_idx = this.gear_idx > 0 ? this.gear_idx - 1 : 0;
break;
}
case AReverse: {
if (v)
this.gear_idx = this.gear_idx < 5 ? 5 : 0;
break;
}
}
}
//invoked each frame to handle the inputs and animate the model
function update_frame(dt, engine, brake, steering)
{
var steer = steering * 0.5;
this.steer(0, steer);
this.steer(1, steer);
if (this.started) {
var eng = engine * EK * gears[this.gear_idx] * ratio;
this.wheel_force(2, eng);
this.wheel_force(3, eng);
}
var brake_idle = (1.0 - engine) * BK * 0.1;
var brake_front = brake * BK * 0.5 + brake_idle;
var brake_rear = brake * BK + brake_idle;
this.wheel_brake(0, brake_front);
this.wheel_brake(1, brake_front);
this.wheel_brake(2, brake_rear);
this.wheel_brake(3, brake_rear);
this.animate_wheels();
// dashboard
// // speed
var spd = Math.abs(this.speed() * MS2KMH2RAD);
this.body.rotate_joint_orig(this.arrow_speed, spd, {x: 0, y: 1, z: 0});
// // rpm
var rpm = 0.0;
var max_wheel_rpm = Math.abs(Math.max(this.wheel(2).rpm, this.wheel(3).rpm));
if (this.started)
rpm += max_wheel_rpm * gears[this.gear_idx] * ratio * RPM2RAD + RPM_IDLE2RAD;
this.body.rotate_joint_orig(this.arrow_rpm, rpm, {x: 0, y: 1, z: 0});
// // clock
var time = new Date();
var hour = time.getHours() * HOURS2RAD;
var mins = time.getMinutes() * MIN2RAD;
this.body.rotate_joint_orig(this.arrow_hour, hour, {x: 0, y: 1, z: 0});
this.body.rotate_joint_orig(this.arrow_min, mins, {x: 0, y: 1, z: 0});
// // accelerate
var acc = (this.speed() - this.speed_old) / dt;
this.speed_old = this.speed();
acc *= 12 * DEG2RAD; // +/- 6 m/s^2
this.body.rotate_joint_orig(this.arrow_1, acc, {x: 0, y: 1, z: 0});
// // gears
var gear = this.gear_idx * 30 * DEG2RAD;
this.body.rotate_joint_orig(this.arrow_2, gear, {x: 0, y: 1, z: 0});
// // throtle
this.body.rotate_joint_orig(this.arrow_3, engine * PI_2, {x: 0, y: 1, z: 0});
this.body.rotate_joint_orig(this.arrow_4, brake * PI_2, {x: 0, y: -1, z: 0});
// FIXME:
var torque = engine;
// engine sounds
if (this.started) {
rpm = max_wheel_rpm * gears[this.gear_idx] * ratio + rpm_val[0];
process_engine_sound(rpm);
// set pitch and volume
for (var i = 1; i <= rpm_num; i++) {
this.snd.set_pitch(rpm_src[i], rpm_pit[i]);
this.snd.set_gain(rpm_src[i], rpm_vol[i] * (1.0 - torque));
this.snd.set_pitch(rpm_src_load[i], rpm_pit[i]);
this.snd.set_gain(rpm_src_load[i], rpm_vol[i] * torque);
}
}
// debug "equalizer"
for (var i = 1; i <= rpm_num; i++) {
var s = Math.ceil(rpm_vol[i] * 20.0) * 0.01; // 1/20 * 0.20m (lenght of band);
var move = {x: 0, y: s * 0.5, z: s * 0.866}; // sin(30), cos(30)
this.body.move_joint_orig(band[i-1], move);
}
}
Using my Gas Pedal instead of keys is way better. Pretty much just gearing, engine and suspension/tire tweaks. I wouldn't dare touch the other code.