Steering Behaviors: Leader Following

A few days ago I read a post about Steering Behaviors on tuts+
http://gamedevelopment.tutsplus.com/tutorials/understanding-steering-behaviors-leader-following–gamedev-10810

I am a big fan of these techniques and decided to create this in #Unity

(demo)

 

using UnityEngine;
using System.Collections;

public class Boid : MonoBehaviour {

    public float MAX_FORCE = 5.4f;
    public float MAX_VELOCITY = 3;

    // Leader sight evasion
     float LEADER_BEHIND_DIST = 3;
    // Separation
     float MAX_SEPARATION = 1.0f;
     float SEPARATION_RADIUS = 2.5f;

    public GameObject Target;

    public int FieldOfView = 45;
    public int ViewDistance = 100;
    public int MinLookDistance = 10;
    private Vector3 rayDirection;
     float rotSpeed = 2.0f;
     float m_MovingTurnSpeed = 90;

        public Vector3 velocity 	;
		public Vector3 desired 		;
		public Vector3 ahead 		;
		public Vector3 behind 		;
		public Vector3 steering 	;

		public bool leader		;

        public string Picktag;
        protected Rigidbody body;

        public  Boid[] neighbors;

        protected void getNeighbors()
        {
            GameObject[] objs = GameObject.FindGameObjectsWithTag("NPC");

            Boid[] neighbors = new Boid[objs.Length];

            for (int i = 0; i < objs.Length; i++)
            {
               neighbors[i]= objs[i].GetComponent<Boid>();
             }
        }

        protected Vector3 seek(Vector3 target)
       {
			Vector3 force =Vector3.zero;
			desired = target-Position;
            desired.Normalize();
			desired*=MAX_VELOCITY;
			force = desired-velocity;
			return force;
	   }

    protected Vector3 separation()
    {

            Vector3 force = Vector3.zero;
            int neighborCount = 0;
            for (int i = 0; i < neighbors.Length; i++)
            {
                Boid b = neighbors[i];
                if (b != this && distance(b.Position, this.Position) <= SEPARATION_RADIUS)
                {
                    force.x += b.Position.x - this.Position.x;
                    force.z += b.Position.z - this.Position.z;
                    neighborCount++;
                }
            }

            if (neighborCount != 0)
            {
                force.x /= neighborCount;
                force.z /= neighborCount;
                force *= -1;
            }

            force.Normalize();
            force *= MAX_SEPARATION;
            return force;

		}

protected float distance(Vector3 a ,Vector3 b )
{
			return Mathf.Sqrt((a.x - b.x) * (a.x - b.x)  + (a.z - b.z) * (a.z - b.z));
}

    protected Vector3 arrive(Vector3 target, float slowingRadius = 200)
    {
        Vector3 force = Vector3.zero;
        float distance;

        desired = target - Position;

        distance = desired.magnitude;
        desired.Normalize();

        if (distance <= slowingRadius)
        {
            desired *= MAX_VELOCITY * (distance / slowingRadius);
        }
        else
        {
            desired *= MAX_VELOCITY;
        }

        force = desired - velocity;

        return force;
    }
    protected Vector3 flee(Vector3 target)
    {
        Vector3 force = Vector3.zero;
        desired = Position - target;
        desired.Normalize();
        desired *= MAX_VELOCITY;
        force = desired - velocity;
        return force;
    }
    protected Vector3 evade(Boid target)
    {
        Vector3 distance = target.Position - Position;
        float updatesNeeded = distance.magnitude / MAX_VELOCITY;
        Vector3 tv = new Vector3(target.velocity.x, target.velocity.y, target.velocity.z);
        tv *= updatesNeeded;
        Vector3 targetFuturePosition = new Vector3(target.Position.x, target.Position.y, target.Position.z);
        targetFuturePosition += tv;
        return flee(targetFuturePosition);
    }

    protected Vector3 followLeader(Boid leader)
   {
            Vector3 tv = new Vector3(leader.velocity.x, leader.velocity.y, leader.velocity.z);
            Vector3 force = Vector3.zero;
            tv.Normalize();
			tv*=LEADER_BEHIND_DIST;
            ahead = leader.transform.position + tv;
			tv*=-1;
            behind = leader.transform.position + tv;

            if (distance(leader.Position, this.Position) <= LEADER_BEHIND_DIST)
            {
                force += (evade(leader));
                force*=0.5f; // da um pouco de boost na força 

            }
            else
            {
                force += (arrive(behind, LEADER_BEHIND_DIST));
            }

            force +=  separation();

			return force;
	}
    protected void truncate(Vector3 v,float max)
    {
			float i;
			i = max /v.magnitude;
			i = (i < 1.0f) ? i : 1.0f;
            v *= i;
	}

   protected float getAngle(Vector3 vector)
   {
			return Mathf.Atan2(vector.x, vector.z);
}

    public float Angle
    {
        get
        {
            return transform.rotation.eulerAngles.y;
        }
        set
        {
            transform.rotation = Quaternion.AngleAxis(value, Vector3.up);
            return;
        }

    }
    public Vector3 Position
    {
        get
        {
            return transform.position;
        }
        set
        {
            transform.position = value;
            return;
        }

    }
    protected void TurnToVelocity()
    {
        transform.rotation = Quaternion.Slerp(transform.rotation,
                                                   Quaternion.LookRotation(velocity),
                                                   m_MovingTurnSpeed * Time.deltaTime);
    }

    protected void TurnToTarget(Vector3 t)
    {
      //  if (Vector3.Distance(t, transform.position) <= MinLookDistance)
      //  {
            Quaternion tarRot = Quaternion.LookRotation(t - transform.position);
            transform.rotation = Quaternion.Slerp(transform.rotation, tarRot, rotSpeed * Time.deltaTime);
      //  }

    }
    protected bool DetectAspect()
    {
        if (Target)
        {
            RaycastHit hit;
            rayDirection = Target.transform.position - transform.position;
            if ((Vector3.Angle(rayDirection, transform.forward)) < FieldOfView)
            {

                if (Physics.Raycast(transform.position, rayDirection, out hit, ViewDistance))
                {
                    Picktag = hit.collider.gameObject.tag;
                    return true;
                }
            }
        }
        Picktag = "NONE";
        return false;
    }

    /*
    void OnDrawGizmos()
    {

        if (Target)
        {
            Debug.DrawLine(transform.position, Target.transform.position, Color.red);

            Vector3 frontRayPoint = transform.position + (transform.forward * ViewDistance);
            Vector3 leftRayPoint = frontRayPoint;
            leftRayPoint.x += FieldOfView * 0.5f;
            Vector3 rightRayPoint = frontRayPoint;
            rightRayPoint.x -= FieldOfView * 0.5f;

            Debug.DrawLine(transform.position, frontRayPoint, Color.green);
            Debug.DrawLine(transform.position, leftRayPoint, Color.green);
            Debug.DrawLine(transform.position, rightRayPoint, Color.green);
        }
    }*/
}

 

using UnityEngine;
using System.Collections;

public class Npc : Boid
{

    public GameObject Leader;

    void Start()
    {
        body = GetComponent<Rigidbody>();
     //   getNeighbors();

    }
	void Update ()
    {

        steering *= 0;

        if (leader)
        {
            steering = steering + arrive(Target.transform.position,3);
            TurnToTarget(Target.transform.position);
        }
        else
        {
            if (Leader)
            {
                Boid l= Leader.GetComponent<Boid>();
                steering = steering + followLeader(l);
                TurnToTarget(l.Position);
            }
        }

        truncate(steering, MAX_FORCE);
        steering *= (1 / body.mass);
        velocity = velocity + steering;
        truncate(velocity, (!leader ? MAX_VELOCITY * (0.3f + UnityEngine.Random.Range(0.1f, 0.5f)) : MAX_VELOCITY));
        body.velocity=velocity;
       //TurnToVelocity();
	}

}

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s