У меня есть куча объектов разного размера и скорости, которые тяготеют друг к другу. При каждом обновлении мне приходится проходить через каждый объект и складывать силы, связанные с гравитацией любого другого объекта. Он не очень хорошо масштабируется, это одно из двух больших узких мест, которые я нашел в своей игре, и я не уверен, что делать, чтобы улучшить производительность.
Такое ощущение, что я должен быть в состоянии улучшить производительность. В любой момент времени, вероятно, 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.
Любые мысли о том, как я мог бы улучшить это? Какая эвристика, которую я могу использовать, чтобы сократить длину цикла от сотен до нескольких? Какой код я могу выполнять реже, чем каждое обновление? Должен ли я просто многопоточить его, пока он не станет достаточно быстрым, чтобы позволить мир приличного размера? Стоит ли пытаться переложить расчеты скорости на графический процессор? Если так, то как бы я это разработал? Могу ли я хранить статические общие данные на графическом процессоре? Могу ли я создавать функции HLSL на графическом процессоре и вызывать их произвольно (используя XNA), или они должны быть частью процесса отрисовки?
G * m1 * m2 / r^2
, где G просто настроить поведение. (хотя я не могу просто заставить их следовать по пути, потому что пользователь может нарушить работу системы)