[Из песочницы] Птички и 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 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();
}
Эта функция будет находиться в другом классе.
Теперь можно добавить саму функцию расчётов:
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 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();
}
}
Вешаем Boids.cs на камеру и запускаем. При 1500 птиц я получил 70 fps на своём компьютере.
WebPlayer: тут
Код: Скачать