Saturday, 18 July 2015

Unity Automated Turret Tutorial Tracking Code

Unity Automated Turret Tutorial Tracking Code

A video explainging this code is available here: https://www.youtube.com/watch?v=-_k8Ob7ElUo&feature=youtu.be

I have provided two scripts below. Once is for a simple tracking system in unity & the other is just to move an object continuously between two points. Remember to name the file the same as the class name or they won't compile in unity.

Tracking Script:

using UnityEngine;
using System.Collections;

public class TrackingSystem : MonoBehaviour {
public float speed = 3.0f;
public GameObject m_target = null;
Vector3 m_lastKnownPosition = Vector3.zero;
Quaternion m_lookAtRotation;

// Update is called once per frame
void Update () {
if(m_target){
if(m_lastKnownPosition != m_target.transform.position){
m_lastKnownPosition = m_target.transform.position;
m_lookAtRotation = Quaternion.LookRotation(m_lastKnownPosition - transform.position);
}

if(transform.rotation != m_lookAtRotation){
transform.rotation = Quaternion.RotateTowards(transform.rotation, m_lookAtRotation, speed * Time.deltaTime);
}
}
}

bool SetTarget(GameObject target){
if(!target){
return false;
}

m_target = target;

return true;
}
}


Movement Script:

using UnityEngine;
using System.Collections;

public class EnemyAi : MonoBehaviour {
public Transform pointA;
public Transform pointB;
public float speed;

// Update is called once per frame
void Update () {
transform.position = Vector3.Lerp(pointA.position, pointB.position, Mathf.Sin(Time.time * speed));
}
}

Sunday, 5 July 2015

Unity Lerping

When i started with unity, lerping was something extremely common to use but I never really grasped it near the start. Overtime I have realised how exactly it works, but noticed people still struggling with its use so I thought I would share what I have learned so far.

So to start what does a lerp do?

A lerp will transition from one value to another using the provided value. So if we have two numbers ranging from five to ten and the end value was 0.3 then the resulting number would be calculated as so: 10 - 5 = 5 / 5*0.3f = 1.5 / 1.5 + 5. By getting the difference between the values and then multiplying it by the value provided and adding it to the original number you get the lerp of the numbers. Obviously this gets more complicated for different classes, but this is the basics of a lerp.

In unity lerp functions are provided as so: LerpClass Lerp(LerpClass , LerpClass , float). The end float being a number between 0 - 1 & LerpClass being the relevant unity class.

So now you understand how they are done, how do you use them?

The most common lerp I use is for Vector3 so I will start with that.

class LerpTest : MonoBehaviour{
  float m_lerpProgress;
  bool m_lerping;
  Vector3 m_lerpFrom;
  Vector3 m_lerpTo;

  void Start(){
     StartLerp(new Vector3(0.0f, 0.0f, 0.0f), new Vector3(0.0f, 10.0f, 0.0f));
  }

   void Update(){
     if(m_lerping){
       m_lerpProgress += Time.deltaTime;

       if(m_lerpProgress > 1.0f){
          m_lerpProgress = 1.0f;
          m_lerping = false;
     }

       transform.position = Vector3.Lerp(m_lerpFrom, m_lerpTo, m_lerpProgress);
     }
  }

  void StartLerp(Vector3 startPos, Vector3 endPos){
    m_lerpFrom = startPos;
    m_lerpTo = endPos;
    m_lerping = true;
    m_lerpProgress = 0.0f;
  }
}

Using the above code you can use the start lerp function to help transition something between any two provided locations. So let's break down exactly how it all works.

First of all the variables used:

m_lerpProgress: This stores the amount of progress made between the two points from A - B. This value should always be from 0 - 1.

m_lerping: This is just used to stop the lerp code continuously running once we have already finished lerping.

m_lerpFrom - m_lerpTo: These two are used for holding the locations that we want to go from and to, provided using the StartLerp function.

In the update function we only handle the lerp when a lerp has been started. Right now we transition between the two provided points within one second as Time.deltaTime is the time between frames in realTime. I have provided a couple of ways to alter how long a lerp takes abit further down. The main mistake people make with a lerp is that they will put something along the lines of this:

transform.Position = Vector3.Lerp(transform.position, targetLocation, Time.deltaTime);

This code will work fine, but it will slow down the further it progresses and we have a lack of control over the lerp as a whole. Say we want to lerp between (0, 0, 0) & (0, 10, 0) here's how the two ways would work assuming Time.deltaTime was always 0.1f (for easier math):

-----------------------------------------------------------------------------------------------------------------------

transform.position = Vector3.Lerp(m_lerpFrom, m_lerpTo, m_lerpProgress);

Results:

(0, 1, 0)
(0, 2, 0)
(0, 3, 0)
(0, 4, 0)
...
(0, 9, 0)
(0, 10, 0)

This would progress at a consistent rate as it went.

-----------------------------------------------------------------------------------------------------------------------

transform.Position = Vector3.Lerp(transform.position, targetLocation, Time.deltaTime);

Results:

(0, 1, 0)
(0, 1.9, 0)
(0, 2.71, 0)
(0, 3.439, 0)

This math gets difficult fast, but as we get closer to the target the amount of progress gets smaller, resulting in a slow down as it goes along.

-----------------------------------------------------------------------------------------------------------------------

Now if we use the consistent rate what if we wanted to alter the speed?

I have written two ways to do this below, the first just using a speed value to alter the rate at which we progress and the second using a time for the journey to take.

Speed:

class LerpTest : MonoBehaviour{
  public float speed;

  float m_lerpProgress;
  bool m_lerping;
  Vector3 m_lerpFrom;
  Vector3 m_lerpTo;

  void Start(){
      StartLerp(new Vector3(0.0f, 0.0f, 0.0f), new Vector3(0.0f, 10.0f, 0.0f));
  }

  void Update(){
     if(m_lerping){
        m_lerpProgress += Time.deltaTime * speed;

        if(m_lerpProgress > 1.0f){
           m_lerpProgress = 1.0f;
          m_lerping = false;
        }

        transform.position = Vector3.Lerp(m_lerpFrom, m_lerpTo, m_lerpProgress);
     }
  }

  void StartLerp(Vector3 startPos, Vector3 endPos){
     m_lerpFrom = startPos;
     m_lerpTo = endPos;
     m_lerping = true;
     m_lerpProgress = 0.0f;
  }
}

Time:
class LerpTest : MonoBehaviour{
  public float time;

  float m_lerpProgress;
  bool m_lerping;
  Vector3 m_lerpFrom;
  Vector3 m_lerpTo;

  void Start(){
     StartLerp(new Vector3(0.0f, 0.0f, 0.0f), new Vector3(0.0f, 10.0f, 0.0f));
  }

  void Update(){
     if(m_lerping){
        m_lerpProgress += Time.deltaTime * (1.0f/time);

        if(m_lerpProgress > 1.0f){
         m_lerpProgress = 1.0f;
         m_lerping = false;
        }

       transform.position = Vector3.Lerp(m_lerpFrom, m_lerpTo, m_lerpProgress);
     }
  }

  void StartLerp(Vector3 startPos, Vector3 endPos){
     m_lerpFrom = startPos;
     m_lerpTo = endPos;
     m_lerping = true;
     m_lerpProgress = 0.0f;
  }
}

To affect the rate of progress we manipulate Time.deltaTime. In the first case we provide a number just to move faster by or slower if you go below one, I generally use this for things like movement speed. Now with the time part since we know the amount of progress is 0 - 1 we can multiply the deltaTime by 1.0f / time we want to take. This will slow the rate of progress to be exactly what is needed to get there in the set time.

Now that you know the basics of using lerp these can be used with any lerp not just Vector3 just replace Vector3 with the relevant class (that has a .Lerp function). Below I have provided a slightly different use of lerp to progress at a consistent rate across any distance with Vector3 to show powerful lerp can be used when used correctly; this could be used for moving objects through a series of points without their speed varying.

class LerpTest : MonoBehaviour{
  public float speed;

  float m_lerpProgress;
  bool m_lerping;
  Vector3 m_lerpFrom;
  Vector3 m_lerpTo;
  float m_privSpeed;

  void Start(){
     StartLerp(new Vector3(0.0f, 0.0f, 0.0f), new Vector3(0.0f, 10.0f, 0.0f));
  }

  void Update(){
     if(m_lerping){
        m_lerpProgress += Time.deltaTime * m_privSpeed;

        if(m_lerpProgress > 1.0f){
           m_lerpProgress = 1.0f;
           m_lerping = false;
        }

        transform.position = Vector3.Lerp(m_lerpFrom, m_lerpTo, m_lerpProgress);
     }
  }

  void StartLerp(Vector3 startPos, Vector3 endPos){
     m_lerpFrom = startPos;
     m_lerpTo = endPos;

     float dist = Vector3.Distance(m_lerpFrom, m_lerpTo);
     m_privSpeed = speed / dist;
     m_lerping = true;
     m_lerpProgress = 0.0f;
  }
}

The speed that you provide will now be for a vector of length 1, which means as the distance gets longer or shorter it won't effect the speed that the object travels at.

I know this was quite a long post, but I hope it helps people understand lerp better.

Any questions?
Ask below.