Birds and Unity3D, an attempt to optimize

After reading a post about creating birds on Unity3D , I decided to offer my optimization option.

In Unity, it is bad to place a script on each object, especially if there are a lot of them, strong lags appear. In order not to hang the script Boid.cs can be done differently.

Create a class Boid:

public class Boid
{
    public Vector3 velocity;
    public Vector3 position;//Добавляем положение птицы в пространстве
    private float cohesionRadius = 10;
    private float separationDistance = 5;
    private Boid[] boids;
    private Vector3 cohesion;
    private Vector3 separation;
    private int separationCount;
    private Vector3 alignment;
    private float maxSpeed = 15;
    public Boid(Vector3 pos)
    {
        position = pos;
    }
}

In this class, all calculations will be made. To make it independent of game objects, you need to replace the Physics.OverlapSphere function:
    public static Boid[] boids;
    static public Boid[] Sphere(Vector3 position, float radius)
    {
        List mids = new List();
        for (int i = 0; i < boids.Length; i++)
        {
            if (Vector3.Distance(position, boids[i].position) < radius)
                mids.Add(boids[i]);
        }
        return mids.ToArray();
    }

This function will be in another class.
Now you can add the calculation function itself:
public void CalculateVelocity()
    {
        Vector3 newVelocity = Vector3.zero;
        cohesion = Vector3.zero;
        separation = Vector3.zero;
        separationCount = 0;
        alignment = Vector3.zero;
        boids = Boids.Sphere(position, cohesionRadius); //Здесь мы заменили функцию Physics.OverlapSphere на свою
        foreach (Boid boid in boids)
        {
            alignment += boid.velocity;//Нам больше не нужно получать компонент объекта
            cohesion += boid.position;//Больше не обрашаемся к Transfom
            if (boid != this && (position - boid.position).magnitude < separationDistance)
            {
                separation += (position - boid.position) / (position - boid.position).magnitude;
                separationCount++;
            }
        }
        cohesion = cohesion / boids.Length;
        cohesion = cohesion - position;
        cohesion = Vector3.ClampMagnitude(cohesion, maxSpeed);
        if (separationCount > 0)
            separation = separation / separationCount;
        separation = Vector3.ClampMagnitude(separation, maxSpeed);
        alignment = alignment / boids.Length;
        alignment = Vector3.ClampMagnitude(alignment, maxSpeed);
        newVelocity += cohesion * 0.5f + separation * 15f + alignment * 1.5f;
        newVelocity = Vector3.ClampMagnitude(newVelocity, maxSpeed);
        velocity = (velocity * 2f + newVelocity) / 3f;//Добавлено для большей гладкости движения
        if (position.magnitude > 40)
        {
            velocity += -position.normalized;
        }
    }

With this function we get velocity. Now you need to move the bird, for this we add the Update function.
public void Update()
    {
        position += velocity * Time.deltaTime;
        Debug.DrawRay(position, separation, Color.green);//Здесь же мы рисуем лучи для отладки
        Debug.DrawRay(position, cohesion, Color.magenta);
        Debug.DrawRay(position, alignment, Color.blue);
    }

This completes the Boid class.
Now you need to display the birds no matter how.
To do this, I created an array of primitives that I moved on stage. All this was done in the Boids.cs script:
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class Boids : MonoBehaviour {
    GameObject[] boidsObjects;
	// Use this for initialization
	void Start () {
        boidsObjects = new GameObject[1500];//Создаём 1500 птиц
        boids = new Boid[boidsObjects.Length];
        for (int i = 0; i < boids.Length; i++)
        {
            GameObject boid = GameObject.CreatePrimitive(PrimitiveType.Cube);//Птицы будут кубами
            boid.transform.position = Random.insideUnitSphere * 35f;
            Destroy(boid.collider);//Удаляем колайдеры чтобы уменьшить лаги
            boidsObjects[i] = boid;
            boids[i] = new Boid(boid.transform.position);//Создаём объект Boid
        }
        StartCoroutine(UpdatePhis());//Функция InvokeRepeating мне не нравится
	}
    IEnumerator UpdatePhis()
    {
        while (true)
        {
            int UpdateCount = 0;
            for (int i = 0; i < boids.Length; i++)
            {
                boids[i].CalculateVelocity();
                UpdateCount++;
                if (UpdateCount > 100)//Чтобы ещё увеличить fps обрабатываем не всех птиц сразу
                {
                    yield return null;
                    UpdateCount = 0;
                }
            }
        }
    }
	// Update is called once per frame
	void Update () {
        for (int i = 0; i < boids.Length; i++)
        {
            boids[i].Update();//Двигаем птиц
            boidsObjects[i].transform.position = boids[i].position;
        }
	}
//Здесь я разместил замену OverlapSphere
    public static Boid[] boids;
    static public Boid[] Sphere(Vector3 position, float radius)
    {
        List mids = new List();
        for (int i = 0; i < boids.Length; i++)
        {
            if (Vector3.Distance(position, boids[i].position) < radius)
                mids.Add(boids[i]);
        }
        return mids.ToArray();
    }
}

We hang Boids.cs on the camera and launch. At 1,500 birds, I got 70 fps on my computer.
WebPlayer: here
Code: Download

Also popular now: