Птички и Unity3D, попытка оптимизации

от автора

Прочитав пост про создание птичек на Unity3D, я решил предложить свой вариант оптимизации.

В Unity плохо размещать скрипт на каждом объекте, особенно если их очень много, появляются сильные лаги. Чтобы не вешать скрипт Boid.cs можно сделать по другому.

Создадим класс 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;     } } 

В этом классе будут производиться все расчёты. Чтобы сделать его независимым от игровых объектов необходимо заменить функцию Physics.OverlapSphere:

    public static Boid[] boids;     static public Boid[] Sphere(Vector3 position, float radius)     {         List<Boid> mids = new List<Boid>();         for (int i = 0; i < boids.Length; i++)         {             if (Vector3.Distance(position, boids[i].position) < radius)                 mids.Add(boids[i]);         }         return mids.ToArray();     } 

Эта функция будет находиться в другом классе.
Теперь можно добавить саму функцию расчётов:

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;         }     } 

С помощью этой функции мы получаем velocity. Теперь нужно двигать птицу, для этого добавим функцию Update.

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);     } 

На этом класс Boid закончен.
Теперь нужно как ни будь отобразить птиц.
Для этого я создал массив примитивов которые и перемещал на сцене. Всё это делалось в скрипте Boids.cs:

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<Boid> mids = new List<Boid>();         for (int i = 0; i < boids.Length; i++)         {             if (Vector3.Distance(position, boids[i].position) < radius)                 mids.Add(boids[i]);         }         return mids.ToArray();     } } 

Вешаем Boids.cs на камеру и запускаем. При 1500 птиц я получил 70 fps на своём компьютере.
WebPlayer: тут
Код: Скачать

ссылка на оригинал статьи https://habrahabr.ru/post/283064/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *