Outerra forum

Please login or register.

Login with username, password and session length
Advanced search  

News:

Download Outerra Tech Demo. Unofficial Outerra Discord server, MicroProse Discord server for OWS.

Pages: 1 ... 3 4 [5] 6 7 8

Author Topic: Vehicle script [version 1.4.0]  (Read 82978 times)

giucam

  • Full Member
  • ***
  • Posts: 171
  • It's an ugly pile of bones... like me.
Re: Vehicle script [version 1.3.2]
« Reply #60 on: June 03, 2013, 01:17:33 pm »

Odd... pasting it in notepad++ here works all right. Anyway, i've attached the js.
Logged
ResidualVM 0.1.1 is OUT! www.residualvm.org

bugsblake

  • Sr. Member
  • ****
  • Posts: 255
  • jedi master
Re: Vehicle script [version 1.3.2]
« Reply #61 on: June 03, 2013, 01:57:17 pm »

thanks! yh i know, its pastes alright sometimes and not others? :/ anyway thanks for the file! and thanks for your advice in my other post, all engine sounds working now! will update the mustang and charger later tonight! thanks a lot mate! :D
Logged
Intel 6 core i7 Xeon - 4930k @3.40 GHz
GTX 770 4GB X2 in SLI
Asus P9X79 Extreme MOBO
Patriot 16GB DDR3 1600MHz
SSD 250GB + SATA 500GB + SATA 1TB

M7

  • Hero Member
  • *****
  • Posts: 736
  • newbie
Re: Vehicle script [version 1.3.2]
« Reply #62 on: June 03, 2013, 11:50:42 pm »

in 132 for the high rev sound you use 2 simultanious sound ? I like the idea that it can be script,i have some idea how to use it on tanks but on the BMW, i'm not so sure it sound better than the high rev alone. The e90_onlow.ogg is probably the best high rev sound for land vehicle ingame. Looks like it will be a pretty tough job to improve it.

On the other end, i'm so glad you're taking on to add these new features, really appreciate!!
Logged

giucam

  • Full Member
  • ***
  • Posts: 171
  • It's an ugly pile of bones... like me.
Re: Vehicle script [version 1.3.2]
« Reply #63 on: June 04, 2013, 05:50:54 am »

Actually 3 simultanious sounds, but you may hear only one because two have 0 volume. I needed to change the sound handling because when using an axis to accellerate the 90_onlow.ogg was playing only when fully accellerating. So i changed it to always play it and to set the volume of it to the engine value passed to the update function (which goes from 0 to 1), and the off sound uses 1 - engine. That way the off and on sounds blend nicely when pushing more or less on the accellerator.
Then there's the idle sound, which can be heard only when going not too fast (more or less), fading away as you gain speed.

So yeah, if you use the keyboard you should not notice much difference with before.
Logged
ResidualVM 0.1.1 is OUT! www.residualvm.org

M7

  • Hero Member
  • *****
  • Posts: 736
  • newbie
Re: Vehicle script [version 1.3.2]
« Reply #64 on: June 04, 2013, 09:15:06 am »

I use keyboard and it sounds much different than previous version. The acceleration sound quite mushy (not clear like before)

But now i will have to try it with a pedal. This is really cool stuff if you can blend
different sounds during acceleration/decelaration. It might make it much easier to create sound for high rev if you dont have to use the pitch multiplier as much. Wow great stuff!!!!

But people using  keyboard only , they might be better off these new versions.
« Last Edit: June 04, 2013, 12:38:33 pm by M7 »
Logged

M7

  • Hero Member
  • *****
  • Posts: 736
  • newbie
Re: Vehicle script [version 1.3.2]
« Reply #65 on: June 08, 2013, 10:03:28 pm »

 I tried this time with a pedal and it was pretty much the same thing. Then i thought to checkt the .impcfg (which unfortunatly we dont get anymore when using the .otx to export) to look for another bone than the wheel to set the soundEmitter. I didn't find a bone  but pick up a random part, i actually choose 'box61' and BINGO!

This thing sounds incredible now  compare to one sound at a time. To my ears, it sound almost like a formula one and you get perfect transitions. Fken good job Giucam!!!!!!

The only thing is the idle sound, i barely ear it and the sound cut as well. It's really weird cause if i put the soundEmitter back to Wheel_RF , e90_onidle.ogg sounds perfect.

Logged

giucam

  • Full Member
  • ***
  • Posts: 171
  • It's an ugly pile of bones... like me.
Re: Vehicle script [version 1.3.2]
« Reply #66 on: June 09, 2013, 10:35:36 am »

Wait, was it using the wheel as sound emitter? I changed it to the bone "hood" in the latest versions. Are you using the bmw version 2 or still the 1?
Logged
ResidualVM 0.1.1 is OUT! www.residualvm.org

M7

  • Hero Member
  • *****
  • Posts: 736
  • newbie
Re: Vehicle script [version 1.3.2]
« Reply #67 on: June 09, 2013, 12:59:12 pm »

Hehe! Wrong car and wrong script ::) didnt know there was a new car and i used the engine1.3.2.js that you have last as attachment which still have the wheel as sound emitter.

But now that i got all the right parts, everything sound perfect!!!!!!!!  And also you can reload sounds within the game now, which makes it so much easier to experiment. Looking forward to try new sound combo with this script . Thanks so much Giucam!

« Last Edit: June 09, 2013, 01:38:08 pm by M7 »
Logged

M7

  • Hero Member
  • *****
  • Posts: 736
  • newbie
Re: Vehicle script [version 1.3.2]
« Reply #68 on: June 09, 2013, 11:20:26 pm »

I tried this script with the Dodge bigfoot. Everything works as expected except for sound. First, the idle sound is barely perceptible and breaks, then acceleration/decelaration sounds just woble. I also tried to use the BMW sounds but it didn't play at all.

Also looks like you dont need to set a bone as sound emitter anymore. Sounds will play with or without (unlike before)

I made an .otx if you  want to take a look.

https://docs.google.com/file/d/0B96RrTcNJsI2N0Q5ajJNcEowWVE/edit?usp=sharing
Logged

giucam

  • Full Member
  • ***
  • Posts: 171
  • It's an ugly pile of bones... like me.
Re: Vehicle script [version 1.3.3]
« Reply #69 on: June 10, 2013, 10:43:35 am »

I made a mistake with the sound emitter indeed.

Version 1.3.3

Code: [Select]
/*
    Vehicle script file
    Copyright (C) 2012 - 2013  Giulio Camuffo <giuliocamuffo@gmail.com>

    This library 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.0 of the License, or (at your option) any later version.

    This library 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/>.
*/

//see http://xtrac.outerraworld.com/trac.fcgi/wiki/vehicle for example and documentation

// VERSION 1.3.3

var chassis = {};

// --- Vehicle specific stuff ---
function chassis_setup() {
    var wheelparam = {
        radius: 0.30,
        width: 0.20,
        suspension_max: 0.1,
        suspension_min: -0.05,
        suspension_stiffness: 50.0,
        damping_compression: 0.06,
        damping_relaxation: 0.05,
        slip: 2.0,
        roll_influence: 0.1,
        rotation: -1
    };

    this.add_wheel('wheel_FL', wheelparam);
    this.add_wheel('wheel_FR', wheelparam);
    this.add_wheel('wheel_RL', wheelparam);
    this.add_wheel('wheel_RR', wheelparam);

    this.load_sound("e90_onidle.ogg"); //idle
    this.load_sound("e90_offlow.ogg"); //off
    this.load_sound("e90_onlow.ogg"); //on
    chassis.basePitch = [ 1, 0.4, 0.4 ];             //base pitch for idle, off, on
    chassis.relVolumes = [ 0.8, 1, 1 ];
    chassis.soundEmitter = "hood";

    //engine properties -- modify these to change the engine behaviour
    chassis.wheelRadius = 0.24;

    chassis.torquePoints = [ { rpm: 500,  torque: 0},
                             { rpm: 1000, torque: 250},
                             { rpm: 2000, torque: 335},
                             { rpm: 3000, torque: 380},
                             { rpm: 4000, torque: 400},
                             { rpm: 5000, torque: 395},
                             { rpm: 6000, torque: 400},
                             { rpm: 7000, torque: 390},
                             { rpm: 8000, torque: 365},
                             { rpm: 9000, torque: 0  } ];

    chassis.forwardGears = [ { ratio: 4.06, shiftUp: 8000, shiftDown: -1   },
                             { ratio: 2.40, shiftUp: 8000, shiftDown: 4500 },
                             { ratio: 1.58, shiftUp: 8000, shiftDown: 5000 },
                             { ratio: 1.19, shiftUp: 8000, shiftDown: 5500 },
                             { ratio: 1.00, shiftUp: 8000, shiftDown: 6000 },
                             { ratio: 0.87, shiftUp: -1,   shiftDown: 6000 } ];
    chassis.reverseGears = [ { ratio: 4.68, shiftUp: -1, shiftDown: -1 } ];

    chassis.differentialRatio = 3.85;
    chassis.efficiency = 0.9;
    chassis.speedLimiter = -1; // maximum speed in m/s. a value < 0 means there's no limiter
    chassis.engineBrakeCoefficient = 0.4;
    chassis.breakingForce = 3000.0;
    chassis.pitchMultiplier = 1.5;
    chassis.engineInertia = 0.015;
    chassis.minimumRPM = 1500;
    chassis.minimum = 0.2;
    //end of engine properties

    return { mass:1570, steering:1.2, steering_ecf:700, centering: 5.0, centering_ecf: 40, com: { z:0.1 } };
}

function vehicle_setup() {
    this.set_fps_camera_pos( {x: -0.33,y: -0.20, z: 1.15});
    this.soundRefDistance = 5;
    this.automaticTransmission = false;
    this.clutchMode = ClutchMode.Automatic;
}

function animate()
{
    this.animate_wheels();
}

// --- End of vehicle specific stuff ---



//invoked only the first time the model is loaded, or upon reload
function init_chassis() {
    this.setup = chassis_setup;
    var ret = this.setup();

    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.prev = gear;
        gear.next = prev;
        gear.index = -i - 1;
        prev = gear;
    }

    return ret;
}

var ClutchMode = { Manual: 0, Automatic: 1, Mixed: 2 };
var ClutchState = { Engaged: 0, Disengaged: 1, Engaging: 2, Disengaging: 3 };

//invoked for each new instance of the vehicle
function init_vehicle() {
    this.snd = this.sound();

    this.torque = engineTorque;
    this.shiftUp = shift_up;
    this.shiftDown = shift_down;
    this.selectGear = select_gear;
    this.updateAutomaticTransmission = automatic_transmission;
    this.automaticClutch = automatic_clutch;
    this.clutchValue = clutch_value;
    this.animate = animate;
    this.setup = vehicle_setup;

    this.setup();

    var id = this.get_geomob(0).get_joint(chassis.soundEmitter);
    this.idleSource = this.snd.create_source(id);
    this.onSource = this.snd.create_source(id);
    this.offSource = this.snd.create_source(id);
    this.idleSound = 1;
    this.snd.set_ref_distance(this.idleSource, this.soundRefDistance);
    this.snd.set_ref_distance(this.onSource, this.soundRefDistance);
    this.snd.set_ref_distance(this.offSource, this.soundRefDistance);
    this.snd.play(this.idleSource, 0, true, false);
    this.snd.play(this.offSource, 1, true, false);
    this.snd.play(this.onSource, 2, true, false);

    this.clutch = 1.0;
    this.clutchState = ClutchState.Disengaged;
    this.started = false;
    this.gear = chassis.neutroGear;
    this.direction = 0;
    this.engineRPM = 0;
    this.starting = false;
    this.clutchOverride = false;
}

//invoked when engine starts or stops
function engine(start) {
    this.started = false;
    this.starting = start;
    this.idleSound = 1.0;
}

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

function action(key, value, dt)
{
    if (key == AAuxb1 && value == 0) {
        this.automaticTransmission = !this.automaticTransmission;
        this.log_inf("Automatic transmission " + (this.automaticTransmission ? "enabled" : "disabled"));
    }

    if (key == AAuxb2 || key == AAuxa2) {
        if (key == AAuxa2) {
            value = 1 - (value + 1) / 2;
        }

        this.clutchState = (value == 0 ? ClutchState.Disengaged : ClutchState.Engaged);
        this.clutch = 1 - value;
        this.clutchOverride = value != 0;
    }

    if (value == 1 && !this.automaticTransmission) {
        switch(key) {
            case AShiftUp:
                this.shiftUp();
                break;
            case AShiftDown:
                this.shiftDown();
                break;
            default:
                break;
        }
    }
}

function select_gear(gear)
{
    if (this.gear == gear) {
        return;
    }

    var i = this.gear.index;
    this.gear = gear;
    if (i == 0 && this.clutchMode == ClutchMode.Automatic && (this.started || this.starting)) {
        this.clutchState = ClutchState.Engaging;
    }
    this.log_inf("gear " + i + " => " + this.gear.index);
}

function shift_up()
{
    var i = this.gear.index;
    if (this.gear.next) {
        this.selectGear(this.gear.next);
    } else if (i == 0) {
        this.selectGear(chassis.forwardGears[0]);
    } else if (i == -1) {
        this.selectGear(chassis.neutroGear);
    }
}

function shift_down()
{
    var i = this.gear.index;
    if (this.gear.prev) {
        this.selectGear(this.gear.prev);
    } else if (i == 0) {
        this.selectGear(chassis.reverseGears[0]);
    } else if (i == 1) {
        this.selectGear(chassis.neutroGear);
    }
}

function automatic_transmission(engine)
{
    if (this.engineRPM < 10 && this.gear.index != 0) {
        this.direction = 0;
        this.selectGear(chassis.neutroGear);
    }
    if (engine != 0.0) {
        if (sign(engine) != this.direction) {
            this.direction = sign(engine);
            this.selectGear(chassis.neutroGear);
            if (this.direction == 1.0) {
                this.selectGear(chassis.forwardGears[0]);
            } else if (this.direction == -1.0) {
                this.selectGear(chassis.reverseGears[0]);
            }
        }
    }

    if (this.clutch != 0) {
        if (this.engineRPM > this.gear.shiftUp && this.gear.next) {
            this.shiftUp();
        } else if (this.engineRPM < this.gear.shiftDown && this.gear.prev) {
            this.shiftDown();
        }
    }
}

function automatic_clutch(wheelsRpm)
{
    var clutched = (this.clutchState == ClutchState.Disengaged  || this.clutchState == ClutchState.Disengaging) && this.gear.index != 0;
    var clutchRPM = chassis.minimumRPM * 7 / 4;
    var w = wheelsRpm * this.gear.ratio * chassis.differentialRatio;

    if (this.clutchMode == ClutchMode.Automatic && !this.clutchOverride && (this.started || this.starting)) {
        if (clutched && this.engineRPM < chassis.minimumRPM && w < chassis.minimumRPM) {
            this.clutchState = ClutchState.Engaging;
        } else if (!clutched && (this.engineRPM > clutchRPM || w > chassis.minimumRPM)) {
            this.clutchState = ClutchState.Disengaging;
        }
    }

    if (this.clutchState == ClutchState.Disengaging) {
        if (this.gear.index != 0) {
            this.clutch = (w > chassis.minimumRPM ? chassis.minimumRPM : w) / chassis.minimumRPM;

            // This makes an horizontal S-like shape. (mirrored, like Z)
            var f = this.clutch * 2;
            if (f < 0.5) {
                this.clutch = -(f * f * f * f - 1) / 5;
            } else {
                f = f - 1;
                this.clutch = (f * f * f * f) + 0.2;
            }
            this.clutch += 0.4;
            var r = (this.engineRPM - chassis.minimumRPM) / clutchRPM;
            r = (r > 1 ? 1 : (r < 0 ? 0 : r));
            r = Math.sqrt(r);
            this.clutch *= r
        } else {
            this.clutch = 1;
        }

        if (this.clutch >= 1) {
            this.clutch = 1;
            this.clutchState = ClutchState.Disengaged;
        }
    } else if (this.clutchState == ClutchState.Engaging) {
        this.clutch = 0;
        this.clutchState = ClutchState.Engaged;
    }
    return this.clutch;
}

function clutch_value(wheelsRpm)
{
    var clutch = this.clutch;
    if (this.clutchMode != ClutchMode.Manual && !this.clutchOverride) {
        clutch = this.automaticClutch(wheelsRpm);
    }
    if (this.gear.index == 0) {
        clutch = 0;
    }
    return clutch;
}

//invoked each frame to handle the inputs and animate the model
function update_frame(dt, engine, brake, steering) {
    steering *= 0.6;
    this.steer(-2, steering);

    if (this.automaticTransmission) {
        this.updateAutomaticTransmission(engine);
    }

    var wheelsRpm = Math.abs(this.max_rpm());
    if (sign(this.speed()) != sign(this.gear.index) && this.gear.index != 0) {
        wheelsRpm = 0;
    }

    if (engine < 0) {
        engine = -engine;
    }

    var appliedTorque = 0;
    if (this.starting) {
        if (this.engineRPM > chassis.minimumRPM) {
            this.starting = false;
            this.started = true;
        } else {
            appliedTorque = 200 * (1 - this.engineRPM / chassis.minimumRPM);
        }
    }

    var oldRPM = this.engineRPM;
    var clutch = this.clutchValue(wheelsRpm);
    this.engineRPM = this.engineRPM * (1 - clutch) + wheelsRpm * clutch * this.gear.ratio * chassis.differentialRatio;

    var running = this.started || this.starting;
    if (running) {
        if (this.engineRPM < chassis.minimumRPM && engine < chassis.minimum) {
            engine = chassis.minimum;
        }
        if (chassis.speedLimiter < 0 || Math.abs(this.speed()) < chassis.speedLimiter) {
            appliedTorque += engine * this.torque(this.engineRPM);
        }
    }

    this.engineRPM += appliedTorque * dt / chassis.engineInertia;

    var s = sign(this.engineRPM);
    var friction = 0.2;
    var eb = -sign(this.engineRPM) * chassis.maxPowerTP.torque * chassis.engineBrakeCoefficient *
                  (friction + (1.0 - friction) * this.engineRPM / chassis.maxRPM);

    this.engineRPM += eb * dt / chassis.engineInertia;
    if (s != sign(this.engineRPM)) {
        this.engineRPM = 0;
    } else {
        appliedTorque += eb;
    }

    var tq = appliedTorque + chassis.engineInertia * (oldRPM - this.engineRPM) / dt;
    var force = tq * clutch * this.gear.ratio * chassis.differentialRatio * chassis.efficiency / chassis.wheelRadius;
    if (this.gear.index < 0) {
        force = -force;
    }

    this.wheel_force(2, force / 2);
    this.wheel_force(3, force / 2);

    brake *= chassis.breakingForce;
    this.wheel_brake(-1, brake);

    this.animate();

    var rpm = (this.engineRPM + oldRPM) / 2.0; // stabilize the fluctuations when the wheelsRpm and engineRPM
                                               // are very different
    var pitch = chassis.pitchMultiplier * (rpm - chassis.minimumRPM) / chassis.maxRPM;
    var vol = rpm / chassis.minimumRPM * 2.0;
    vol = (vol > 1 ? 1 : (vol < 0 ? 0 : vol));

    this.snd.set_pitch(this.onSource, pitch + chassis.basePitch[2]);
    this.snd.set_gain(this.onSource, chassis.relVolumes[2] * engine * vol);

    var speed = Math.abs(this.speed());
    this.snd.set_pitch(this.offSource, pitch + chassis.basePitch[1]);
    var v = speed / 5;
    this.snd.set_gain(this.offSource, chassis.relVolumes[1] * (1 - engine * vol) * Math.min(v, 1.0));

    var v = speed / 20;
    if (!clutch) {
        v = Math.min(v, rpm / chassis.maxRPM);
    }
    if (!running && this.idleSound > 0) {
        this.idleSound -= dt;
        this.idleSound = (this.idleSound < 0 ? 0 : this.idleSound);
    }
    this.snd.set_pitch(this.idleSource, pitch + chassis.basePitch[0]);
    this.snd.set_gain(this.idleSource, this.idleSound * chassis.relVolumes[0] * (1 - engine) * Math.max(vol - v, 0));

    if (rpm < 100) { //dead
        if (!this.clutchOverride) {
            this.clutch = 1.0;
            this.clutchState = ClutchState.Disengaged;
        }
        this.started = false;
    }
}

  • Set the sound emitter by setting the chassis.soundEmitter variable, and not by calling add_sound_emitter()


You can adjust the volume of the different sounds by changing the values of chassis.relVolumes, the first one for the idle sound.
Logged
ResidualVM 0.1.1 is OUT! www.residualvm.org

M7

  • Hero Member
  • *****
  • Posts: 736
  • newbie
Re: Vehicle script [version 1.3.3]
« Reply #70 on: June 10, 2013, 02:48:00 pm »

I still had sound wobling with 1.3.2 but with this new line you added...

    var id = this.get_geomob(0).get_joint(chassis.soundEmitter);
    this.idleSource = this.snd.create_source(id);
    this.onSource = this.snd.create_source(id);
    this.offSource = this.snd.create_source(id);

...the wobling is gone. Thanks!
Logged

M7

  • Hero Member
  • *****
  • Posts: 736
  • newbie
Re: Vehicle script [version 1.3.3]
« Reply #71 on: June 10, 2013, 10:27:23 pm »

I don't know if we can make special request but one thing that would be cool for the immersion factor, would be to include is a startup and turn off sound. I'd say the best way i'seen it done (at least for startup) is with the Lamborghini. When you hit forward, the startup sound plays but the car dont move forward like in many script, instead the startup sound play till the end of its time and only then can you rev the engine and and put it in gear.

 Have you ever thought to include this in future versions?
« Last Edit: June 11, 2013, 09:25:41 am by M7 »
Logged

giucam

  • Full Member
  • ***
  • Posts: 171
  • It's an ugly pile of bones... like me.
Re: Vehicle script [version 1.3.3]
« Reply #72 on: June 11, 2013, 06:38:09 am »

Yeah, but i don't have a good enough startup sound. What I'd want is the sound of the starter motor only, so i could make it blend with the existing sound.
Logged
ResidualVM 0.1.1 is OUT! www.residualvm.org

M7

  • Hero Member
  • *****
  • Posts: 736
  • newbie
Re: Vehicle script [version 1.3.3]
« Reply #73 on: June 11, 2013, 08:53:55 am »

Yeah might not be obvious to find a good startup sound to fit with the BMW set. But i beleive it's your intention to have this script as a possible basis for all ground vehicle since it has manual and automatic and the amazing new possibilities for sound.

Then people could adapt the script and sound to the specific vehicle they want to emulate. So even if you dont have the right startup sound for your specific car, i think it could be a good idea to release a version with these scripted in so that others could work on their sound set.

I know i want to try to get this script working with a tank. It might be tough to merge Cameni's tank steering script with this one. But to have the startup and turnoff already in will make it possibly easier in long term since i might not have to merge it twice.

As for updates, i found myself some tricks so to not start over at editing value of specific vehicle every times there's a new version. I copy/paste the script in a drawing program (in my case i use illustrator) so i can have a view of whole script at once. When there's an update, i copy paste the new version and then justapose the 2 versions. Much easier to find the new lines. Then i will copy only the new lines into my vehicle script.
Logged

giucam

  • Full Member
  • ***
  • Posts: 171
  • It's an ugly pile of bones... like me.
Re: Vehicle script [version 1.4.0]
« Reply #74 on: July 05, 2013, 12:34:41 pm »

Version 1.4.0:

Code: [Select]
[/*
    Vehicle script file
    Copyright (C) 2012 - 2013  Giulio Camuffo <giuliocamuffo@gmail.com>

    This library 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.0 of the License, or (at your option) any later version.

    This library 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/>.
*/

//see http://xtrac.outerraworld.com/trac.fcgi/wiki/vehicle for example and documentation

// VERSION 1.4.0

//thanks to hhrhhr for the code in calc_sound: http://www.outerra.com/forum/index.php?topic=1884.msg21810#msg21810

var chassis = {};

// --- Vehicle specific stuff ---
function chassis_setup() {
    var wheelparam = {
        radius: 0.30,
        width: 0.20,
        suspension_max: 0.1,
        suspension_min: -0.05,
        suspension_stiffness: 50.0,
        damping_compression: 0.06,
        damping_relaxation: 0.05,
        slip: 2.0,
        roll_influence: 0.1,
        rotation: -1
    };

    this.add_wheel('wheel_FL', wheelparam);
    this.add_wheel('wheel_FR', wheelparam);
    this.add_wheel('wheel_RL', wheelparam);
    this.add_wheel('wheel_RR', wheelparam);
   
    chassis.soundEmitter = "hood";
    chassis.soundRefDistance = 10;

    chassis.onSamples = [ { rpm: 859, sound: this.load_sound("v8/859_P.ogg") },
                          { rpm: 984, sound: this.load_sound("v8/984_P.ogg") },
                          { rpm: 1126, sound: this.load_sound("v8/1126_P.ogg") },
                          { rpm: 1476, sound: this.load_sound("v8/1476_P.ogg") },
                          { rpm: 2215, sound: this.load_sound("v8/2215_P.ogg") },
                          { rpm: 3324, sound: this.load_sound("v8/3324_P.ogg") },
                          { rpm: 4358, sound: this.load_sound("v8/4358_P.ogg") },
                          { rpm: 5712, sound: this.load_sound("v8/5712_P.ogg") },
                          { rpm: 6540, sound: this.load_sound("v8/6540_P.ogg") } ];

    chassis.offSamples = [ { rpm: 859, sound: this.load_sound("v8/859.ogg") },
                           { rpm: 984, sound: this.load_sound("v8/984.ogg") },
                           { rpm: 1126, sound: this.load_sound("v8/1126.ogg") },
                           { rpm: 1476, sound: this.load_sound("v8/1476.ogg") },
                           { rpm: 2215, sound: this.load_sound("v8/2215.ogg") },
                           { rpm: 3324, sound: this.load_sound("v8/3324.ogg") },
                           { rpm: 4358, sound: this.load_sound("v8/4358.ogg") },
                           { rpm: 5712, sound: this.load_sound("v8/5712.ogg") },
                           { rpm: 6540, sound: this.load_sound("v8/6540.ogg") } ];

    //engine properties -- modify these to change the engine behaviour
    chassis.wheelRadius = 0.24;

    chassis.torquePoints = [ { rpm: 500,  torque: 0},
                             { rpm: 1000, torque: 250},
                             { rpm: 2000, torque: 335},
                             { rpm: 3000, torque: 380},
                             { rpm: 4000, torque: 400},
                             { rpm: 5000, torque: 395},
                             { rpm: 6000, torque: 400},
                             { rpm: 7000, torque: 390},
                             { rpm: 8000, torque: 365},
                             { rpm: 9000, torque: 0  } ];

    chassis.forwardGears = [ { ratio: 4.06, shiftUp: 8000, shiftDown: -1   },
                             { ratio: 2.40, shiftUp: 8000, shiftDown: 4500 },
                             { ratio: 1.58, shiftUp: 8000, shiftDown: 5000 },
                             { ratio: 1.19, shiftUp: 8000, shiftDown: 5500 },
                             { ratio: 1.00, shiftUp: 8000, shiftDown: 6000 },
                             { ratio: 0.87, shiftUp: -1,   shiftDown: 6000 } ];
    chassis.reverseGears = [ { ratio: 4.68, shiftUp: -1, shiftDown: -1 } ];

    chassis.differentialRatio = 3.85;
    chassis.efficiency = 0.9;
    chassis.speedLimiter = -1; // maximum speed in m/s. a value < 0 means there's no limiter
    chassis.engineBrakeCoefficient = 0.4;
    chassis.breakingForce = 3000.0;
    chassis.pitchMultiplier = 1.5;
    chassis.engineInertia = 0.025;
    chassis.minimumRPM = 1100;
    chassis.minimum = 0.5;
    //end of engine properties

    return { mass:1570, steering:1.2, steering_ecf:700, centering: 5.0, centering_ecf: 40, com: { z:0.1 } };
}

function vehicle_setup() {
    this.set_fps_camera_pos( {x: -0.33,y: -0.40, z: 1.15});
    this.automaticTransmission = false;
    this.clutchMode = ClutchMode.Automatic;
}

function animate()
{
    this.animate_wheels();
}

// --- End of vehicle specific stuff ---



//invoked only the first time the model is loaded, or upon reload
function init_chassis() {
    this.setup = chassis_setup;
    var ret = this.setup();

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

    for (var i = 0; i < chassis.offSamples.length; ++i) {
        chassis.offSamples[i].source = this.add_sound_emitter(chassis.soundEmitter);
    }
    for (var i = 0; i < chassis.onSamples.length; ++i) {
        chassis.onSamples[i].source = this.add_sound_emitter(chassis.soundEmitter);
    }

    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.prev = gear;
        gear.next = prev;
        gear.index = -i - 1;
        prev = gear;
    }

    return ret;
}

var ClutchMode = { Manual: 0, Automatic: 1, Mixed: 2 };
var ClutchState = { Engaged: 0, Disengaged: 1, Engaging: 2, Disengaging: 3 };

//invoked for each new instance of the vehicle
function init_vehicle() {
    this.snd = this.sound();

    this.torque = engineTorque;
    this.shiftUp = shift_up;
    this.shiftDown = shift_down;
    this.selectGear = select_gear;
    this.updateAutomaticTransmission = automatic_transmission;
    this.automaticClutch = automatic_clutch;
    this.clutchValue = clutch_value;
    this.animate = animate;
    this.setup = vehicle_setup;
    this.calcSound = calc_sound;

    for (var i = 0; i < chassis.offSamples.length; ++i) {
        this.snd.set_ref_distance(chassis.offSamples[i].source, chassis.soundRefDistance);
        this.snd.play(chassis.offSamples[i].source, chassis.offSamples[i].sound, true, false);
        this.snd.set_gain(chassis.offSamples[i].source, 0);
    }
    for (var i = 0; i < chassis.onSamples.length; ++i) {
        this.snd.set_ref_distance(chassis.onSamples[i].source, chassis.soundRefDistance);
        this.snd.play(chassis.onSamples[i].source, chassis.onSamples[i].sound, true, false);
        this.snd.set_gain(chassis.onSamples[i].source, 0);
    }

    this.setup();

    this.clutch = 1.0;
    this.clutchState = ClutchState.Disengaged;
    this.started = false;
    this.gear = chassis.neutroGear;
    this.direction = 0;
    this.engineRPM = 0;
    this.starting = false;
    this.clutchOverride = false;
}

//invoked when engine starts or stops
function engine(start) {
    this.started = false;
    this.starting = start;
    this.idleSound = 1.0;
}

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

function action(key, value, dt)
{
    if (key == AAuxb1 && value == 0) {
        this.automaticTransmission = !this.automaticTransmission;
        this.log_inf("Automatic transmission " + (this.automaticTransmission ? "enabled" : "disabled"));
    }

    if (key == AAuxb2 || key == AAuxa2) {
        if (key == AAuxa2) {
            value = 1 - (value + 1) / 2;
        }
        value = 1 - value;
        value *= value;

        this.clutchState = (value == 1 ? ClutchState.Disengaged : ClutchState.Engaged);
        this.clutch = value;
        this.clutchOverride = value != 1;
    }

    if (value == 1 && !this.automaticTransmission) {
        switch(key) {
            case AShiftUp:
                this.shiftUp();
                break;
            case AShiftDown:
                this.shiftDown();
                break;
            default:
                break;
        }
    }
}

function select_gear(gear)
{
    if (this.gear == gear) {
        return;
    }

    var i = this.gear.index;
    this.gear = gear;
    if (i == 0 && this.clutchMode == ClutchMode.Automatic && (this.started || this.starting)) {
        this.clutchState = ClutchState.Engaging;
    }
    this.log_inf("gear " + i + " => " + this.gear.index);
}

function shift_up()
{
    var i = this.gear.index;
    if (this.gear.next) {
        this.selectGear(this.gear.next);
    } else if (i == 0) {
        this.selectGear(chassis.forwardGears[0]);
    } else if (i == -1) {
        this.selectGear(chassis.neutroGear);
    }
}

function shift_down()
{
    var i = this.gear.index;
    if (this.gear.prev) {
        this.selectGear(this.gear.prev);
    } else if (i == 0) {
        this.selectGear(chassis.reverseGears[0]);
    } else if (i == 1) {
        this.selectGear(chassis.neutroGear);
    }
}

function automatic_transmission(engine)
{
    if (this.engineRPM < 10 && this.gear.index != 0) {
        this.direction = 0;
        this.selectGear(chassis.neutroGear);
    }
    if (engine != 0.0) {
        if (sign(engine) != this.direction) {
            this.direction = sign(engine);
            this.selectGear(chassis.neutroGear);
            if (this.direction == 1.0) {
                this.selectGear(chassis.forwardGears[0]);
            } else if (this.direction == -1.0) {
                this.selectGear(chassis.reverseGears[0]);
            }
        }
    }

    if (this.clutch != 0) {
        if (this.engineRPM > this.gear.shiftUp && this.gear.next) {
            this.shiftUp();
        } else if (this.engineRPM < this.gear.shiftDown && this.gear.prev) {
            this.shiftDown();
        }
    }
}

function automatic_clutch(wheelsRpm)
{
    var clutched = (this.clutchState == ClutchState.Disengaged  || this.clutchState == ClutchState.Disengaging) && this.gear.index != 0;
    var clutchRPM = chassis.minimumRPM * 7 / 4;
    var w = wheelsRpm * this.gear.ratio * chassis.differentialRatio;

    if (this.clutchMode == ClutchMode.Automatic && !this.clutchOverride && (this.started || this.starting)) {
        if (clutched && this.engineRPM < chassis.minimumRPM && w < chassis.minimumRPM) {
            this.clutchState = ClutchState.Engaging;
        } else if (!clutched && (this.engineRPM > clutchRPM || w > chassis.minimumRPM)) {
            this.clutchState = ClutchState.Disengaging;
        }
    }

    if (this.clutchState == ClutchState.Disengaging) {
        if (this.gear.index != 0) {
            this.clutch = (w > chassis.minimumRPM ? chassis.minimumRPM : w) / chassis.minimumRPM;

            // This makes an horizontal S-like shape. (mirrored, like Z)
            var f = this.clutch * 2;
            if (f < 0.5) {
                this.clutch = -(f * f * f * f - 1) / 5;
            } else {
                f = f - 1;
                this.clutch = (f * f * f * f) + 0.2;
            }
            this.clutch += 0.4;
            var r = (this.engineRPM - chassis.minimumRPM) / clutchRPM;
            r = (r > 1 ? 1 : (r < 0 ? 0 : r));
            r = Math.sqrt(r);
            this.clutch *= r
        } else {
            this.clutch = 1;
        }

        if (this.clutch >= 1) {
            this.clutch = 1;
            this.clutchState = ClutchState.Disengaged;
        }
    } else if (this.clutchState == ClutchState.Engaging) {
        this.clutch = 0;
        this.clutchState = ClutchState.Engaged;
    }
    return this.clutch;
}

function clutch_value(wheelsRpm)
{
    var clutch = this.clutch;
    if (this.clutchMode != ClutchMode.Manual && !this.clutchOverride) {
        clutch = this.automaticClutch(wheelsRpm);
    }
    if (this.gear.index == 0) {
        clutch = 0;
    }
    return clutch;
}

const PI_2 = Math.PI / 2.0;

function calc_sound(rpm, volmul, list)
{
    var l = list.length;

    if (rpm <= list[1].rpm) {
        // only first sample
        this.snd.set_pitch(list[1].source, rpm / list[1].rpm);
        this.snd.set_gain(list[1].source, volmul * 1.0);
        for (var i = 2; i < l; i++) {
            this.snd.set_gain(list[i].source, 0.0);
        }
    } else if (rpm > list[l - 2].rpm) {
        this.snd.set_pitch(list[l - 2].source, rpm / list[l - 2].rpm);
        this.snd.set_gain(list[l - 2].source, volmul * 1.0);
        for (var i = 0; i < l - 2; i++) {
            this.snd.set_gain(list[i].source, 0);
        }
    } else {
        for (var i = 0; i < l - 1; ++i) {
            var sample = list[i];
            var next = list[i + 1]

            if (rpm > next.rpm || rpm <= list[i - 1].rpm) {
                this.snd.set_gain(sample.source, 0.0);
            } else if (rpm > sample.rpm) {
                var drpm = next.rpm - sample.rpm;
                var vol_l = (next.rpm - rpm) / drpm;
                var vol_h = (rpm - sample.rpm) / drpm;

                this.snd.set_gain(sample.source, volmul * Math.sin(vol_l * PI_2));
                this.snd.set_gain(next.source, volmul * Math.sin(vol_h * PI_2));

                this.snd.set_pitch(sample.source, rpm / sample.rpm);
                this.snd.set_pitch(next.source, rpm / next.rpm);
            }
        }
    }
}

//invoked each frame to handle the inputs and animate the model
function update_frame(dt, engine, brake, steering) {
    steering *= 0.6;
    this.steer(-2, steering);

    if (this.automaticTransmission) {
        this.updateAutomaticTransmission(engine);
    }

    var wheelsRpm = Math.abs(this.max_rpm());
    if (sign(this.speed()) != sign(this.gear.index) && this.gear.index != 0) {
        wheelsRpm = 0;
    }

    if (engine < 0) {
        engine = -engine;
    }

    var appliedTorque = 0;
    if (this.starting) {
        if (this.engineRPM > chassis.minimumRPM) {
            this.starting = false;
            this.started = true;
        } else {
            appliedTorque = 200 * (1 - this.engineRPM / chassis.minimumRPM);
        }
    }

    var oldRPM = this.engineRPM;
    var clutch = this.clutchValue(wheelsRpm);
    this.engineRPM = this.engineRPM * (1 - clutch) + wheelsRpm * clutch * this.gear.ratio * chassis.differentialRatio;

    var s = sign(this.engineRPM);
    var friction = 0.2;
    var eb = -s * chassis.maxPowerTP.torque * chassis.engineBrakeCoefficient *
              (friction + (1.0 - friction) * this.engineRPM / chassis.maxRPM);
    this.engineRPM += eb * dt / chassis.engineInertia;

    if (s != sign(this.engineRPM)) {
        this.engineRPM = 0;
    } else {
        appliedTorque += eb;
    }

    var running = this.started || this.starting;
    if (running) {
        if (this.engineRPM < chassis.minimumRPM) {
            var e = (chassis.minimumRPM - this.engineRPM) * chassis.minimum / this.torque(this.engineRPM);
            if (engine < e) {
                engine = (e > 1 ? 1 : e);
            }
        }
        if (chassis.speedLimiter < 0 || Math.abs(this.speed()) < chassis.speedLimiter) {
            appliedTorque += engine * this.torque(this.engineRPM);
        }
    } else {
        engine = 0;
    }

    this.engineRPM += (1 - clutch) * appliedTorque * dt / chassis.engineInertia;

    var tq = appliedTorque + chassis.engineInertia * (oldRPM - this.engineRPM) / dt;
    var force = tq * clutch * this.gear.ratio * chassis.differentialRatio * chassis.efficiency / chassis.wheelRadius;
    if (this.gear.index < 0) {
        force = -force;
    }

    this.wheel_force(2, force / 2);
    this.wheel_force(3, force / 2);

    brake *= chassis.breakingForce;
    this.wheel_brake(-1, brake);

    this.animate();

    var rpm = (this.engineRPM + oldRPM) / 2.0; // stabilize the fluctuations when the wheelsRpm and engineRPM
                                               // are very different

    this.calcSound(rpm, engine, chassis.onSamples);
    this.calcSound(rpm, 1 - engine, chassis.offSamples);

    if (rpm < 100) { //dead
        if (!this.clutchOverride) {
            this.clutch = 1.0;
            this.clutchState = ClutchState.Disengaged;
        }
        this.started = false;
    }
}

  • Added the logic to use many samples for the sound, so it is more realistic. Thanks to hhrhhr.
« Last Edit: July 05, 2013, 12:39:54 pm by giucam »
Logged
ResidualVM 0.1.1 is OUT! www.residualvm.org
Pages: 1 ... 3 4 [5] 6 7 8