Что не так с моей функцией обновления положения планеты возле звезды?

Вначале код, кажется, работает, когда планета изгибается к звезде, но затем, когда он должен или втягиваться в звезду, или делать орбиту, он просто отталкивается в противоположном направлении. Что я делаю неправильно? Кажется, что изменение в поведении происходит, когда меняется знак расстояния.

if(!alive){
    return;
}
xPos += t * velocity/10000 * cos(direction / 180 * 3.14);
yPos += t * velocity/10000 * sin(direction / 180 * 3.14);

double gravity = 1000;
double starX = 1920/2;
double starY = 1080/2;

double deltaX = xPos - starX;
double deltaY = yPos - starY;
double distance = sqrt(pow(deltaX, 2) + pow(deltaY, 2));
int modifier = 1;
if (xPos > starX){
    modifier = -1;
}
double angle = atan(deltaY / deltaX) * 180 / 3.14;
std::cout << angle << std::endl;

xPos += t * gravity / pow(distance,2) * modifier * cos(angle / 180 * 3.14);
yPos += t * gravity / pow(distance,2) * modifier * sin(angle / 180 * 3.14);

if (xPos > starX - 100 && xPos < starX + 100 && yPos > starY - 100 && yPos < starY + 100){
    alive = false;
}

xPos и ​​yPos - текущее положение планеты. время, прошедшее с момента последнего обновления. скорость и направление - начальная скорость и угол, под которым начинается планета. Эта сила никогда не меняется, так как мы находимся в космосе. гравитация - это гравитационная постоянная. starX и starY - это положение звезды, а расстояние - это расстояние между звездой и планетой. угол - это угол между звездой и планетой (у меня такое ощущение, что именно это и вызывает нежелательное поведение.)

1 ответ

Ваша первая проблема - использовать atan(y/x) вместо atan2(y, x), что предназначено для того, чтобы избавить вас от проблем. В частности, когда x становится маленьким, atan2 справится должным образом, а atan не сможет справиться с y / x в тех же условиях. Я думаю, что это главная причина вашего взрыва, так как я воспринимаю ваш код на своих собственных условиях.

Сказав это, @Jim Lewis и @CodesInChaos также делают важные наблюдения. F=ma означает, что вы должны вывести ускорение из своих сил, а затем интегрировать ускорение, чтобы получить скорость (которая должна быть переменной состояния), и интегрировать скорость, чтобы получить положение. И если вы хотите, чтобы ваша программа была стабильной, когда планета превращается в звезду, вам понадобится более сложный метод интеграции. Ваш существующий метод известен как "метод Эйлера", и если вы посмотрите его в Википедии, вы получите представление о том, где вы стоите и куда вам следует идти.

Дополнительным уточнением было бы включение "умной тригонометрии". Заметьте, что когда у вас есть три стороны прямоугольного треугольника, нет необходимости вычислять угол для вычисления синуса и косинуса. В этом случае ваши стороны - это расстояние, deltaX и deltaY. Таким образом, вы можете сделать cosAngle = deltaX / distance и sinAngle = deltaY / distance и использовать их для вычисления компонентов ускорения. Чтобы убедиться в этом, вы можете проверить cosAngle*cosAngle + sinAngle*sinAngle = 1. Кроме того, их знак точно подходит для использования в остальной части вычисления.

Я думаю, вы обнаружите, что если вы "сделаете Эйлера правильно", точно реализуете уравнения движения и используете atan2 или умный триг, вы обнаружите, что вам вообще не нужен ваш хак "модификатор". Может получиться так, что если это для игры (ваш 1920/2,1080/2 заставляет меня поверить в это), и вы можете достаточно хорошо контролировать начальные условия и не перегружать систему слишком долго, вам может не понадобиться обновить от Эйлера.

Другие вопросы по тегам