Programming the Player UI

This Post covers how the UI within Velicous Racing is programmed.

Because this is a single player game, the UI is contained on a UI just one static canvas. This means that I can create a script with a number of variables and then just drag the correct UI pieces to their corresponding variables in the editor. The script will then have all the references it needs to update the UI at run time, it just needs to access the other scripts on the player to get all of the information it needs. The flow chart below attempts to explain this better.

New-Mind-Map (17)

The figure shows the the UI script is essentially two methods which are called every frame, these methods access other scripts on the player to update the UI accordingly, the script is pasted below.

[RequireComponent(typeof(Player_Motor))]
[RequireComponent(typeof(Player_TimeManager_Script))]
public class Player_UI : MonoBehaviour {

 public Text CheckPointFlash;
 public Text TimeLeft;
 public Text LapCount;
 public Text LapTime;
 public Text DrivenDistance;
 public Text BestLapTime;
 public Text BestDistace;
 public Text GameOverDistance;
 public GameObject CrashPanel;
 public GameObject ResetPanel;
 public GameObject GameOverPanel;

 public Text SpeedText;
 public Text EngineOutput;
 public Image SpeedoMeterNeedle;
 public Image SpeedoMeterOuter;
 public Image RedLineFlash;
 public Image Boost_Meter;
 public float MaxNeedleAngle;

 private Player_Motor playerMotor;
 private Player_TimeManager_Script timeManager;
 private float playerMaxSpeed;
 private float playerMaxEngineRpm;
 private float playerFuelAmount; 

 private void Start()
 {
  playerMotor = GetComponent<Player_Motor>();
  timeManager = GetComponent<Player_TimeManager_Script>();
  playerMaxSpeed = playerMotor.TopSpeed;
  playerMaxEngineRpm = playerMotor.MaxEngineRpm;
 }

 private void Update()
 {
  UpdateSpeedo();
  UpdateInfo();
  if (playerMotor.Crashed == true)
  {
   CrashPanel.SetActive(true);
  } else
  {
   CrashPanel.SetActive(false);
  }

  if(Player_TimeManager_Script.GameOver == true)
  {
   GameOverDistance.text =
   Mathf.RoundToInt(timeManager.DistanceDriven).ToString();
   Image image = ResetPanel.GetComponent<Image>();
   image.CrossFadeAlpha(1, 0.25f, false);
   GameOverPanel.SetActive(true);
  }
 }

 public IEnumerator FlashCheckPoint()
 {
  CheckPointFlash.gameObject.SetActive(true);
  yield return new WaitForSeconds(1);
  CheckPointFlash.gameObject.SetActive(false);
 }

 private void UpdateInfo()
 {
  TimeLeft.text = Mathf.RoundToInt(timeManager.TimeLeft).ToString();
  LapCount.text = timeManager.LapCount.ToString();
  LapTime.text = timeManager.FormattedLapTime;
  DrivenDistance.text = Mathf.RoundToInt(timeManager.DistanceDriven).ToString() + " m";
  BestLapTime.text = timeManager.FormattedBestLapTime;
  BestDistace.text = Mathf.RoundToInt(timeManager.BestDistanceDriven).ToString();
 }

 private void UpdateSpeedo()
 {
  //Speedometer
  float playerCurrentSpeed = playerMotor.ForwardSpeed();
  float speedRange = Mathf.InverseLerp(0, playerMaxSpeed, playerCurrentSpeed);
  SpeedText.text = Mathf.RoundToInt((playerCurrentSpeed * 2.2369f) / 2).ToString();
  SpeedoMeterOuter.fillAmount = speedRange;

  //RPM Counter
  float playerCurrentEngineRpm = playerMotor.EngineRpm();
  if (playerCurrentEngineRpm > (playerMaxEngineRpm - 50))
  {
   RedLineFlash.gameObject.SetActive(true);
  }
  else
  {
   RedLineFlash.gameObject.SetActive(false);
  }
  float ang = Mathf.Lerp(0, MaxNeedleAngle, Mathf.InverseLerp(0, playerMaxEngineRpm, playerCurrentEngineRpm));
  SpeedoMeterNeedle.transform.rotation = Quaternion.Euler(0, 0, -ang);

  //Boost meter
  playerFuelAmount = playerMotor.boostFuelAmount;
  float boostRangne = Mathf.InverseLerp(100, 0, playerFuelAmount);
  Boost_Meter.fillAmount = 1 - boostRangne;

  //Engine Output (Force Meter)
  EngineOutput.text = Mathf.RoundToInt(playerMotor.currentEngineForce * 0.001f).ToString();
 }

 public void ChangeLevel(int _level)
 {
  SceneManager.LoadScene(_level);
 }
}
Advertisements

Vehicle Crash Programming

This post explains how the crash system in Velicous Racing is programmed.

As explained in early post, many of the physics within the game are controlled tightly or disabled all together to give more predictable results. However this presents a problem when the player crashes the vehicle, with such tightly controlled physics the crashes are often predicable, un-random and not realistic all together. As shown in the video below,

To combat this a custom a set of methods have been created to emulate more realistic crashes. The methods essentially detect when a collision has taken place, if a collision is detected then many of the players controls are disabled while physics are enabled on the car. Flow chart below,

New-Mind-Map (10)

With the logic created, I program the methods.

//Collision and Crash Check
private void OnCollisionEnter(Collision collision)
{
 //Play a sound when we hit something
 soundController.PlayHitSound();
 //Find the velocity difference, between us and the object we crashed
 float velocityDiff = collision.relativeVelocity.magnitude;
 //Covert our up vector to w rodl transform
 Vector3 up = transform.TransformDirection(transform.up);
 //Find direction to crash
 Vector3 toOther = collision.contacts[0].point - crashReferencePoint.transform.position;
 //Check direction and force of crash
 if(Vector3.Dot(up, toOther) &gt; 0.1f &amp;&amp; velocityDiff &gt; 100)
 {
  StartCoroutine("HasCrashed");
 }
}
//Void Update Snippet - Check if car has recovered
if (crashed)
{
 boosting = false;
 if (Physics.Raycast(transform.position, -transform.up, out hit, suspensionRange))
 {
  grounded = true;
 } else
{
 grounded = false;
}

if (transform.hasChanged)
{
 Vector3 rotationDiff = transform.rotation.eulerAngles - savedTransformRotation;
 curDir += rotationDiff.y;
 savedTransformRotation = transform.rotation.eulerAngles;
 transform.hasChanged = false;
}

if (rigid.velocity.magnitude == 0 &amp;&amp; grounded == true)
{
 crashed = false;
}
}

The video below shows the results,

 

 

Programming SpeedControl And Refill Pads

In Velicous Racing there  are two types of ‘pads’ found on the road, these are the speed control pad and Refill Pad. As the name suggest the speed control pad controls the players forward velocity while the refill pad fills the players boost fuel.

Speed Control Pad

In some areas of the enviroment the car has to jump, across the enviroment. Because the player can control what speed they are driving at when they take these jumps it would be nice if they where traveling at the correct speed to land in the correct location. This is what speed control pads do, when the player passes over the pad there velocity is changed to the stored target speed.

The speed control pad itself it simply a trigger collider and a controlling script, as shown below.

slowdown

When the player passes through the trigger collider the players rigid body is sampled so that its velocity can be changed. When the rigid bodies velocity is sampled it is returned in world co-ordinates, for this reason is converted to a local vector, the local vectors z value (forward) is then changed to the respective stored speed so that the player lands in the correct position.

The video below shows the same pad both slowing the player and speeding him up, so hat he lands in roughly the same position every time.

The controlling script is pasted below,

public class SlowDownPlate_Script : MonoBehaviour {

 [SerializeField]
 private float targetSpeed = 150.0f;
 [SerializeField]
 private float smoothvalue = 5f;
 private AudioSource myAudio;

 void Start()
 {
  myAudio = GetComponent<AudioSource>();
 }

 private void OnTriggerStay(Collider other)
 {
  //Check the collider is a player
  if(other.tag == "Player")
  {
    //Play A Sound
    myAudio.Play();
    //Grab the player rigid body reference
    Rigidbody otherBody = other.GetComponent<Rigidbody>();
    if (otherBody != null)
    {
      //Grab players world velocity
      Vector3 velocity = otherBody.velocity;
      //Localise it
      Vector3 localVel = other.transform.InverseTransformDirection(velocity);
      //Lerp the players velocity to the target speed
      localVel.z = Mathf.Lerp(localVel.z, targetSpeed, smoothvalue *
      Time.fixedDeltaTime);
      //Reapply the veclotity as a world velocity
      Vector3 worldVel = otherBody.transform.TransformDirection(localVel);
      otherBody.velocity = worldVel;
    }
   }
 }
}

Boost Refill Pad

The player is able to boost while racing to increase the power of their engine, however this uses ‘boost fuel’ when this is empty the player cannot boost anymore. To refill the player’s boost fuel they must drive over a boost refill pad.

The boost pad works in much the same way as the speed control pad, it is simply a trigger collider and a controlling script.

refilpad

Once again as the player passes through the trigger collider the controlling script is activated. This script accesses the players motor script and adds an amount of fuel for every tick the player is inside of the trigger collider, until the players fuel is completely full.

The script is pasted below,

public class BoostRefill_Script : MonoBehaviour {

 private AudioSource myAudio;
void Start()
 {
  myAudio = GetComponent<AudioSource>();
 }

 void OnTriggerStay(Collider other)
 { 
  if(other.gameObject.tag == "Player")
  {
    if (other.GetComponent<Player_Motor>().boostFuelAmount < 100)
    {
      if(myAudio.isPlaying == false)
      {
        myAudio.Play();
      }
      other.GetComponent<Player_Motor>().boostFuelAmount += 1;
      }
     }
   }
}

Programming Other Vehicle Physics

This post covers miscellaneous methods that are running in the background that complete the vehicle controller, these methods simulate drag among other physics emulations.

Update Forward Velocity Based On Direction

Because the cars in Velicous Racing hover, there is no contact with the ground and this means that as the player turns the car it will simply continue in its original direction. Much like an object floating in space.

To counter this problem a method was created, this method cancels any ‘sideways’ velocity over time. Ultimately this means that when the player turns the car, sideways velocity will be detected and canceled out over time. As usual I provide a flow graph to illustrate,

New-Mind-Map (9)

With the logic set out, I created the final codes.

private float GripBasedOnSpeed(float _speed)
{
 float range = Mathf.InverseLerp(0, topSpeed, _speed);
 float grip = maxGrip * range;
 float returnMaxedGrip = Mathf.Max(minGrip, grip);
 return returnMaxedGrip;
}
private void KeepVelocityAlignedWithVehicle()
{
 Vector3 localV = transform.InverseTransformDirection(rigid.velocity);
 localV.x = Mathf.Lerp(localV.x, 0, currentGrip * Time.fixedDeltaTime);
 Vector3 worldV = transform.TransformDirection(localV);
 rigid.velocity = worldV;
}

Drag

In Unity’s physics engine, by default air drag is a static value. However in real life as an object accelerates to a higher speed its drag increases proportionally. So we must emulate this in Unity. To keep things simply as we are only trying to emulate drag and not simulate it, we can use a formula based on the objects current speed and terminal velocity.

Drag = Current Velocity / Terminal Velocity

The above formula produces a normalized value that ranges from 0 – 1, this can be used to set Unity’s drag value at run time. Which produces much more realistic results compared to a static drag value.

private void UpdateDrag()
{
 rigid.drag = rigid.velocity.magnitude / topSpeed;
}

Audacity – Sound Editor

This short post covers my use of Audacity to edit sounds.

Because I am downloading royalty free sound effects for this game I need the ability to edit these sounds. As they may not be up to standard to to my specification for this task I will use Audacity.

Audacity is a free open source sound editing software capable of not only cutting sounds but also making adjustments to them such as fade, pitch or volume.

To illustrate how I will be using Audacity, I have created a production log of me editing just one sound within the game. If you listen closely to looped sound in the video below you can clearly hear an click or artifact on each loop.

This artifact is down to bad editing, essentially the volume at the start or end of the loop is not zero so it does not seamlessly loop. I will therefore use Audacity to fix this, the process is illustrated below.

Once the file is open in Audacity a wave will be displayed, this wave represents the peaks and troughs of the sound. By zooming(Ctrl + 1) into the begging or end of the sound wave we can see it more detail.

 

The images above show the zoomed view of the sound wave, the first image represents the very start of the sound as shown the volume comes in at  0 and then begins to change. However, the second image represents the end of the sound and this does not end on a volume of 0 and therefore the sound will not loop as the volume will jump from some value to 0 instantly as the sound starts. To fix this then we can use Audacity’s fade feature to fade out the volume at the end.

By using Audacity’s Fadeout tools we have managed to cancel any volume at the end of the sound wave, the same process can be used for the beginning if need be. The resulting fixed sound can be heard below.

Audacity has range of audio tools which I will utilize during the development of this game. This post shows only one of these processes, buts demonstrates my typical use of Audacity.

Vehicle Hover and Steer

This post explains the custom vehicle controller I created for this game. Because this game has hovering cars that move at high speed the default vehicle controller was in no way suitable.

Hover Ability

After some research I could see two feasible methods for getting the desired results in Unity. Both of these use methods use ray cast fired down from the car towards the ground to test for distance and adjust the cars position accordingly.

There are some differences in the approaches I found however, the first method uses four ray cast and Unity’s inbuilt physics engine to apply reactive forces. Thus keeping the car floating above the ground, this is illustrated below.

raycastphysics

This method produces very realistic looking results, however using the physics engine makes it very hard to control the cars hover and makes it very unpredictable. Another undesirable result of this method is that if the player crashes the car at high speed the physics engine struggles to produce realistic looking results.

The second method I found during my research uses just one ray cast and directly sets the position of the car using its transform instead of Unity’s physics engine. Again this method is illustrated below.

raycastphysics2

This method again has its advantages and dis-advantages. The ‘hover’ motion of this solution is much more stable and controllable than previously described solution, but it is less reactive to bumps and therefore bottoms out more often on un-even terrain or hills. This is because the ground is only sampled in one position and if the car rotates the front or back of the car can be lower than the sampled position,

Because both of the solutions have there pro’s and con’s my final solution is a hybrid of the two and again is illustrated below.

raycastphysics3

The later ‘hybrid’ method uses four ray casts, to produce a relative ‘force’ which applied directly through the physics engine, but as an acceleration. Accelerations in Unity ignore all physics and simply moves the transform. This gives the best of both worlds, because it is very controllable while at the same time it has four sample points which helps negates the problems with bumps and uneven terrain.

Finally the cars rigid body rotations are frozon so that physics do not effect them

The flow graph below explains how the logic flows for the cars hover suspension .

New-Mind-Map (5)

Finally, I moved onto create the final code.

//Hover Physics
private void HoverSuspension()
{
 for (int i = 0; i &amp;amp;amp;lt; RayCastPoints.Length; i++)
 {
  if (Physics.Raycast(RayCastPoints[i].position, -transform.up, out hit, suspensionRange))
  {
   if (hit.collider.tag == "Driveable" || hit.collider.tag == "Road")
   {
    distances[i] = hit.distance;
    curNormals[i] = hit.normal;
    vectors[i] = hit.point;
    groundedArray[i] = true;
  }
 }
 else
 {
 distances[i] = 999f; // Debug Value to bypass later code
 groundedArray[i] = false;
 }
 }
 //If any ray has hit, then we are grounded.
 if(groundedArray[0] == true || groundedArray[1] == true || groundedArray[2] == true || groundedArray[3] == true)
 {
 grounded = true;
 } else
 //No rays hit, we are flying!
 {
 grounded = false;
 return;
 }

 float minDistance = Mathf.Min(distances[0], distances[1], distances[2], distances[3]);
 int index = System.Array.IndexOf(distances, minDistance);
 Vector3 minPoint = vectors[index];

 //Find velocity at hit point
 Vector3 _velocityAtTouch = rigid.GetPointVelocity(minPoint);
 //Create compression varible
 float _compression = minDistance / hoverHeight;
 _compression = -_compression + 1;
 //Create counterForce vector
 Vector3 _counterForce = (transform.up * _compression) * suspensionForce;
 //Create a stabalising drag force
 Vector3 t = transform.InverseTransformDirection(_velocityAtTouch);
 //Remove X and Z
 t.z = t.x = 0;
 //Create a Y drag force
 Vector3 _shockDrag = rigid.transform.TransformDirection(t) * -suspensionDamp;
 //Apply The Force, Use the physics engine, but apply it as an acceleration
 rigid.AddForce(_counterForce + _shockDrag, ForceMode.Acceleration);
 }

Terrain and Steering Rotation

Now the car can hover, I move onto programming its ability to align its self with terrain below. Because my hover solution adds a single force to the cars transform it can not deal with rotations, for this reason I need a second method which can.

After some research I once again found a solution, available to view here.

Unity Hover Car Terrain Align Solution

The solution is posted by ‘aldonaletto‘ uses only one ray trace to sample the normal angle of the terrain below relative to the car, this value is then used to adjust the cars rotation accordingly.

Because my car has four race traces aldonaletto’s solution can be adapted and made more accurate for my needs. Once again a flow chart shows the logic,

New-Mind-Map (6)

The flow chart above describes how the car will align itself with the terrain below, but does not allow the player to steer the car. How this is done is shown below,

New-Mind-Map (7)

Final code for the vehicles ability to align its self with the terrain and steer is below,

//Steerting and floor aignment
private void TerrainAlignSteer(float _horizontalInput)
{
//Average the normals
Vector3 averageCurNormal = (curNormals[0] + curNormals[1] + curNormals[2] + curNormals[3]) / 4;
//Check how fast we are going relative to top speed
float speedRange = Mathf.InverseLerp(0, topSpeed, currentSpeed);
//Use speedrange value to adjust the cars turn rate
float adjustedTurnFoce = Mathf.Max(minTurnForce, maxTurnForce * 1 - speedRange);
float turn = (adjustedTurnFoce * _horizontalInput * Time.fixedDeltaTime);
curDir = (curDir + turn) % 360; // rotate angle modulo 360 according to input
//Smooth the terrain normal
curNormal = Vector3.Lerp(curNormal, averageCurNormal, 5 * Time.fixedDeltaTime);
//Find the difference between up and required normal
Quaternion grndTilt = Quaternion.FromToRotation(Vector3.up, curNormal);
//Multiply the input with terrain align and apply
Quaternion newRot = grndTilt * Quaternion.Euler(0, curDir, 0);
transform.rotation = newRot;
}

Enviroment Production

This post covers the production of the first enviroment.

Maya Block-out Track

The first step in producing the enviroment was to create a basic block-out of the track within Maya according the concept.

The first step of this process is to create a simply plane with the desired width of the road and to UV map it. This plane will be duplicated many times to create the final road. It is best practice to leave some divisions on the plane, as it will need to be deformed and the division will give a cleaner deformation.

plane

The next step I take it to create a CV curve that follows as closely as possible the track concept design, this curve will be used to deform the road planes. Although this curve does not represent the final shape of the track, it does provide a basis to build from and this is why we must follow the concept closely. If the track is made up of multiple individual sections, then more than one curve can be used to create each section.

splines

Once the curves are complete, I begin to measure the length of each curve and create the corresponding road sections. The length of each curve can easily be measured in Maya using the ‘arclen’ command.

arclen

Once the length of each curve is known, the number of planes needed to create each section can be calculated using;
‘curve length / piece length = number of pieces needed to create section’

I then use duplicate special on the single road section created in step one, the number of duplicates is calculated using the formula above.

Next I connect the created road section to corresponding curve. This is done by first combing all of the road pieces into one single mesh and then attaching that mesh to the curve using ‘Attach to Motion Path’. Finally, the combined mesh can be deformed to the shape of the curve using the ‘Flow Path Object’ option within Maya constraint menus. The resolution of the Flow path can be controlled using the division attribute.

Further adjustments can be made by moving lattice created by the flow path object, once I am happy with the road section I delete the construction history of the mesh. This disconnects it from the curve and flow path,leaving just the static mesh behind. Finally the mesh can be be ‘separated’, this step undoes the ‘combine’ step taken earlier and breaks the mesh back into the singular planes it is constructed from. The final result then is multiple singular planes each with individual but identical UV maps, which have been deformed to create the basic shape of the track.

The same process is repeated for each curve and section of the road until the full track block out is complete.

completeblock

Unity Prop Placement

I import the blocked out track into Unity and also create a terrain asset. So that I can begin to block out the actual enviroment within Unity.

unity1

The next step was to  block out the basic areas of interest according to the concept, for this I use Unity’s prototype assets as they are perfectly scaled to various sizes and can therefore be used as a size reference without actually needed to import them into Maya.

Once the basic block out is created within Unity, I begin to create assets in Maya. The block out references are used for as a size reference so that the props fit in their according place.

Some shots of props created in Maya,

Once props are created in Unity they can be brought into Unity to placed in their final location.

Some props are duplicated many times within Maya before being sent to Unity, as Maya snapping and organizing tools are more powerful than Unity’s.

For instance props, can be parented to another prop before being brought into Unity, within Unity the child prop can simply be zeroed out and the prop will be in its correct location.

Unity Lighting

Once 95 percent of the props are placed in their correct position, I begin to light the level. The first step I take in this process is to  adjust the ambient light in the scene to replicated sunlight or moonlight. Because this will be a night scene I am going for a moon lit feel.

I first change the sky box to suit and then adjust the ambient light until I feel like I have achieved a moonlit feel. From studying moon lit pictures I have decided moon light is generally pure white or a weak blue. In my scene I tried both, with blue giving the best results.

Once the ambient light is complete, I move onto creating Fog. Fog within Unity can be used to hide areas you do not want the player to see, such as the horizon line for instance. It also give distance objects a more realistic feel, as in real life the further an object is from the view point the more blurred it appears.

The next part of lighting the scene involves placing iridescent materials around the scene along with light objects. I manually place lights where they are needed, there should be no black areas in the scene where the player can access. If the player can reach that part of the enviroment it should be lit.

With the lights placed in the scene I can finally bake the pre-computed GI information. This information allows Unity to compute light bounce at run time, so that shadows and objects are indirectly lit by other objects. This gives a much more realistic feel to the scene and also help improve lighting in the scene.

With the lighting complete, I call the enviroment complete. Although I will be continuously making small changes.

Vehicle Engine

This post covers the how the ‘engine’ of the vehicles within the game are programmed. During this post whenever I say engine, I am referring to the script that makes the car move forward according the players input, rather than the game engine itself.

Taking in the players input and multiplying that with a constant number is the basic principle behind this script, however applying the subsequent number would give a very linear acceleration to the car as the engine would produce maximum power immediately, something that does not happen in real life. Especially as i am trying to mimic jet engines, which take some time to spool up and produce power.

For this reason I also create a RPM method, this method simulates the engine spooling up and adjust power accordingly. As usual a flow chart is provided,

New-Mind-Map (8)

Below is the RPM and engine force method.

public float EngineRpm()
{
 if (grounded)
  {
  //Rpm limiter
  if (currentEngineRpm >= maxEngineRpm)
  {
   return currentEngineRpm = currentEngineRpm - 100;
  }
  //Player is accelerating
  if (VerticalInput > 0)
  {
   float engineSpoolRateRange = 1 - Mathf.InverseLerp(500, maxEngineRpm, currentEngineRpm);
   float maxedEngineSpoolRateRange = Mathf.Max(minEngineSpoolRate, engineSpoolRateRange);
   return currentEngineRpm = Mathf.Lerp(currentEngineRpm, idleEngineRpm + VerticalInput * maxEngineRpm, (maxedEngineSpoolRateRange * engineSpoolRate) * Time.deltaTime);
  } else
  //Engine Spool Down
  {
   return currentEngineRpm = Mathf.Lerp(currentEngineRpm, idleEngineRpm, Time.fixedDeltaTime);
  }
 } else
 //Not grounded,Engine Spool Down
 {
  return currentEngineRpm = Mathf.Lerp(currentEngineRpm, idleEngineRpm, Time.fixedDeltaTime);
 }
}
//Forward Force
private void EngineForce(float _verticalInput, bool _boost)
{
 if (_verticalInput > 0)
 {
  Vector3 _engineForce = Vector3.zero;
  if (_boost == true)
  {
   if (boostFuelAmount >= 0)
   {
     soundController.PlayBoost();
     boosting = true;
     float newAccelerationForce = accelerationForce * boostForce;
     _engineForce = (transform.forward * newAccelerationForce * EngineRpm()) *
_verticalInput;
     engineSpoolRate = storedEngineSpoolRate * 5.0f;
     boostFuelAmount -= boostFuelBurnRate;
     currentEngineForce = currentEngineRpm * newAccelerationForce;
   } else
   {
     boosting = false;
    _engineForce = (transform.forward * accelerationForce * EngineRpm()) *
  _verticalInput;
    engineSpoolRate = storedEngineSpoolRate;
    currentEngineForce = currentEngineRpm * accelerationForce;
  }
 } else
 if (_boost == false)
 {
   boosting = false;
   _engineForce = (transform.forward * accelerationForce * EngineRpm()) *
   _verticalInput;
   engineSpoolRate = storedEngineSpoolRate;
   currentEngineForce = currentEngineRpm * accelerationForce;
 }
 rigid.AddForce(_engineForce, ForceMode.Force);
 } else
  if(_verticalInput < 0)   {     if(currentSpeed > 0)
    {
      Vector3 _engineForce = (transform.forward * brakingForce) * _verticalInput;
      rigid.AddForce(_engineForce, ForceMode.Force);
      currentEngineForce = currentEngineRpm * accelerationForce;
   }
  } else
  if(_verticalInput == 0)
  {
    currentEngineForce = currentEngineRpm * accelerationForce;
  }
}

Unity Plugins

This post covers the Unity Plugins used in this project.

Terrain Tool Kit 2017(Free)

The terrain toolkit is a script that unlocks new features within the terrain editor. The toolkit contains algorithms that are capable of generating terrain procedural based on the users input. This can then be fine tuned using the traditional manual terrain tools.

Not only is terrain tool kit capable of generating procedural terrain but also capable of automatically laying down textures to that terrain based on some input variables. The texture positions are calculated using the angle and height of the terrain to determine which textures should be laid where, for instance cliffs will have a high angle close to 90 degree’s while snowing mountain tops may have a low angle but a high height value.

The images below explain how Terrain Tool Kit can be used.

Terrain_ToolKit

Blog at WordPress.com.

Up ↑