Расчёт физики космических объектов в 2D
Я совершеено сбит с толку. Почему в пресловутой Space Flight Simulator орбиты стабильны,замкнуты и подобны кругу, а мои орбиты напоминают ядро атома с электронами.
Возможно стоит использовать какой-то другой метод просчёта физики, который я не знаю, или у меня в рассчётах ошибки, я не уверен. Ниже мой код.
Сразу скажу, ошибки в конкретно отображении траектории нет, объект и правда движется чётко по траектории.
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 шт):
Это и есть эллипсоидная орбита, а не белиберда. С планетами происходит тоже самое, что и с спутниками. Плутон вообще в перегее становится ближе к солнцу, чем Нептун! Апогей и перигей могут не так сильно отличаться, всё зависит от стартовых параметров. Если знать, как считать можно и окружность получить.
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
, если не из свойств тел?
Хитрость в том, что при движении в гравитационном поле вектор силы меняется непрерывно, в зависимости от гравитационного потенциала, и если вы берёте значительные отрезки времени, то орбита тем сильнее отличается от эллипса, параболы или гиперболы - чем большей длины интервалы времени Вы используете. Простейшее решение - уменьшать интервалы времени между расчётными точками. Более сложное решение - получить точные формулы для расчёта движения по орбите, когда направление и модуль силы меняются непрерывно. Но тут надо решать дифференциальные уравнения. Если считаете не в декартовой, а в полярной системе координат, то надо ещё вычислять и добавить в формулу фиктивную силу Кориолиса.
Спасибо @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);
}