DTS/3dsmax/Creating a Simple Flying Vehicle

From TDN

This page is a Work In Progress.


Introduction

This tutorials will get you to create a simple flying vehicle, using some of the basic datablock settings.
이 안내서는 기본 데이터 블럭 설정들을 이용하여 간단한 비행체를 만들도록 도와준다.
The advance stages are more centered around specific vehicle types, while this will work for pretty much any flying vehicle.
이글은 특별한 승용 타입에 대해서 보다 집중하고 있으며 비행체에 대해서 많은 역할을 할 것이다.

Scripting is required for vehicles, mainly to get the player to use and control it.
승용물을 위한 스크립트들은 어떻게 사용하고 컨트롤할 것인가 대부분이다.

You will effectively use many areas that require some familiarity with, you must be familiar with the following; correctly export model, understand particle scripts, understand sound scripts, and have some general scripting abilities.
여러 부분에서 효과적으로 사용하려면 정확하게 모델을 출력하는 것, 스크립트, 사운드 스크립트의 이해 그리고 일반적인 스크립팅 능력들에 익숙해져야한다.

The DTS Scripting Guide is also a good resource to consult to find out more about the datablock structure of vehicles.
DTS Scripting Guide는 승용물의 데이터 블럭 구조를 참조하기 위한 좋은 소스이다.

Contents


Requirements

Before you start off on this little question, please make sure you that you have a stage version of your game running, and you have particles, sounds and models to work with. This tutorial does not cover how to go about modeling or preparing sounds.

시작하기 전에 실행되는 게임 버전에 파티클, 사운드, 모델들이 있어야한다. 이 안내서는 모델을 만들거나 사운드를 준비하는 과정을 다루지 않는다.

The model

An example vehicle created in 3DS Max 8.
Enlarge
An example vehicle created in 3DS Max 8.
The model for a simple flying vehicle, can be pretty much anything, from a sphere to a box or a teapot if you wanted to. More complex spaceships are better, and many can be found for free over the internet for rapid testing. Your model will need to meet the standard DTS requiremens as set out in the previous lessons.

Nodes

The nodes is what will really give your vehicles power, they are the link between your script and your model. The more nodes you place, the more complex your vehicle and datablock (and in some cases your controls) will become. You will need the typical nodes required by a mesh; including detail, collision, bounds, etc... Setup your model with a good level of LOD, as this will make it far more efficient.

Contrail#
This emitter creates contrails, which are those little wisps that you see that emit from the tips of wings on airplanes.
Example Usage - Contrail0, Contrail1, etc...

JetNozzle#
This node tells the engine where to emit a jet engine exhaust from.
Example Usage – JetNozzle0, JetNozzle1, etc...

Light# - Light Emitter Marker
There are nodes to fix lights onto your ship.
Example Usage – Light0, Light1, etc...

LOS-# – Line of Sight marker
Markers for line of sight, or 'bullet' collision shapes. Uses # 9 through 15.
Example Usage – LOS-9, LOS-10, LOS-15, etc...

LOSCol – Line of sight geometry
Geometry for line of sight collision. Uses # 9 through 15
Example Usage – LOSCol-9, LOSCol-1, LOSCol-15, etc...

mount# - Mount Nodes Mount nodes are used for two things with vehicles, either as a player attachment point or as a weapon location. Typically mount nodes will be used or assigned to the following functions:

mount0 – pilot of vehicle
mount1 – navigator/gunner
mount2 – passenger
mount3 – passenger
mount4 – passenger
mount5 – passenger
mount6 – passenger
mount7 – passenger
mount8 – passenger
mount9 – Weapon (bomb bay)
mount10 – Weapon (gun)

Smoke_node# – Particle Emitter Placement Marker
These nodes (named “smoke_node#) denote the location of a particle system to the engine.
"smoke_node"라고 불리는 노드들은 소립자 시스템의 위치를 엔진에게 알려준다.

This particular particle system emits particles based on the amount of damage that your vehicle has taken. 

이 소립자 시스템은 승용물이 받은 충격의 정도에 기초한 양의 소립자들을 방출한다.
To place this node on your vehicle, create a dummy helper object and link it to the location on your mesh where you would like the damage smoke to emit from in the game.
승용물에 연기 노드를 위치시키는 방법은 하나의 더미 헬퍼 객체를 만들고 그 객체를 게임에서 충격으로 인해 연기가 날 위치에 연결해주는 것이다.
Example Usage – Smoke_node0, Smoke_node1, etc...
용례- Smoke_node0, Smoke_node1, etc...

This is an example of a fully 'noded' ship (Only thing missing is the multires mesh and further detail nodes) Image:Flying_nodes.png
Note: Node setup may be slightly different for your exporter. Check the documentation (if any) that came with your exporter.

Vehicle Datablock

Provided below is the vehicle datablock for your fighter. You can simply copy and paste this info into ~/server/scripts/vehicles/ under fighter.cs. You need to make sure you relink the shape files and names are correct. It is commented to help you out with certain features.

//-----------------------------------------------------------------------------
// Flying Vehicle Shape File
//-----------------------------------------------------------------------------
// Vehicle Name: Fighter
// Version: 1.0

datablock FlyingVehicleData(TKFighter)
{
    spawnOffset                = "0 0 2";
    emap                           = true;
    category                      = "Vehicles";
    shapeFile                     = "~/data/shapes/vehicles/tkfighter.dts";  // Shape File
    multipassenger            = false;
    computeCRC                = true;
                	
    //debrisShapeName     = "~/data/shapes/vehicles/tkfighter_debris.dts";
    //debris                        = FighterShapeDebris;
    //renderWhenDestroyed     = false;

    drag                             = 0.25;
    density                         = 1.0;

// Mounting Details
    numMountPoints           = 1;
    maxMountSpeed           = 0.1;
    mountDelay                   = 8;
    dismountDelay              = 1;
    stationaryThreshold      = 0.5;
    maxDismountSpeed      = 0.1;
    mountPose[0] = "Sitting";
    mountPointTransform[0] = "0 0 0 0 0 1 0";
    isProtectedMountPoint[0]  = false;
    minMountDist			= 2;

// Camera Settings
    cameraOffset                = 1.5;  // Vertical offset from camera mount point
	cameraMaxDist            = 16;
	cameraOffset              = 3.65;
	cameraLag                  = 0.1;
    cameraRoll                       = true; // Roll the camera with the vehicle

// Explosions                 = FighterVehicleExplosion; // Particle Data?
    explosionDamage           = 10.5;
    explosionRadius           = 15.0;

    maxDamage                 = 50.40;
    destroyedLevel            = 50.40;

// Afterburner and any energy weapon pool        			
    energyPerDamagePoint      = 160;
    maxEnergy                 = 280;
    rechargeRate              = 0.8;

    minDrag                   = 40; // Linear Drag (eventually slows you down when not thrusting...constant drag)
    rotationalDrag            = 20; // Anguler Drag (dampens the drift after you stop moving the mouse...also tumble drag)

    maxAutoSpeed	            = 10; // Autostabilizer kicks in when less than this speed. (meters/second)
    autoAngularForce          = 400; // Angular stabilizer force (this force levels you out when autostabilizer kicks in)
    autoLinearForce           = 300; // Linear stabilzer force (this slows you down when autostabilizer kicks in)
    autoInputDamping          = 0.55; // Dampen control input so you don't` whack out at very slow speeds

// Maneuvering
    maxSteeringAngle          = 4; // Max radiens you can rotate the wheel. Smaller number is more maneuverable.
    horizontalSurfaceForce    = 20; // Horizontal center "wing" (provides "bite" into the wind for climbing/diving and turning)

    verticalSurfaceForce      = 20; // Vertical center "wing" (controls side slip. lower numbers make MORE slide.)
    maneuveringForce          = 6400; // Horizontal jets (W,S,D,A key thrust)
    steeringForce             = 500; // Steering jets (force applied when you move the mouse)
    steeringRollForce         = 200; // Steering jets (how much you heel over when you turn)
    rollForce        		= 10; // Auto-roll (self-correction to right you after you roll/invert)
    hoverHeight        		= 0.5; // Height off the ground at rest
    createHoverHeight         = 0.5; // Height off the ground when created
    maxForwardSpeed        	= 90; // speed in which forward thrust force is no longer applied (meters/second)

// Turbo Jet
    jetForce        		= 3000; // Afterburner thrust (this is in addition to normal thrust)
    minJetEnergy        	= 28; // Afterburner can't be used if below this threshhold.
    jetEnergyDrain        	= 2.8; // Energy use of the afterburners (low number is less drain...can be fractional)
    vertThrustMultiple        = 3.0; // Auto stabilize speed

// Rigid body
    mass                      = 100; // Mass of the vehicle
    integration               = 3; // Physics integration: TickSec/Rate
    collisionTol              = 0.6; // Collision distance tolerance
    contactTol                = 0.4; // Contact velocity tolerance

    bodyFriction              = 0; // Don't mess with this.
    bodyRestitution           = 0.8; // When you hit the ground, how much you rebound. (between 0 and 1)
    minRollSpeed              = 2000; // Don't mess with this.
    softImpactSpeed        	= 3; // Sound hooks. This is the soft hit.
    hardImpactSpeed        	= 15;// Sound hooks. This is the hard hit.

// Ground Impact Damage (uses DamageType::Ground)
    minImpactSpeed        	= 10; // If hit ground at speed above this then it's an impact. Meters/second
    speedDamageScale          = 0.06;

// Object Impact Damage (uses DamageType::Impact)
    collDamageThresholdVel    = 23.0;
    collDamageMultiplier      = 0.02;

// Contrails
    minTrailSpeed        	= 15;      // The speed your contrail shows up at.
    trailEmitter        	= FighterContrailEmitter;
    forwardJetEmitter         = FighterFJetEmitter;
    downJetEmitter        	= FighterDJetEmitter;

//Sounds
    jetSound        		= FighterThrustSound;
    engineSound        	      = FighterEngineSound;
    //softImpactSound        	= FighterSoftImpactSound;
    //hardImpactSound        	= FighterHardImpactSound;

    //softSplashSoundVelocity			= 10.0;
    //mediumSplashSoundVelocity		= 15.0;
    //hardSplashSoundVelocity			= 20.0;
    //exitSplashSoundVelocity			= 10.0;

    //exitingWater        	= FighterExitWaterMediumSound;
    //impactWaterEasy        	= FighterImpactWaterSoftSound;
    //impactWaterMedium       = FighterImpactWaterMediumSound;
    //impactWaterHard        	= FighterImpactWaterMediumSound;
    //waterWakeSound        	= FighterWakeMediumSplashSound;

//  dustEmitter        	      = FighterLiftoffDustEmitter;

    triggerDustHeight         = 4.0;
    dustHeight        		= 1.0;

//  damageEmitter[0]          = LightDamageSmoke;
//  damageEmitter[1]          = HeavyDamageSmoke;
//  damageEmitter[2]          = MediumDamageSmoke;

    damageEmitterOffset[0]	= "0.0 -3.0 0.0 ";
    damageLevelTolerance[0]	= 0.3;
    damageLevelTolerance[1]	= 0.7;
    numDmgEmitterAreas        = 3;
        		
// Weapons and Ammo
    //max[RocketAmmo]        	= 1000;

    //splashEmitter[0]        = VehicleFoamDropletsEmitter;
    //splashEmitter[1]        = VehicleFoamEmitter;

    //shieldImpact        	= VehicleShieldImpact;

    //cmdCategory        	= "Tactical";
    //cmdIcon        		= CMDFlyingScoutIcon;
    //cmdMiniIconName        	= "commander/MiniIcons/com_scout_grey";
    //targetNameTag        	= 'Fighter';
    //targetTypeTag        	= 'FlyingVehicle';
    //sensorData        	= AWACPulseSensor;
    //sensorRadius        	= AWACPulseSensor.detectRadius;
    //sensorColor        	= "255 194 9";
   maxInvRocketLauncher = "1";
   maxInvRocketLauncherAmmo = "200";


                	
    checkRadius               = 5.5;
    observeParameters         = "0 0 1";
    shieldEffectScale         = "0.937 1.125 0.60";
};

//----------------------------------------------------------------------------------------
// Game Functions
//----------------------------------------------------------------------------------------

function Scout::create(%block)    //for when you create it
{
	%obj = new FlyingVehicle() {
		dataBlock = %block;
	};
   return(%obj);
}

function Scout::onAdd(%this,%obj)  //initialize everything you add to it
{
        %obj.mountable = true;       //bydj --important - without this you can't mount your vehicle
        //add items to spawn
        %obj.setInventory(RocketLauncher, 1);
        %obj.setInventory(RocketLauncherAmmo, 200);
        %obj.mountImage(ChaingunImage, 0);  //mounts weapon image to mount point on vehicle //needed?
         //%obj.mountImage(Chaingun2Image, 2);  //mounts weapon image to mount point on vehicle
   
   //set levels of health/energy
	%obj.setEnergyLevel(%this.MaxEnergy);
	%obj.setRechargeRate(%this.rechargeRate);
	%obj.setRepairRate(%this.repairRate);
}

function Flyer::onDamage(%this, %obj, %delta)
{
    Parent::onDamage(%this, %obj);
    %currentDamage = %obj.getDamageLevel();
    if(%currentDamage > %obj.destroyedLevel)
    {
        if(%obj.getDamageState() !$= "Destroyed")
        {
        if(%obj.respawnTime !$= "")
        %obj.marker.schedule = %obj.marker.data.schedule(%obj.respawnTime, "respawn", %obj.marker); 
        %obj.setDamageState(Destroyed);
        }
    }
    else
    {
        if(%obj.getDamageState() !$= "Enabled")
        %obj.setDamageState(Enabled);
    }
}

Different Types of Flying Vehicles

Vehicle types will be further covered in the advanced tutorial. As a word of advice, you should setup your vehicle carefully. By setup I mean place your nodes in a structure that best uses the datablock.

Special Effects Overview

The special effects, including sounds, particles and lights should be put together into a common vehicle fx script, as to minimize the duplication of effects and allows for easy testing. The file setup we're going to use for this tutorial will be named vehicle_spec_fx.cs placed in /data/server/scripts/vehicles/.

The following scripts are part of vehicle_spec_fx.cs, for the sake of this tutorial, we're going to briefly cover the main areas of these scripts. There is more information about these in the DTS Script Guide and WorldEditor section.

Sound Setup

The sounds are pretty simple to setup. Make sure you you're using the right description, in this case it will mostly be AudioDefaultLooping3d which is defined in ~/client/scripts/audioprofiles.cs but we will create a global for the vehicles, make a new type of sound and link it into the audio profile.

...
$VehiclesAudioType = 6;  // Audio Type for vehicles.

//-----------------------------------------------------------------------------
new AudioDescription(AudioDefaultLooping3d)
{
volume   = 10.0;
   isLooping = true;
   is3D     = false;
   type     = $VehiclesAudioType;  // Points to AudioType for Vehicles
};

Now you can add all the sounds you want really as shown below:

//----------------------------------------------------------------------------------------
// Sound Details
//----------------------------------------------------------------------------------------

//FighterSoftImpactSound;
//FighterHardImpactSound;

//FighterExitWaterMediumSound;
//FighterImpactWaterSoftSound;
//FighterImpactWaterMediumSound;
//FighterImpactWaterMediumSound;
//FighterWakeMediumSplashSound;

// Audio Profiles
datablock AudioProfile(FighterThrustSound)
{
  fileName = "~/data/sound/vehicles/fighterUp.wav";
  description = AudioDefaultLooping3d;
  preload = true;
};
datablock AudioProfile(FighterEngineSound)
{
  fileName = "~/data/sound/vehicles/fighterEngine.wav";
  description = AudioDefaultLooping3d;
  preload = true;
};
datablock AudioProfile(FighterDiveSound)
{
  fileName = "~/data/sound/vehicles/fighterDown.wav";
  description = AudioDefaultLooping3d;
  preload = true;
};
datablock AudioProfile(FighterManeuverSound)
{
  fileName = "~/data/sound/vehicles/fighterManeuver.wav";
  description = AudioDefaultLooping3d;
  preload = true;
};

Particle Setup

You must define and exec/load the appropriate ParticleEmitterdata blocks prior to invoking and linking to them in the vehicle datablock for contrails as an example.
Particles are something that can be recycled from previous particle systems, so this section is somewhat up to you as to how you structure your systems and emitters. You should place your images in ~/data/particles/, since you won't end up with thousands of particles, its safe to keep them in one single folder. You will need images for the following (Marked are the images that can be recycled):

Explosion: Debris and Vehicle Explosion - Best make these new.
Dust: Liftoff dust - New or Recycled.
Smoke: Heavy, Medium, Light - Recycled.
Contrail: Jet emitters, Contrails - New.
Movement: Up, Down, Left, Right, Dive - New.
Other: Water Splash, foam,

//----------------------------------------------------------------------------------------
// Particle Details
//----------------------------------------------------------------------------------------
//FighterVehicleExplosion;
//FighterLiftoffDustEmitter;
//--------------------------------------------------------------
// DEBRIS SMOKE PARTICLES
//--------------------------------------------------------------

datablock ParticleData(DebrisSmokeParticle)
{
   dragCoeffiecient     = 4.0;
   gravityCoefficient   = -0.00;
   inheritedVelFactor   = 0.2;
   lifetimeMS           = 1000;  
   lifetimeVarianceMS   = 100;
   textureName          = "~/data/particles/smokeParticle";
   useInvAlpha =     true;
   spinRandomMin = -50.0;
   spinRandomMax = 50.0;
   colors[0]     = "0.3 0.3 0.3 0.0";
   colors[1]     = "0.3 0.3 0.3 1.0";
   colors[2]     = "0.0 0.0 0.0 0.0";
   sizes[0]      = 2;
   sizes[1]      = 3;
   sizes[2]      = 5;
   times[0]      = 0.0;
   times[1]      = 0.7;
   times[2]      = 1.0;
};

datablock ParticleEmitterData(DebrisSmokeEmitter)
{
   ejectionPeriodMS = 25;
   periodVarianceMS = 5;
   ejectionVelocity = 1.0;
   velocityVariance = 0.5;
   thetaMin         = 10.0;
   thetaMax         = 30.0;
   useEmitterSizes = true;
   particles = "DebrisSmokeParticle";
};

//--------------------------------------------------------------
// SMALL HEAVY DAMAGE SMOKE
//--------------------------------------------------------------

datablock ParticleData(SmallHeavyDamageSmokeParticle)
{
   dragCoefficient      = 0.0;
   gravityCoefficient   = -0.01;
   inheritedVelFactor   = 0.5;
   constantAcceleration = 0.0;
   lifetimeMS           = 1000;
   lifetimeVarianceMS   = 200;
   useInvAlpha          = true;
   spinRandomMin        = -90.0;
   spinRandomMax        = 90.0;
   textureName          = "~/data/particles/smokeParticle";
   colors[0]     = "0.7 0.7 0.7 0.0";
   colors[1]     = "0.3 0.3 0.3 1.0";
   colors[2]     = "0.0 0.0 0.0 0.0";
   sizes[0]      = 0.2;
   sizes[1]      = 0.8;
   sizes[2]      = 2.0;
   times[0]      = 0.0;
   times[1]      = 0.5;
   times[2]      = 1.0;
};

datablock ParticleEmitterData(SmallHeavyDamageSmoke)
{
   ejectionPeriodMS = 25;
   periodVarianceMS = 0;
   ejectionVelocity = 3.0;
   velocityVariance = 0.0;
   ejectionOffset   = 0.0;
   thetaMin         = 0;
   thetaMax         = 35;
   overrideAdvances = false;
   particles = "SmallHeavyDamageSmokeParticle";
};

//--------------------------------------------------------------
// HEAVY DAMAGE SMOKE
//--------------------------------------------------------------

datablock ParticleData(HeavyDamageSmokeParticle)
{
   dragCoefficient      = 0.0;
   gravityCoefficient   = -0.01;
   inheritedVelFactor   = 0.5;
   constantAcceleration = 0.0;
   lifetimeMS           = 2000;
   lifetimeVarianceMS   = 200;
   useInvAlpha          = true;
   spinRandomMin        = -90.0;
   spinRandomMax        = 90.0;
   textureName          = "~/data/particles/smokeParticle";
   colors[0]     = "0.7 0.7 0.7 0.0";
   colors[1]     = "0.3 0.3 0.3 0.7";
   colors[2]     = "0.0 0.0 0.0 0.0";
   sizes[0]      = 1.2;
   sizes[1]      = 2.6;
   sizes[2]      = 4.0;
   times[0]      = 0.0;
   times[1]      = 0.5;
   times[2]      = 1.0;
};

datablock ParticleEmitterData(HeavyDamageSmoke)
{
   ejectionPeriodMS = 20;
   periodVarianceMS = 6;
   ejectionVelocity = 4.0;
   velocityVariance = 0.5;
   ejectionOffset   = 1.5;
   thetaMin         = 0;
   thetaMax         = 35;
   overrideAdvances = false;
   particles = "HeavyDamageSmokeParticle";
};

//--------------------------------------------------------------
// SMALL LIGHT DAMAGE SMOKE
//--------------------------------------------------------------

datablock ParticleData(SmallLightDamageSmokeParticle)
{
   dragCoefficient      = 0.0;
   gravityCoefficient   = -0.01;
   inheritedVelFactor   = 0.5;
   constantAcceleration = 0.0;
   lifetimeMS           = 1000;
   lifetimeVarianceMS   = 200;
   useInvAlpha          = true;
   spinRandomMin        = -90.0;
   spinRandomMax        = 90.0;
   textureName          = "~/data/particles/smokeParticle";
   colors[0]     = "0.7 0.7 0.7 0.0";
   colors[1]     = "0.5 0.5 0.5 0.4";
   colors[2]     = "0.3 0.3 0.3 0.0";
   sizes[0]      = 0.8;
   sizes[1]      = 1.6;
   sizes[2]      = 3.0;
   times[0]      = 0.0;
   times[1]      = 0.5;
   times[2]      = 1.0;
};

datablock ParticleEmitterData(SmallLightDamageSmoke)
{
   ejectionPeriodMS = 40;
   periodVarianceMS = 0;
   ejectionVelocity = 3.0;
   velocityVariance = 0.0;
   ejectionOffset   = 0.0;
   thetaMin         = 0;
   thetaMax         = 35;
   overrideAdvances = false;
   particles = "SmallLightDamageSmokeParticle";
};

//--------------------------------------------------------------
// LIGHT DAMAGE SMOKE
//--------------------------------------------------------------

datablock ParticleData(LightDamageSmokeParticle)
{
   dragCoefficient      = 0.0;
   gravityCoefficient   = -0.01;
   inheritedVelFactor   = 0.5;
   constantAcceleration = 0.0;
   lifetimeMS           = 1500;
   lifetimeVarianceMS   = 200;
   useInvAlpha          = true;
   spinRandomMin        = -90.0;
   spinRandomMax        = 90.0;
   textureName          = "~/data/particles/smokeParticle";
   colors[0]     = "0.7 0.7 0.7 0.0";
   colors[1]     = "0.5 0.5 0.5 0.7";
   colors[2]     = "0.3 0.3 0.3 0.0";
   sizes[0]      = 1.2;
   sizes[1]      = 2.6;
   sizes[2]      = 4.0;
   times[0]      = 0.0;
   times[1]      = 0.5;
   times[2]      = 1.0;
};

datablock ParticleEmitterData(LightDamageSmoke)
{
   ejectionPeriodMS = 30;
   periodVarianceMS = 6;
   ejectionVelocity = 4.0;
   velocityVariance = 0.5;
   ejectionOffset   = 1.5;
   thetaMin         = 0;
   thetaMax         = 35;
   overrideAdvances = false;
   particles = "LightDamageSmokeParticle";
};

//--------------------------------------------------------------
// Contrail
//--------------------------------------------------------------
datablock ParticleData(FighterContrailParticle)
{
  dragCoefficient      = 1.5;
  gravityCoefficient   = 0;
  inheritedVelFactor   = 0.2;
  constantAcceleration = 0.0;
  lifetimeMS           = 3000;
  lifetimeVarianceMS   = 0;
  textureName          = "~/data/particles/trailParticle";
  colors[0]     = "0.6 0.6 0.6 0.5";
  colors[1]     = "0.2 0.2 0.2 0";
  sizes[0]      = 0.6;
  sizes[1]      = 5;
};

datablock ParticleEmitterData(FighterContrailEmitter)
{
  ejectionPeriodMS = 50;
  periodVarianceMS = 0;
  ejectionVelocity = 1;
  velocityVariance = 1.0;
  ejectionOffset   = 0.0;
  thetaMin         = 0;
  thetaMax         = 180;
  phiReferenceVel  = 0;
  phiVariance      = 360;
  overrideAdvances = false;
  particles = "FighterContrailParticle";
};


//--------------------------------------------------------------
// Movement
//--------------------------------------------------------------

// Forward
datablock ParticleData(FighterFJetParticle)
{
  dragCoefficient      = 1.5;
  gravityCoefficient   = 0;
  inheritedVelFactor   = 0.2;
  constantAcceleration = 0.0;
  lifetimeMS           = 3000;
  lifetimeVarianceMS   = 0;
  textureName          = "~/data/particles/forwardParticle";
  colors[0]     = "0.6 0.6 0.6 0.5";
  colors[1]     = "0.2 0.2 0.2 0";
  sizes[0]      = 0.6;
  sizes[1]      = 5;
};


datablock ParticleEmitterData(FighterFJetEmitter)
{
  ejectionPeriodMS = 50;
  periodVarianceMS = 0;
  ejectionVelocity = 1;
  velocityVariance = 1.0;
  ejectionOffset   = 0.0;
  thetaMin         = 0;
  thetaMax         = 180;
  phiReferenceVel  = 0;
  phiVariance      = 360;
  overrideAdvances = false;
  particles = "FighterFJetParticle";
};

// Backward
datablock ParticleData(FighterBackParticle)
{
  dragCoefficient      = 1.5;
  gravityCoefficient   = 0;
  inheritedVelFactor   = 0.2;
  constantAcceleration = 0.0;
  lifetimeMS           = 3000;
  lifetimeVarianceMS   = 0;
  textureName          = "~/data/particles/backwardParticle";
  colors[0]     = "0.6 0.6 0.6 0.5";
  colors[1]     = "0.2 0.2 0.2 0";
  sizes[0]      = 0.6;
  sizes[1]      = 5;
};

datablock ParticleEmitterData(FighterBackEmitter)
{
  ejectionPeriodMS = 50;
  periodVarianceMS = 0;
  ejectionVelocity = 1;
  velocityVariance = 1.0;
  ejectionOffset   = 0.0;
  thetaMin         = 0;
  thetaMax         = 180;
  phiReferenceVel  = 0;
  phiVariance      = 360;
  overrideAdvances = false;
  particles = "FighterBackParticle";
};

//Upwards
datablock ParticleData(FighterUJetParticle)
{
  dragCoefficient      = 1.5;
  gravityCoefficient   = 0;
  inheritedVelFactor   = 0.2;
  constantAcceleration = 0.0;
  lifetimeMS           = 3000;
  lifetimeVarianceMS   = 0;
  textureName          = "~/data/particles/upParticle";
  colors[0]     = "0.6 0.6 0.6 0.5";
  colors[1]     = "0.2 0.2 0.2 0";
  sizes[0]      = 0.6;
  sizes[1]      = 5;
};

datablock ParticleEmitterData(FighterUJetEmitter)
{
  ejectionPeriodMS = 50;
  periodVarianceMS = 0;
  ejectionVelocity = 1;
  velocityVariance = 1.0;
  ejectionOffset   = 0.0;
  thetaMin         = 0;
  thetaMax         = 180;
  phiReferenceVel  = 0;
  phiVariance      = 360;
  overrideAdvances = false;
  particles = "FighterUJetParticle";
};

//Downward
datablock ParticleData(FighterDJetParticle)
{
  dragCoefficient      = 1.5;
  gravityCoefficient   = 0;
  inheritedVelFactor   = 0.2;
  constantAcceleration = 0.0;
  lifetimeMS           = 3000;
  lifetimeVarianceMS   = 0;
  textureName          = "~/data/particles/downParticle";
  colors[0]     = "0.6 0.6 0.6 0.5";
  colors[1]     = "0.2 0.2 0.2 0";
  sizes[0]      = 0.6;
  sizes[1]      = 5;
};

datablock ParticleEmitterData(FighterDJetEmitter)
{
  ejectionPeriodMS = 50;
  periodVarianceMS = 0;
  ejectionVelocity = 1;
  velocityVariance = 1.0;
  ejectionOffset   = 0.0;
  thetaMin         = 0;
  thetaMax         = 180;
  phiReferenceVel  = 0;
  phiVariance      = 360;
  overrideAdvances = false;
  particles = "FighterDJetParticle";
};

//--------------------------------------------------------------
// WATER SPLASH EFFECTS
//--------------------------------------------------------------

datablock ParticleData(VehicleFoamParticle)
{
   dragCoefficient      = 2.0;
   gravityCoefficient   = -0.05;
   inheritedVelFactor   = 0.0;
   constantAcceleration = 0.0;
   lifetimeMS           = 1200;
   lifetimeVarianceMS   = 400;
   useInvAlpha          = false;
   spinRandomMin        = -90.0;
   spinRandomMax        = 500.0;
   textureName          = "~/data/particles/smokeParticle";
   colors[0]     = "0.7 0.8 1.0 1.0";
   colors[1]     = "0.7 0.8 1.0 0.5";
   colors[2]     = "0.7 0.8 1.0 0.0";
   sizes[0]      = 2;
   sizes[1]      = 4;
   sizes[2]      = 6;
   times[0]      = 0.0;
   times[1]      = 0.5;
   times[2]      = 1.0;
};

datablock ParticleEmitterData(VehicleFoamEmitter)
{
   ejectionPeriodMS = 40;
   periodVarianceMS = 0;
   ejectionVelocity = 10.0;
   velocityVariance = 1.0;
   ejectionOffset   = 0.0;
   thetaMin         = 85;
   thetaMax         = 85;
   phiReferenceVel  = 0;
   phiVariance      = 360;
   overrideAdvances = false;
   particles = "VehicleFoamParticle";
};

Particle Textures

Scripting - Controlling that beast!

This section will explain the core functionalities of the vehicle setup, they will make the model, particles, sounds and everything else work together. This section is script intensive, but its as explained and simple as it can be for the moment. A large part of this section depends on the setup and requirements of your game.

Controls
Vehicles will make use of popping actionmaps, which means you effectively have two sets of key bindings; the standard keys for your player, then after mounting the vehicle, you pop the vehicle's actionmap which sets the keybindings to use this vehicle-specific actions. Action maps are explained here, in the Input Overview.

You should create a seperate set of keybindings for your each vehicle (unless they share the same controls) which are then called through the mounting procedure.

Creation/Destruction

Damage

Mounting/Dismounting



A recap

Provided here is a little recap of the files and areas covered.

Files in Use

fighter.dts
Location:/data/shapes/
Use: This is your model file and should be associated with its texture(s).

fighter.cs
Location:/server/scripts/vehicles/
Use: Give your vehicle model some power through the datablocks.

default.bind.cs
Location:/client/scripts/
Use: The main keyboard controls for your vehicle, typically an addition to the current keyboard controls defaultly installed with the SDK.

Particles
Location:/data/particles/
Use: The folder that contains all the particle images il .png format. You will typically need the following images:
smoke, dust (up, down and liftoff), foam, contrail, jet, explosion.

Sounds
Location:/data/sound/vehicles/
Use: The folder that contains all the sounds for your vehicles. You will typically need the following sounds:
explosion, engine, vehicle_up/down/maneuver.

Vehicle_spec_fx.cs
Location:/server/scripts/vehicles/
Use: This is a common vehicles script file that controls the special effects such as lights, sound and particles for your vehicles.

Resources

http://www.garagegames.com/index.php?sec=mg&mod=resource&page=view&qid=2036

http://www.garagegames.com/index.php?sec=mg&mod=resource&page=view&qid=3925

http://www.garagegames.com/index.php?sec=mg&mod=resource&page=view&qid=4273