Прочитав пост про создание птичек на Unity3D, я решил предложить свой вариант оптимизации.
В Unity плохо размещать скрипт на каждом объекте, особенно если их очень много, появляются сильные лаги. Чтобы не вешать скрипт Boid.cs можно сделать по другому.
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/
Добавить комментарий