Podążanie za obiektem w przestrzeni 2D

Podążanie za obiektem (np. kursorem), od punktu do punktu, inaczej mówiąc: interpolacja liniowa.

Ostatnio zauważyłem, że wiele osób ma problem z dość prostym do rozwiązania problemem: ruchu obiektu do określonego punktu (np. do kursora myszy), całość może też być wykorzystana w np. podążaniu za obiektem.

W tym krótkim wpisie pokażę Wam jak takie coś wykonać na przykładzie programu w SFML, gdzie koło podąża za kursorem myszy (demo jest na samym końcu wpisu)

 

Trochę matematyki…


Krótki wstęp teoretyczny (mam nadzieję, że tak prostych rzeczy nie muszę specjalnie długo tłumaczyć).

Niewiele osób zdaje sobie sprawę, że płynne poruszanie obiektu z punktu do punktu to nic innego jak wektor, dokładnie ten sam, który poznaje się w liceum.

linear

Co zrobić aby uzyskać wektor przemieszczenia od punktu A do punktu B? Dokładnie! Musimy od współrzędnych punktu B odjąć współrzędne punktu A.

Aby uzyskać płynne poruszanie się od punktu A do punktu B, to należy przemieścić obiekt o w*delta_time (delta_time to przyrost klatek na sekundę). Jednak w tej postaci przesunięcie nie będzie stałe tzn. im mniejsza odległość od celu, tym mniejsza prędkość.

Jeżeli zależy nam na zlikwidowaniu tego zjawiska to musimy otrzymany wektor znormalizować, tzn sprawić że jego wartości x/y będą znajdowały się w przedziale [-1,1]. Normalizacja odbywa się przez podzielenie składowych wektora przez jego początkową długość.

 

Demo


Demo napisane w SFML przedstawiające jak napisać kod, w którym obiekt porusza się w stronę kursora.

@filipekczek7 pokazał jak zrobić poruszanie się obiektu do punktu tutaj.

 

Code ON!


  • Patrycjerz

    Kod fajny, zrobiony ciekawym sposobem (nie wiedziałem, że istnieje coś takiego, jak normalizacja wektora), ale zauważyłem ten sam błąd, co w mojej implementacji poruszania obiektu za kursorem, a chodzi o dzielenie przez zero (wiersz 30). Jeśli zaistnieje taka sytuacja, to metoda move dostanie jakąś niezdefiniowaną wartość i obiekt zniknie z ekranu. Oczywiście można to łatwo rozwiązać, dodając if(length).

    Także radzę ci stosować ograniczenie liczby klatek na sekundę, ponieważ program zżera mi aż 6,5% mocy procesora. Gdy użyję metody setFramerateLimit (sf::RenderWindow) z przykładową wartością 100, to spada to praktycznie do zera.

    Pozdrawiam!

    • Faktycznie, nie uwzględniłem case’a gdzie oba wektory są identyczne 😛 Dzięki za zwrócenie uwagi

      Pozdrawiam

  • filipekczek7

    Kurczę, Patrycjerz był szybszy: ja też chciałem powiedzieć coś o tym, że jak nasza, hm, postać, będzie już na swoim miejscu to już nie musi się ruszać, ale ważne, że ktoś to zauważył 😉

    Super kod, prosty i przejrzysty, po zanalizowaniu kodu Patrycjerza (na forum) ten zrozumiałem od razu. Ten efekt zwalniania jest nbardzo fajny, a jaki prosty 🙂 Powtarzam jeszcze raz, super pomysł 😉

    Tylko że ja mam jeszcze jedno pytanko, które już zadałem Patrycjerzowi parę razy i jeszcze o nim dyskutujemy: czemu wektor mnoży się przez czas pomiędzy klatkami? Rozumiem, że gdyby nie to, to kształt by miał wielką prędkość, a tak jak się pomnoży przez np. 0,03 to będzie się poruszał normalniej, a za pomocą zmiennej speed prosto się ustala prędkość. Dużo pokręciłem, ale to właśnie dlatego, że niezbyt wiem, dlaczego to się tak mnoży, byłbym bardzo wdzięczny za wytłumaczenie, sprawdzę, czy Patrycjerz wytłumaczy mi to podobnie 😉 Dzięki bardzo!

    • Odpowiedź jest dość banalne: dzięki temu prędkość poruszania nie zależy od ilości klatek na sekundę, czyli czasu pomiędzy wyświetleniem kolejnej klatki. W ten sposób niwelujesz problem jaki istniał przy jakiejś grze wyścigowej: prędkość poruszania pojazdu zależała od ilości fps (im lepszy komputer tym szybszy samochód). Otrzymana w ten sposób wartość jest bardzo mała, dlatego należy pomnożyć ją przez jakąś większą wartość 😉

      • filipekczek7

        O kurczę, rzeczywiście! Bardzo proste, dzięki za wytłumaczenie 😉

      • filipekczek7

        No, wreszcie wszedłem na kompa i zająłem się tym kodem i wykombinowałem ruch obiektu przez kliknięcie, zamiast przytrzymanie myszy, taki point-and-click wydaje mi się lepszym rozwiązaniem 😉 Tutaj kod dla potomnych i ciekawych 😉

        • To raczej trudne zadanie nie było, jeżeli możesz to zedytuj swojego posta, a kod wrzuć na pastebin’a czy coś w tym stylu i zostaw linka do niego w komentarzu.

          • filipekczek7

            No pewnie, że trudne nie było, początkujący też by mógł takie coś zrobić. Mimo to i tak na początku miałem parę problemów 😐 A kod dałem jakby ktoś chciał od razu skopiować i wkleić 😉

          • Demo jest na tyle sympatyczne, że podrzucę też link bezpośrednio do wpisu

          • filipekczek7

            O, jak miło 🙂 Fajnie, dzięki 😉

  • pw1602

    Błąd:
    Początek postu:
    Musimy od współrzędnych punktu B musimy odjąć współrzędne punktu A.”

    Koniec postu:
    „(…)w który kliknięto to(…)”

    • Tradycyjnie błędy typowo językowe, ale dzięki za zwrócenie uwagi.