Расчёт физики космических объектов в 2D

Я совершеено сбит с толку. Почему в пресловутой Space Flight Simulator орбиты стабильны,замкнуты и подобны кругу, а мои орбиты напоминают ядро атома с электронами.

Возможно стоит использовать какой-то другой метод просчёта физики, который я не знаю, или у меня в рассчётах ошибки, я не уверен. Ниже мой код.

Сразу скажу, ошибки в конкретно отображении траектории нет, объект и правда движется чётко по траектории.

Space Flight Simulator

Мой Unity проект

void Gravity()
{
    if (planet == null) return;

    Vector2 dirToPlanet = (planet.transform.position - transform.position).normalized;
    float dist = dirToPlanet.magnitude;

    float gravityForce = gravitationalConstant * (shuttleMass * planetMass) / (dist * dist);

    Vector2 gravity = dirToPlanet * gravityForce;
    shuttleRB.AddForce(gravity * 0.1f);
}

Ответы (3 шт):

Автор решения: Yaroslav

введите сюда описание изображения

Это и есть эллипсоидная орбита, а не белиберда. С планетами происходит тоже самое, что и с спутниками. Плутон вообще в перегее становится ближе к солнцу, чем Нептун! Апогей и перигей могут не так сильно отличаться, всё зависит от стартовых параметров. Если знать, как считать можно и окружность получить.


Vector2 dirToPlanet = (planet.transform.position - transform.position).normalized;
// dist = 1, потому что normalized
float dist = dirToPlanet.magnitude;
// Vector2.magnitude - √(x²+y²)
// вычисление квадратных корней это операция занимающая много тактов процессора
// какой смысл вычислять квадратный корень dirToPlanet, если сразу же возводишь dist в корень?
// Vector2.sqrMagnitude - x²+y², то есть значение длины в квадрате
// п.с. что бы сравнить две длины, вычислять их корни тоже нет смысла
float gravityForce = gravitationalConstant * (shuttleMass * planetMass) / (dist * dist);

shuttleRB.AddForce(gravity * 0.1f);

А почему используется AddForce, а не присваивание свойства velocity? AddForce учитывает дельту времени симуляции и массу RidgidBody (+= force * FixedDeltaTime / mass). А откуда взяты shuttleMass и planetMass, если не из свойств тел?

→ Ссылка
Автор решения: Виктор

Хитрость в том, что при движении в гравитационном поле вектор силы меняется непрерывно, в зависимости от гравитационного потенциала, и если вы берёте значительные отрезки времени, то орбита тем сильнее отличается от эллипса, параболы или гиперболы - чем большей длины интервалы времени Вы используете. Простейшее решение - уменьшать интервалы времени между расчётными точками. Более сложное решение - получить точные формулы для расчёта движения по орбите, когда направление и модуль силы меняются непрерывно. Но тут надо решать дифференциальные уравнения. Если считаете не в декартовой, а в полярной системе координат, то надо ещё вычислять и добавить в формулу фиктивную силу Кориолиса.

→ Ссылка
Автор решения: Egor

Спасибо @StanislavVolodarskiy за ответ на вопрос, пусть, к сожалению, и комментарием:

dist всегда равен единице, он вычисляется от нормализованного вектора.

Правильным решением этой проблемы будет простое:

void Gravity()
{
    if (planet == null) return;

    // Убрать .normalized
    Vector2 dirToPlanet = (planet.transform.position - transform.position);

    float dist = dirToPlanet.magnitude;

    float gravityForce = gravitationalConstant * (shuttleMass * planetMass) / (dist * dist);
    
    // Перенести .normalized сюда
    Vector2 gravity = dirToPlanet.normalized * gravityForce; 

    shuttleRB.AddForce(gravity * 0.1f);
}

введите сюда описание изображения

→ Ссылка