У мене є купа предметів різної величини та швидкості, які тяжіють один до одного. Під час кожного оновлення я повинен переходити кожен об'єкт і додавати сили завдяки гравітації кожного іншого об'єкта. Це не дуже добре, це одне з двох великих вузьких місць, які я знайшов у своїй грі, і я не впевнений, що робити для підвищення продуктивності.
Таке враження, що я маю змогу покращити продуктивність. У будь-який момент часу, ймовірно, 99% об'єктів у системі матимуть лише незначний вплив на об’єкт. Я, звичайно, не можу сортувати об'єкти за масою і розглядаю лише 10 найбільших об'єктів чи щось подібне, тому що сила змінюється на відстані більше, ніж з масою (рівняння по лініях force = mass1 * mass2 / distance^2
). Я думаю, що хорошим наближенням було б розглянути найбільші об’єкти та найближчі об’єкти, ігноруючи сотні крихітних фрагментів скелі з іншого боку світу, які ніяк не можуть вплинути ні на що - але для того, щоб з’ясувати, які об’єкти є найближче мені доводиться повторювати всі об’єкти, і їх положення постійно змінюються, тож це не так, як я можу це зробити один раз.
В даний час я роблю щось подібне:
private void UpdateBodies(List<GravitatingObject> bodies, GameTime gameTime)
{
for (int i = 0; i < bodies.Count; i++)
{
bodies[i].Update(i);
}
}
//...
public virtual void Update(int systemIndex)
{
for (int i = systemIndex + 1; i < system.MassiveBodies.Count; i++)
{
GravitatingObject body = system.MassiveBodies[i];
Vector2 force = Gravity.ForceUnderGravity(body, this);
ForceOfGravity += force;
body.ForceOfGravity += -force;
}
Vector2 acceleration = Motion.Acceleration(ForceOfGravity, Mass);
ForceOfGravity = Vector2.Zero;
Velocity += Motion.Velocity(acceleration, elapsedTime);
Position += Motion.Position(Velocity, elapsedTime);
}
(зауважте, що я видалив багато коду - наприклад, тести зіткнення, я не повторюю об'єкти вдруге, щоб виявити зіткнення).
Тож я не завжди повторюю весь список - я роблю це лише для першого об'єкта, і кожного разу, коли об'єкт знаходить силу, яку він відчуває до іншого об'єкта, цей інший об'єкт відчуває ту саму силу, тому він просто оновлює обидва їх - і тоді цей перший об'єкт не потрібно розглядати знову для решти оновлення.
Функції Gravity.ForceUnderGravity(...)
і Motion.Velocity(...)
т. Д. Просто використовують трохи вбудованої XNA у векторну математику.
Коли два об'єкти стикаються, вони створюють безмасштабні сміття. Він зберігається в окремому списку, і масивні предмети не повторюються над сміттям як частина їх обчислення швидкості, але кожен шматок сміття повинен перебирати масивні частинки.
Це не повинно масштабуватися до неймовірних меж. Світ не є необмеженим, він містить межу, яка знищує предмети, які його перетинають - я б хотів обробляти, можливо, тисячу або близько предметів, в даний час гра починає задихатися близько 200.
Будь-які думки про те, як я міг би покращити це? Якийсь евристичний я можу використовувати для гоління довжини петлі від сотень до декількох? Який код я можу виконувати рідше, ніж кожне оновлення? Чи повинен я просто багатопрочитати його, поки він не стане досить швидким, щоб забезпечити світ пристойних розмірів? Чи варто спробувати вивантажити обчислення швидкості на GPU? Якщо так, то як я це архітектор? Чи можу я зберігати статичні, спільні дані на GPU? Чи можу я створити HLSL функції на графічному процесорі та викликати їх довільно (за допомогою XNA) чи вони повинні бути частиною процесу малювання?
G * m1 * m2 / r^2
, де G просто налаштувати поведінку. (хоча я не можу їх просто пройти шляхом, оскільки користувач може порушити систему)