W świetle kontekstu pytania, http://nodewar.com/ , istnieje kilka szczegółowych uwag dotyczących twojego rozwiązania:
- Masz (niską) maksymalną prędkość kątową i wystarczający maksymalny moment obrotowy, aby ją osiągnąć w bardzo krótkim czasie.
- Zarówno twój dron, jak i cel mają prędkość i przyspieszenie zewnętrzne niezwiązane z pchnięciem (obfituje grawitacja).
- Wybrany cel zmienia się tak często, że próba doskonałego celu byłaby stratą. Powinieneś spróbować zbliżyć się i poprawić go co klatkę.
Metody te postanowiłem wykorzystać do osiągnięcia pożądanego przyspieszenia.
Przyspieszenie, a nie prędkość
Ponieważ masz już określoną prędkość, a twój cel się porusza, nie potrzebujesz pchnięcia w kierunku punktu. Potrzebujesz ciągu, aby zmienić prędkość na taką, jaka powinna być. Oznacza to, że twój statek musi wskazywać nie w kierunku, w którym zmierza, ale w kierunku, w którym powinien przyspieszyć.
// My target velocity is for maintaining a circular orbit. Yours may differ.
// Earlier, I calculated total gravity and the perpendicular direction.
// You may wish to subtract gravity from your total, rather than match it.
var targetVel = o.lib.vec.times(lateralDir, targetVelMag);
var targetAccel = lv.sum(
o.lib.vec.diff(targetVel, o.me.vel),
o.lib.vec.times(gravity, 1 / o.me.mass)
);
Kierowanie w prawo
Masz wektor przyspieszenia, teraz chcesz go zastosować. Określ, jak daleko trzeba obrócić. Prawdopodobnie użyłem więcej kroków, niż jest to wymagane, ale wprawiają mnie w zakłopotanie współrzędne i myślę, że nielimitowana wartość obrotu statku i tak jest błędem w API.
// convert acceleration to an angle
var polar = o.lib.vec.toPolar(targetAccel);
var traj = polar[1];
// constrain the angle to +/-2PI, because the ship's rotation is not limited
// by default
var fixed_rot = o.lib.ang.rescale(o.me.rot);
// limit the correction to be +/-1PI
var traj_correction = traj - fixed_rot;
if (traj_correction > (Math.PI)){
traj_correction = (2 * Math.PI) - traj_correction;
} else if (traj_correction < (-1 * Math.PI)){
traj_correction = (2 * Math.PI) + traj_correction;
}
Prosta formuła. Cały czas obracanie jest bezpieczne, więc nie zawracaj sobie głowy zastosowaniem częściowych wartości momentu obrotowego. Jeśli potrzebujesz niewielkiej korekty prędkości kątowej, i tak możesz to ustalić wiele razy na sekundę.
if (traj_correction > 0){
torque = 1;
} else if (traj_correction < 0){
torque = -1;
}
Mniej prosta formuła. Nadejdzie moment, w którym nie będziesz chciał kontynuować skręcania, ponieważ w końcu chcesz przestać. Na szczęście to ograniczenie prędkości kątowej oznacza, że możesz szybko zwolnić od maksymalnej prędkości kątowej do zera. Musisz tylko obliczyć, kiedy to zrobić.
var max_a_accel = c.MAX_TORQUE / o.me.m_i;
var a_deccel_time = Math.abs(o.me.a_vel) / max_a_accel;
// the same math as linear acceleration, now in angles.
var stopping_angle = 0.5 * max_a_accel * a_deccel_time * a_deccel_time;
if (stopping_angle >= Math.abs(traj_correction)){
// slowdown required. Reverse torque
torque *= -1;
}
Po poprawieniu powyższego kodu, aby dopasować go do twoich potrzeb, twój statek powinien szybko i precyzyjnie obrócić się pod dowolnym kątem, który podałeś do celu.
Szybkość taranowania
Kiedy więc pchnąć? Ponownie szybka zmiana celu i inne czynniki powodują ogromne trudności w rozwiązaniu dokładnego rozwiązania. Nie próbuj.
// if the heading is close to the final value, thrust.
if (Math.abs(traj_correction ) < 0.02) { // about 1 degree
if (true
// some logical test, in case you don't want to accelerate past
// a maximum speed, or some such. Not required for your stated purpose.
){
thrust = 1;
}
}
W przypadkach, w których potrzebujesz częściowego ciągu, możesz ponownie polegać na tym, że możesz wybierać między 0 a 1 ciągiem wiele razy na sekundę. Zapewnia to efektywny ciąg cząstkowy bez zmiany rzeczywistej wartości.
Powodzenia!