• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

Poruszanie obiektem względem pozycji

Object Storage Arubacloud
0 głosów
1,612 wizyt
pytanie zadane 27 września 2015 w C i C++ przez Avernis Nałogowiec (27,400 p.)
zmienione kategorie 27 września 2015 przez Avernis
Jak można poruszać obiektem względem pozycji, czyli np obiekt jest na pozycji 0, 0, a ja kliknę myszką i mi zacznie się poruszać do pozycji tam gdzie kliknołem myszkę

3 odpowiedzi

+2 głosów
odpowiedź 27 września 2015 przez Patrycjerz Mędrzec (192,320 p.)
wybrane 27 września 2015 przez Avernis
 
Najlepsza
//Poruszanie obiektu w stronę kursora myszy o podaną prędkość
//2015 Patrycjerz

#include <SFML/Graphics.hpp>
#include <cmath>

int main()
{
    sf::RenderWindow window(sf::VideoMode(600, 600), "Test"); // Stworzenie okna
    window.setFramerateLimit(100); // Nadanie maksymalnej wartości FPS na 100

    sf::Event event; // Obiekt zdarzeń

    sf::Clock clock; // Obiekt zegara

    sf::Time time; // Obiekt czasu

    const float rectangle_x = 50; // Szerokość kwadratu
    const float rectangle_y = 50; // Wysokość kwadratu

    sf::RectangleShape rectangle(sf::Vector2f(rectangle_x, rectangle_y)); // Stworzenie kwadratu
    rectangle.setFillColor(sf::Color::Red); // Nadanie mu koloru czerwonego

    sf::Vector2i mouse_position; // Pozycja kursora myszy

    const float velocity_value = 100; // Wartość wektora prędkości

    sf::Vector2f velocity(0, 0); // Składowe wektora prędkości

    float x; // Różnica pozycji iksowych kursora i kwadratu
    float y; // Różnica pozycji igrekowych kursora i kwadratu
    float z; // Odległość pomiędzy kursorem i kwadratem

    while(window.isOpen())
    {
        // Zdarzenia
        while(window.pollEvent(event))
        {
            if(event.type == sf::Event::Closed)
                window.close();
        }

        mouse_position = sf::Mouse::getPosition(window); // Pobranie pozycji kursora myszy

        if(sf::Mouse::isButtonPressed(sf::Mouse::Left)) // Jeśli naciśnięty lewy przycisk myszy
        {
            x = static_cast<float>(mouse_position.x) - rectangle.getPosition().x - (rectangle_x / 2); // Obliczenie różnicy pozycji iksowych kursora i kwadratu
            y = static_cast<float>(mouse_position.y) - rectangle.getPosition().y - (rectangle_y / 2); // Obliczenie różnicy pozycji igrekowych kursora i kwadratu
            z = sqrtf(x * x + y * y); // Obliczenie odległości pomiędzy kursorem i kwadratem za pomocą twierdzenia Pitagorasa
            velocity.x = (x * velocity_value) / z; // Obliczenie składowej iksowej wektora prędkości za pomocą własności podobieństwa trójkątów
            velocity.y = (y * velocity_value) / z; // Obliczenie składowej igrekowej wektora prędkości za pomocą własności podobieństwa trójkątów

            rectangle.move(velocity.x * time.asSeconds(), velocity.y * time.asSeconds()); // Przesunięcie kwadratu o podany wektor prędkości
        }
        window.clear(); // Czyszczenie ekranu
        window.draw(rectangle); // Narysowanie kwadratu
        window.display(); // Wyświetlenie wszystkiego na ekranie

        time = clock.getElapsedTime(); // Nadanie zmiennej czasowej nowej wartości
        clock.restart(); // Restart zegara (mierzy czas od nowa/od zera)
    }
    return 0;
}

Kolejny raz piszę program "na zamówienie", ale dzięki temu umiem zrobić coś takiego (sam myślałem nad tym chwilę). Więc wilk syty i owca cała smiley

komentarz 27 września 2015 przez Avernis Nałogowiec (27,400 p.)
A czy da się jakoś ten kod zmienić tak aby kwadrat szedł do pozycji gdzie jest myszka a nie w stronę gdzie się klikneło myszką? Nie chodzi mi to od razu o cały kod, ale żeby mi tylko powiedzieć gdzie jakieś zmiany wprowadzić.
komentarz 27 września 2015 przez Patrycjerz Mędrzec (192,320 p.)
Po prostu usuń tego ifa i po kłopocie.
komentarz 27 września 2015 przez niezalogowany
Uwielbiam takie skomplikowane kody ;D Ale uwielbiam je jeszcze bardziej, jak je do końca zrozumię ;) Mnie intrygują linijki 46-54 i 59-60. Nie rozumię jeszcze za bardzo zegara i po co on jest. No, tak, do mierzenia czasu, pętla stałokrokowa, blablabla. Wiem czym jest twierdzenie Pitagorasa, co robią poszczególne funkcje (np. time.asSeconds() zwraca wartość w sekundach, a clock.restart() restartuje zegar), ale chciałbym bardziej zrozumieć ich działanie, szczególnie wzory i zegar (zegar, czas). Czy mógłbyś bardziej wytłumaczyć te linijki co ci podałem? Byłbym bardzo wdzięczny :) Nie musisz się śpieszyć ;)
komentarz 27 września 2015 przez Patrycjerz Mędrzec (192,320 p.)

Nie ma sprawy, nawet podrzucę ci rysunki, ale daj mi czas wink Dla mnie to radość, że komuś się podoba moja praca.

komentarz 27 września 2015 przez niezalogowany
Dla mnie to radość, jak zrozumię ;D Spoko, nie musisz się spieszyć, chciałbym zrozumieć wszystko po kolei, żeby potem samemu takie bajery wymyślać ;)

PS: to z twierdzeniem Pitagorasa to było chyba w kursie Pana Mirosława, jak mówił jak wykorzystać chyba bibliotekę matematyczną, właśnie na przykładzie takiego point-and-click'a.
komentarz 27 września 2015 przez Avernis Nałogowiec (27,400 p.)
Nie do końca o to mi chodziło. Chodzi o to że jak nacisne to się porusza w to miejsce gdzie nacisnołem
komentarz 27 września 2015 przez Patrycjerz Mędrzec (192,320 p.)
edycja 27 września 2015 przez Patrycjerz

Najpierw omówienie klas odpowiedzialnych za czas:

  • Tworzymy sobie obiekt sf::Clock - jest to zegar, który mierzy czas (w swoich cyklach) od swojego stworzenia lub od wywołana metody restart.
  • Potem przydałoby się przekonwertować cykle zegara np. na sekundy. Tworzymy więc obiekt sf::Time, który będzie nam przechowywał wartość czasu w cyklach (pobraną z zegara za pomocą getElapsedTime), a potem konwertujemy to na sekundy za pomocą asSeconds.

Teraz omówienie, jak czas jest wykorzystywany:

  • Wszystko opiera się na mierzeniu czasu poprzedniej klatki i wykorzystaniu go w następnej.
  • Po stworzeniu odpowiednich obiektów, np. na końcu pętli, pobieramy sobie czas z zegara do obiektu czasu (zauważ, że obiekt sf::Time zawiera przy pierwszym obiegu pętli czas równy zeru, ponieważ jeszcze nie było klatki poprzedniej, dostaje ją dopiero przy jej końcu). Potem restartujemy sobie zegar, aby mieć nowy czas i to chyba tyle (nie ma to związku z pętlą stałokrokową. Odpowiednie FPS tworzy użycie metody setFramerateLimit).

Teraz sama mechanika ruchu:

  • Najpierw prędkość: jest ona wektorem (może być także sama wartość, ale wektor jest skierowany, a samą wartością nic nie zrobimy). Jest to zagadnienie z fizyki, ale jakie przydatne smiley Więc jeśli jakiś obiekt posiada wektor prędkości, to można go rozłożyć na dwie składowe:Wektor wypadkowy jest to suma współrzędnych wektorów składowych (wektor ma współrzędne x i y, ponieważ posiada jakiś kierunek). Np. wektor składowy X ma współrzędne: x = -10 i y = 0. Długość wektora prędkości to inaczej przesunięcie obiektu o daną jednostkę czasu, np. v = 10 km/s, to po wektor ma 10 km długości i po sekundzie o tyle się przesunie obiekt (elementarna fizyka). Ogólnie radzę używać wektorów w swoich grach, gdzie tylko się da, bo to bardzo ułatwia sprawę.
  • Tutaj masz rysunek, który pokazuje, co robi program, aby poruszyć obiekt:Więc obliczamy sobie różnice współrzędnych środka obiektu i pozycji kursora (x i y na rysunku). Reszta to tw. Pitagorasa i stosunki boków trójkątów podobnych (to znajdziesz bez problemu w sieci).
  • Potem tylko przemieszczamy dany obiekt o odległość = długość wektora * czas w sekundach (w programie trzeba to liczyć dla współrzędnych x i y).
komentarz 27 września 2015 przez Patrycjerz Mędrzec (192,320 p.)
Avernis, ale masz problem... zapisz sobie gdzieś współrzędne kursora, gdy klikniesz przycisk, a potem liczenie to samo.
komentarz 27 września 2015 przez Avernis Nałogowiec (27,400 p.)
ok, szczęście że jestem anonimowy xD
komentarz 27 września 2015 przez Patrycjerz Mędrzec (192,320 p.)
Szczęście szczęściem, ale praktycznie podałem ci rozwiązanie na tacy, a jakieś modyfikacje możesz robić przecież sam, bo nie są trudne.
komentarz 27 września 2015 przez niezalogowany
@Patrycjerz - ale to po co jest obiekt czasu, sf::Time? Potem, przesuwając obiekt, mnoży się czas w sekundach przez odległość od kwadratu do punktu kliknięcia, ale niezbyt rozumiem po co to O_o
komentarz 27 września 2015 przez Patrycjerz Mędrzec (192,320 p.)

Obiekt sf::Time jest po to potrzebny, aby przetrzymywać czas, bo zegar może być jeden, a czasów trochę więcej. Także dla metody asSeconds.

Z tym mnożeniem się nieco pomyliłeś. Mnoży się czas w sekundach i długość wektora prędkości (może być on jaki chcesz, nawet większy, niż odległość pomiędzy kwadratem i położeniem kursora, tylko wtedy kwadrat będzie ci "zapierniczać", aż miło laugh). Jak już mówiłem, długość wektora prędkości to przesunięcie obiektu w czasie jednej jednostki czasu (dla 10 px/s, po sekundzie obiekt przesunie się o 10 pikseli, w 2,5 sekundy o 25 pikseli, czyli o 2,5 wektora). Po prostu wektor to wartość i także kierunek. Nie ma tu niczego trudnego, mówię ci. Wektory są banalne, wystarczy chwilę z nimi popracować.

Zapomniałem dodać, że długość wektora prędkości w moim kodzie jest stała (masz tam const). Oczywiście możesz ją zmieniać, ale ja zrobiłem ją niezmienialną dla potrzeb przykładu.

komentarz 21 stycznia 2018 przez PsyLisek Użytkownik (570 p.)

@Patrycjerz

Trochę czasu minęło od twoich wypowiedzi, ale chciałbym Ci podziękować. O wiele ułatwiłeś mi pracę, a przy okazji wytłumaczyłeś po co jest potrzeby w pętlach w grze sf::Time.

0 głosów
odpowiedź 27 września 2015 przez Dorion300 Szeryf (90,250 p.)
Analizujesz gdzie jest myszka np. 34x53

I zmieniasz pozycję obiektu na 34x53
komentarz 27 września 2015 przez Avernis Nałogowiec (27,400 p.)
Ok, ale jak amienić na ą pozycję, wim jak zmienić np że się zmienia o 10 pikseli lub więcej/mniej ale nie wiem jak zmienić pozycje względem okna
0 głosów
odpowiedź 27 września 2015 przez niezalogowany

Nie jestem pewny do końca o co ci chodzi:

  1. Posługiwaniem się pozycją obiektów względem okna, a nie pulpitu, czyli (0,0) jest w lewym górnym rogu okna, a nie pulpitu (wtedy wystarczy użyć sf::Mouse::getPosition(window), gdzie window to obiekt sf::RenderWindow)
  2. Liczeniem pozycji wg dowolnego punktu na scenie.
komentarz 27 września 2015 przez Avernis Nałogowiec (27,400 p.)
chodzi o to że obiekt porusza się tam gdzie kliknołem myszką
komentarz 27 września 2015 przez niezalogowany

W takim razie twoje pytanie mnie zmyliło, to akurat jest proste. Po prostu musisz odjąć od pozycji myszy pozycję obiektu, który ma się ruszyć, następnie mnożysz otrzymany wektor przez prędkość jaką chcesz uzyskać i czas pomiędzy klatkami.

Vector2f mouse(sf::Mouse::getPosition(window));

RectangleShape obj; // <- załóżmy że to obiekt, który chcesz przesunąć
Vector2f objPos(obj.getPosition()); // <-pozycja obiektu do przesunięcia


obj.move( mouse - objPos * speed * delta);

Jeżeli obiekt ma się poruszać ze stałą prędkością (a nie jak teraz w przykładzie: bliżej do obiektu tym wolniej się porusza) to musisz go znormalizować.

Z tego co pamiętam to nie ma przeładowanych operatorów do Vector2f, więc musisz moje odjęcie wektrów rozbić na:

(mouse.x - objPos.x * speed * delta, ... )

 

Podobne pytania

0 głosów
3 odpowiedzi 570 wizyt
pytanie zadane 1 października 2015 w C i C++ przez Avernis Nałogowiec (27,400 p.)
+1 głos
1 odpowiedź 314 wizyt
pytanie zadane 27 września 2015 w C i C++ przez Avernis Nałogowiec (27,400 p.)
0 głosów
1 odpowiedź 107 wizyt
pytanie zadane 19 listopada 2015 w C i C++ przez sofnir Gaduła (4,690 p.)

92,572 zapytań

141,422 odpowiedzi

319,643 komentarzy

61,959 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj.

Akademia Sekuraka

Kolejna edycja największej imprezy hakerskiej w Polsce, czyli Mega Sekurak Hacking Party odbędzie się już 20 maja 2024r. Z tej okazji mamy dla Was kod: pasjamshp - jeżeli wpiszecie go w koszyku, to wówczas otrzymacie 40% zniżki na bilet w wersji standard!

Więcej informacji na temat imprezy znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...