Ruch statku kosmicznego

0

Witam, obecnie zajmuję się ruchem statku kosmicznego i mam taki oto problem - statek ma mieć prędkość maksymalną, swoje przyspieszenie, prędkość. Udało mi się zrobić już bardzo dobry kod, ale ma jedną wadę, którą chcę usunąć - otóż, ruch na osiach x i y może zachodzić z jednakową prędkością, więc poruszając się w kierunku rogu ekranu statek osiąga znacznie większą prędkość niż powinien (obecnie jako maksimum ustawiłem 3, ale będzie to zmienna wartość).

Oto, co na ten moment udało mi się zrobić:

    ActionListener TimerTick = new ActionListener() {
    @Override
    public void actionPerformed(ActionEvent e) {
        
        pane.repaint();
        pane.add(panel);
        if (rotate<0.0) {rotate = 2*Math.PI;}
        if (rotate>2*Math.PI) {rotate = 0.0;}
        if (rightKeyPressed==true) {rotate=rotate+0.05;}
        if (leftKeyPressed==true) {rotate=rotate-0.05;}
        xLoc = xLoc - xThrust;
        yLoc = yLoc + yThrust;
        totalThrust = Math.abs(xThrust)+Math.abs(yThrust);
        if (upKeyPressed==true) {
            xAccel = (Math.sin(rotate)*0.05);
            yAccel = (Math.cos(rotate)*0.05);
                xThrust = xThrust-xAccel;
                yThrust = yThrust-yAccel;
        }
        if (downKeyPressed==true) {
            if (xThrust<0.05 && xThrust>-0.05) {xThrust=0;}
            else if (xThrust<=-0.05) {xThrust=xThrust+0.05;}
            else if (xThrust>=0.05) {xThrust=xThrust-0.05;}
            if (yThrust<0.05 && yThrust>-0.05) {yThrust=0;}
            else if (yThrust<=-0.05) {yThrust=yThrust+0.05;}
            else if (yThrust>=0.05) {yThrust=yThrust-0.05;}
        }
        
        if (xThrust>3) {xThrust=3;}
        if (xThrust<-3) {xThrust=-3;}
        if (yThrust>3) {yThrust=3;}
        if (yThrust<-3) {yThrust=-3;}
        
}
};

Da się go zmodyfikować tak, aby maksymalną prędkością dopuszczalną na obu osiach było 3, a w przypadku, w którym statek poruszający się z pełną prędkością zakręca pojazd odpowiednio zmodyfikował swoją prędkość?

1

Wyraź prędkość i przyspieszenie jako skalary, a nie wektory. Dopiero na końcu oblicz przesunięcie używając trygonometrii.

accel = ...; // aktualne przyspieszenie
speed += accel; // modyfikujemy aktualną prędkość zgodnie z przyspieszeniem, tu możesz od razu ograniczyć ją z góry i dołu

/* wyznaczamy nową pozycję statku */
x += Math.cos(rotation) * speed;
y += Math.sin(rotation) * speed;
0

Ja tu wcale nie widzę "bardzo dobrego kodu"... 30 linijek samych ifów to jest tragiczny kod.
Powinieneś liczyś prędkość całkowitą prędkość statku (długość wektora chyba umiesz policzyć?) i jeśli jest za duża to korygować prędkość proporcjonalnie na obu współrzędnych.

1
        if (rotate<0.0) {rotate = 2*Math.PI;}
        if (rotate>2*Math.PI) {rotate = 0.0;}
        if (rightKeyPressed==true) {rotate=rotate+0.05;}
        if (leftKeyPressed==true) {rotate=rotate-0.05;}

Tu jest niefajnie.

        if (rightKeyPressed && !leftKeyPressed) {
                rotate+=agility;
                if (rotate>2*Math.PI) {rotate-=2*Math.PI;}
        } else if (leftKeyPressed && !rightKeyPressed) {
                rotate-=agility;
                if (rotate<0) {rotate+=2*Math.PI;}
        }
0

Niech VX i VY będą wektorami prędkości wzdłuż odpowiednio osi X i osi Y oraz niech kąt ALFA będzie kątem nachylenia statku od tej z osi, dla której kąt ALFA będzie krótszy. W takim wypadku można utworzyć trójkąt prostokątny, gdzie przyprostokątnymi są VX i VY, zaś kąt ALFA jest przy tym boku, którego wybraliśmy wcześniej - oznaczmy tą przyprostokątną przez B, a drugą przyprostokątną przez A. Chcąc wyliczyć wektor prędkości dla trasy odbiegającej od osi X lub Y, należy policzyć przeciwprostokątną C. Możemy ją policzyć ze wzorów: csc ALFA * a lub sec ALFA * b.

Jeżeli się mylę, dajcie mi znać.

0

Oto, jak wygląda mój obecny kod:

    ActionListener TimerTick = new ActionListener() {
    @Override
    public void actionPerformed(ActionEvent e) {
        
        pane.repaint();
        pane.add(panel);
        if (rightKeyPressed && !leftKeyPressed) {
                rotate+=0.05;
                if (rotate>2*Math.PI) {rotate-=2*Math.PI;}
        } else if (leftKeyPressed && !rightKeyPressed) {
                rotate-=0.05;
                if (rotate<0) {rotate+=2*Math.PI;}
        }
        xLoc += Math.sin(rotate) * Thrust;
        yLoc -= Math.cos(rotate) * Thrust;
        if (upKeyPressed==true) {
            Accel = 0.2;
            Thrust += Accel;
            if (Thrust>6) {Thrust=6;}
        }
        if (downKeyPressed==true) {
            if (Thrust<Accel && Thrust>-Accel) {Thrust=0;}
            else if (Thrust<=-Accel) {Thrust=Thrust+Accel;}
            else if (Thrust>=Accel) {Thrust=Thrust-Accel;}
        }
}
};

Wszystko działa perfekcyjnie, mam jeszcze dodatkowe pytanie - można zrobić coś, aby była zachowana kosmiczna "bezwładność"? Przez bezwładność rozumiem możliwość ruchu niezależnie od kierunku, w którym zwrócony jest pojazd (przykładowo: najpierw przyspieszamy poruszając się w górę, zwalniamy przycisk, zmieniamy nachylenie statku tak, aby był zwrócony ku prawej stronie - pojazd dalej porusza się w górę - a następnie przyspieszamy, co skutkuje wraz z upływem czasu zmianą kierunku).

0

Wszystko się da, tylko zanim zaczniesz to coś programować, musisz to najpierw wyliczyć na kartce, zrobić jakiś wzór czy coś w tym stylu, a później po prostu wstawić ten wzór do kodu.

0
norbi452 napisał(a):

Wszystko się da, tylko zanim zaczniesz to coś programować, musisz to najpierw wyliczyć na kartce, zrobić jakiś wzór czy coś w tym stylu, a później po prostu wstawić ten wzór do kodu.

Właśnie z tego powodu zwracam się o Waszą pomoc - nie mam pomysłu, jaki wzór można tu zastosować - myślę nad tym zagadnieniem już od wczoraj, a wciąż nie udało mi się zrobić znaczących postępów.

1

A może wymyślisz coś na podstawie ruchu jednostajnie przyspieszonego? Wzór na przebytą drogę to s = s0 + v0*t + (at2 / 2), gdzie s0 to droga początkowa ciała (jeżeli zaczynasz liczyć od początku ruchu, wynosi ona 0), v0 to prędkość początkowa, a to przyspieszenie, t to czas trwania ruchu. Jest to wzór na ruch jednostajnie przyspieszony, jeżeli chcesz wyliczyć ruch opóźniony, zamiast at2 dajesz (-a)t2. Więc gdy przestaje lecieć, ustalasz v0 na prędkość statku i wyliczasz.

2

W tym wypadku lepiej jest rozbić prędkość na składowe x i y. Pseudokod:

pozycja statku: x, y, rotation
prędkość statku: speed_x, speed_y
przyspieszenie: accel

wyznaczamy nową prędkość:

speed_x += cos(rotation) * accel
speed_y += sin(rotation) * accel

ograniczamy prędkość:

speed = (speed_x^2 + speed_y^2)^0.5
if speed > max_speed
        speed_x = max_speed * speed_x / speed
        speed_y = max_speed * speed_y / speed

przemieszczamy statek:

x += speed_x
y += speed_y
0

Udało się!

Umieszczę tu gotowy kod, może komuś, kto miałby kiedyś podobny problem się przyda:

    ActionListener TimerTick = new ActionListener() {
    @Override
    public void actionPerformed(ActionEvent e) {
        
        pane.repaint();
        pane.add(panel);
        if (rightKeyPressed && !leftKeyPressed) {
                rotate+=0.05;
                if (rotate>2*Math.PI) {rotate-=2*Math.PI;}
        } else if (leftKeyPressed && !rightKeyPressed) {
                rotate-=0.05;
                if (rotate<0) {rotate+=2*Math.PI;}
        }
        
        Thrust = Math.pow(Math.pow(xThrust, 2) + Math.pow(yThrust, 2), 0.5);
        if (Thrust>6) {
            xThrust = 6 * xThrust / Thrust;
            yThrust = 6 * yThrust / Thrust;
        }
        xLoc += xThrust;
        yLoc -= yThrust;
        if (upKeyPressed==true) {
            Accel = 0.2;
            xThrust += Math.sin(rotate)*Accel;
            yThrust += Math.cos(rotate)*Accel;
        }
        if (downKeyPressed==true) {
            if (xThrust<Accel && xThrust>-Accel) {xThrust=0;;}
            else if (xThrust<=-Accel) {xThrust=xThrust+Accel;}
            else if (xThrust>=Accel) {xThrust=xThrust-Accel;}
            if (yThrust<Accel && yThrust>-Accel) {yThrust=0;;}
            else if (yThrust<=-Accel) {yThrust=yThrust+Accel;}
            else if (yThrust>=Accel) {yThrust=yThrust-Accel;}
        }
}
};

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.