Skocz do zawartości

Odległość obiektu od przeszkody i inne ;p


Muchaszewski

Rekomendowane odpowiedzi

Witam. Robię grę TPS (na razie w 2D). Mam problem. Chciałem zrobić w mojej grze strzelanie laserem. Nie było by problemu gdyby nie to że nie znam wystarczająco zoptymalizowanego kodu(zwłaszcza na dużych planszach). Chciałem napisać funkcję która sprawdzała by odległość od gracza do przeszkody po linii prostej, i zwracała by odległość, albo miejsce x,y do tej że przeszkody, a także kąt pod jakim jest gracz względem tej że przeszkody.

 

Mój kod opiera się na szukaniu przeszkody przez funkcję collision_check_point kolejnego piksela do gracza w kierunku, w którym jest obrócony. Następnie sprawdza tą że pozycje pod kątem znajdującej się instancji i zwraca jej obrót. Wszystko ładnie, ale jeśli odległość od przeszkody jest większa niż 100 kratek to zaczyna się problem, a mam w planach aby laser ten odbijał się od pewnego rodzaju bloków i ponownie leciał dalej.

Proszę o napisanie mi wystarczająco zoptymalizowanego kodu, abym nie musiał czekać paru sekund na strzał. Jakoś przeżyję zmniejszenie FPS!

Odnośnik do komentarza
Udostępnij na innych stronach

Trochę trudniej będzie jeśli chodzi o kąt. Ale możesz sprawdzać odległość dwóch linii między bohaterem a przeszkodą. Linie te tworzyły by kąt powiedzmy 5 stopni. Wtedy dostajesz na boki trójkąta i za pomocą sinusów kosinusów itd. obliczasz trzeci. Dzięki temu dostaniesz trójkąt w którym będziesz musiał wyznaczyć kąty między resztą boków. Wybierzesz sobie jeden z nich (wyjdzie w praniu który) i masz problem rozwiązany. Kodu Ci nie napiszę, bo nie pamiętam wzorów na te wszystkie kąty.

Odnośnik do komentarza
Udostępnij na innych stronach

Platyna napisał artykuł o wyszukiwaniu binarnym, szybki i efektowny sposób ;)

https://gmclan.org/index.php?artykul=74

 

Dzięki ;P Będąc na "przechadzce" wpadłem na bardzo podobny pomysł xD Mój "pomysł" będzie szukał najpierw przeszkody co 100 kratek jeśli nie znajdzie przeszuka w kolejnych 100 kratkach, a następnie będzie dzielił to 100 na mniejsze części. Wydaje mi się to bardziej zoptymalizowane biorąc pod uwagę krótkie odległości, gdyż w wyszukiwaniu binarnym Platyna sugeruje podanie od razu maksymalnej odległości strzału.

 

 

Trochę trudniej będzie jeśli chodzi o kąt. (...) Wtedy dostajesz na boki trójkąta i za pomocą sinusów kosinusów itd. obliczasz trzeci. (...)

 

Jest to dobry pomysł, ale trudny do realizacji. Z matmy jestem prawdopodobnie "dobry" :P Ale nie wyobrażam sobie jak by można poprowadzić te 2 linie od gracza i przeszkody. A tak w sumie poco sobie utrudniać.

 

Albo po prostu opisać każdą przeszkodę punktami krańcowymi i przy kolizji odwoływać się do nich.

 

To też nie ma sensu. Prościej jest stworzyć jak najbardziej standardowe przeszkody, do których się wpisze kierunek, a następnie do tego kierunku się odwołać :P Problemem przy moim pomyśle i kt1117 są wszelkiego rodzaju kule, i obszary koliste, ponieważ ciężko będzie określić dokładnie w jakim kierunku mój laser miał by się "odbić". Ale i tak dzięki.

 

 

Mam jeszcze jedno pytanie co do tego. Znalazłem dokładne położenie przeszkody, ale mam problem. Teraz po prostu nie wiem jak można było by się do niej odwołać. Korzystam z instance_nearest(...) ale nie jest to najlepszy pomysł, zwłaszcza przy ciasno upakowanych obiektach. Czy jest jakaś funkcja (jest na pewno, ale zapomniałem jaka ;p) która pozwoli mi się odwołać do obiektu w danym miejscu. Wystarczy id obiektu xD

Odnośnik do komentarza
Udostępnij na innych stronach

To też nie ma sensu. Prościej jest stworzyć jak najbardziej standardowe przeszkody, do których się wpisze kierunek, a następnie do tego kierunku się odwołać :P Problemem przy moim pomyśle i kt1117 są wszelkiego rodzaju kule, i obszary koliste, ponieważ ciężko będzie określić dokładnie w jakim kierunku mój laser miał by się "odbić". Ale i tak dzięki.

Jak to jak mają się odbić? Zgodnie z prawami fizyki! A te są jednoznaczne.

Odnośnik do komentarza
Udostępnij na innych stronach

Dzięki ;P Będąc na "przechadzce" wpadłem na bardzo podobny pomysł xD Mój "pomysł" będzie szukał najpierw przeszkody co 100 kratek jeśli nie znajdzie przeszuka w kolejnych 100 kratkach, a następnie będzie dzielił to 100 na mniejsze części. Wydaje mi się to bardziej zoptymalizowane biorąc pod uwagę krótkie odległości, gdyż w wyszukiwaniu binarnym Platyna sugeruje podanie od razu maksymalnej odległości strzału.

 

Jest to optymalizacja ale mała. Sposób? Ustaw maksymalny test na cały room. Wtedy dalszego zasięgu nie będzie, a sprawdzanie binarne jest chyba najbardziej zoptymalizowanym sposobem. A jeśli już chcesz swój pomysł, to nie dziel na 100 mniejszych tylko binarnie (wtedy zamiast 100 masz 7 sprawdzeń ;P ).

 

Prościej jest stworzyć jak najbardziej standardowe przeszkody, do których się wpisze kierunek, a następnie do tego kierunku się odwołać :P

Im więcej obiektów tym więcej ma GM do przetworzenia, a jeśli będziesz miał takie rozwiązanie, będzie mniej obliczeń bez efektu (jak kontrola zmiennych prędkości, animacji itd, każdy obiekt to ma)

 

Problemem przy moim pomyśle i kt1117 są wszelkiego rodzaju kule, i obszary koliste, ponieważ ciężko będzie określić dokładnie w jakim kierunku mój laser miał by się "odbić". Ale i tak dzięki.

No właśnie, a tak jeżeli płaska powierzchnia - wpisujesz do danych dwa punkty i przy odbiciu odwołujesz się do nich.

 

Mam jeszcze jedno pytanie co do tego. Znalazłem dokładne położenie przeszkody, ale mam problem. Teraz po prostu nie wiem jak można było by się do niej odwołać. Korzystam z instance_nearest(...) ale nie jest to najlepszy pomysł, zwłaszcza przy ciasno upakowanych obiektach. Czy jest jakaś funkcja (jest na pewno, ale zapomniałem jaka ;p) która pozwoli mi się odwołać do obiektu w danym miejscu. Wystarczy id obiektu xD

collision_point powinno załatwić sprawę ;) .

Odnośnik do komentarza
Udostępnij na innych stronach

To akurat wiedziałem że kąt odbicia zależy od kąta padania i tu raczej nie mam problemu... (dobra z fizyki jestem cienki ;p) Właśnie myśląc nad tym zdałem sobie sprawę że be funkcji trygonometrycznych się to nie obejdzie a kt1117 źle zrozumiałem :P Ale ciężko mi wymyślić jakieś rozwiązanie. Myślę nad tym aby kąt zewnętrzny pomiędzy przeszkodą, a laserem podzielić na 2, a wynik będzie kątem odbicia względem przeszkody, ale coś mi się wydaje że źle myślę. )Jeszcze zanim to napisałem znalazłem błąd :P jeśli kąt pomiędzy przeszkodą a laserem wynosie 90 stopni z każdej strony?) Jak czasami widzę te wszystkie wzory na Wikipedii to mnie krew zalewa, więc prosiłbym o jakąś uproszczoną wersję, bądź realny pomysł.

 

EDIT:

collision_point powinno załatwić sprawę

Ta funkcja zwraca tylko 2 wartości true i false. Więc niestety nie

 

Jest to optymalizacja ale mała. Sposób? Ustaw maksymalny test na cały room. Wtedy dalszego zasięgu nie będzie, a sprawdzanie binarne jest chyba najbardziej zoptymalizowanym sposobem. A jeśli już chcesz swój pomysł, to nie dziel na 100 mniejszych tylko binarnie (wtedy zamiast 100 masz 7 sprawdzeń ;P ).

Właśnie o to mi chodziło, ale zapomniałem dodać :P

Edytowane przez Muchaszewski
Odnośnik do komentarza
Udostępnij na innych stronach

Hmm źle się zrozumieliśmy, albo źle napisałem ;p Jeśli strzelimy do płaskiej ściany laserem pod kątem 90 stopni to co się stanie?? Wróci tą samą drogą więc będzie mieć również 90 stopni (Kąt ten jest oczywiście względem ściany). Chyba że... a zresztą. Ja się nie znam.

 

 

A co do wszystkich funkcji collision coś mi nie działało więc chciałem zobaczyć co zwraca ta funkcja :P Wszystkie te funkcje zwracają id obiektu który stoi im na drodze jako pierwszy :P To rozwiązuje wszystkie moje problemy, ale i tak skorzystam z wyliczania dokładnej pozycji "namierzania" :P

Odnośnik do komentarza
Udostępnij na innych stronach

Dzięki ;P Będąc na "przechadzce" wpadłem na bardzo podobny pomysł xD Mój "pomysł" będzie szukał najpierw przeszkody co 100 kratek jeśli nie znajdzie przeszuka w kolejnych 100 kratkach, a następnie będzie dzielił to 100 na mniejsze części. Wydaje mi się to bardziej zoptymalizowane biorąc pod uwagę krótkie odległości, gdyż w wyszukiwaniu binarnym Platyna sugeruje podanie od razu maksymalnej odległości strzału.

Wyszukiwanie binarne + collision_line w tym przypadku będzie szybsze ;)

 

Mam jeszcze jedno pytanie co do tego. Znalazłem dokładne położenie przeszkody, ale mam problem. Teraz po prostu nie wiem jak można było by się do niej odwołać. Korzystam z instance_nearest(...) ale nie jest to najlepszy pomysł, zwłaszcza przy ciasno upakowanych obiektach. Czy jest jakaś funkcja (jest na pewno, ale zapomniałem jaka ;p) która pozwoli mi się odwołać do obiektu w danym miejscu. Wystarczy id obiektu xD

instance_position(...);

Odnośnik do komentarza
Udostępnij na innych stronach

collision_point powinno załatwić sprawę

 

Ta funkcja zwraca tylko 2 wartości true i false. Więc niestety nie

Mylisz się. Wszystkie funkcje collision_ zwracają ID obiektu, jeśli jest jakiś obiekt w polu oznaczonym argumentami funkcji, w przeciwnym wypadku zwracają noone (-4, czyli w sumie false). collision_point zadziała.

 

Wyszukiwanie binarne + collision_line jest bardzo dobrym pomysłem, gdyż zwiększenie zasięgu dwukrotnie spowoduje wydłużenie czasu obliczeń tylko o jedno wywołanie. Nie stracisz fps. Gdzieś nawet zamieściłem kompletny skrypt, możesz poszukać w dziale "Skrypty, przykłady, dodatki" albo przeszukać moje tematy.

 

Obliczanie kątu jest bardzo proste. Musisz tylko wiedzieć, do czego służy point_direction(x1,y1,x2,y2) i wykorzystać to. Ta funkcja pozwoli Ci również obliczyć kąt odbicia promienia od powierzchni kulistych.

 

Mam nadzieję, że pomogłem :-)

Odnośnik do komentarza
Udostępnij na innych stronach

Ta funkcja zwraca tylko 2 wartości true i false. Więc niestety nie

Mylisz się. Wszystkie funkcje collision_ zwracają ID obiektu, jeśli jest jakiś obiekt w polu oznaczonym argumentami funkcji, w przeciwnym wypadku zwracają noone (-4, czyli w sumie false). collision_point zadziała.

A co do wszystkich funkcji collision coś mi nie działało więc chciałem zobaczyć co zwraca ta funkcja :P Wszystkie te funkcje zwracają id obiektu który stoi im na drodze jako pierwszy :P

 

Obliczanie kątu jest bardzo proste. Musisz tylko wiedzieć, do czego służy point_direction(x1,y1,x2,y2) i wykorzystać to. Ta funkcja pozwoli Ci również obliczyć kąt odbicia promienia od powierzchni kulistych.

Nie wiem jak point direction miał by mi pomóc. Zastanawiam się już od dłuższej chwili nad tym i nic nie przychodzi mi do głowy. Point_direction zwraca kierunek pomiędzy 2 punktami ale jakie te punkty bym miał użyć??

 

 

Wyszukiwanie binarne + collision_line jest bardzo dobrym pomysłem, gdyż zwiększenie zasięgu dwukrotnie spowoduje wydłużenie czasu obliczeń tylko o jedno wywołanie. Nie stracisz fps. Gdzieś nawet zamieściłem kompletny skrypt, możesz poszukać w dziale "Skrypty, przykłady, dodatki" albo przeszukać moje tematy.
Nie mogę znaleźć tego przykładu, ale wydaje mi się że mam już coś wystarczająco zoptymalizowanego. Zjada tylko 50fps przy 400 początkowych więc rezultat jest zadowalający przy mapce 10000x10000 :P Ale skrypt i tak się przyda.

 

EDIT:

Drobne sprostowanie co do wydajności. Coś zrobiłem i wydajność mi spadła masakryczne. 5fps jeśli obiekt jest blisko a 40 jeśli jest daleko. :( Muszę napisać wszystko od początku, bo backupa nie mam.

Odnośnik do komentarza
Udostępnij na innych stronach

Zrobiłem mały przykładzik co do moich rozważań odbicia lasera. Sprawdź, czy ci pasuje. Każda odbicie zwalnia pfs o mniej więcej 30 z 600, przy roomie 10000x10000 (na mniejszym różnica 2-4 fps). Rzuć okiem, czy ci odpowiada. Jedynie co to musisz opisać za pomocą prostych i krzywych swoje figury. Ewentualnie ulepszysz kod o kolejne typy powierzchni :) .

 

PLIK

Odnośnik do komentarza
Udostępnij na innych stronach

Najlepiej by było napisać funkcję, zwracającą najmniejszy kąt, pomiędzy 2 liniami. Spróbuję coś wymyślić, bo wydaje mi się, że tak będzie najłatwiej.

E:Sprawdźcie czy dobrze działa:

GML
ax1=argument0

ay1=argument1

ax2=argument2

ay2=argument3

bx1=argument4

by1=argument5

bx2=argument6

by2=argument7

 

kba=point_direction(ax1,ay1,ax2,ay2)

kbb=point_direction(bx1,by1,bx2,by2)

return abs(kba-kbb)

E2:Teraz łatwo wprowadzić w życie mój pomysł:

1.Za pomocą kombinacji lenghdir'ów collision_line i wyszukiwania binarnego wyznaczasz współrzędne dwóch liń, które idą 1* w lewo i w prawo od kierunku bohatera, aż do napotkania przeszkody.

2.Między końcami tych liń od strony przeszkody wyznaczasz trzecią linię.

3.Za pomocą mojej funkcji wyliczasz kąt między linią strzału lasera a przeszkodą.

4.Dostajesz kąt odbicia, wykonujesz na nim działanie:

GML
kat=kat+(180-(kat*2))

E3:Na kulach najlepiej działa z bliska, na płaskich powinno nie mieć to wpływu. Chodzi o to, że kąt rozszerza się, tzn. im dalej od wierzchołka mierzysz odległość między ramionami, tym ta odległość jest większa.

Odnośnik do komentarza
Udostępnij na innych stronach

Ten skrypt mam też w przykładzie, dircmp, jedynie bez wyznaczania kierunku przez point_direction, ale za to zwracający różnicę zawsze w zakresie (-180, 180>.

 

Można i tak, lecz co jeśli będzie bardzo mała przeszkoda w bardzo dużej odległości? Albo jeśli będzie odbijało się tuż przy wieszchołku? Wtedy jedna/dwie linie będą miały końce zupełnie gdzie indziej i efekt wyjdzie... nie taki jak powinien być ;P

Odnośnik do komentarza
Udostępnij na innych stronach

Jeśli chcesz dodać odpowiedź, zaloguj się lub zarejestruj nowe konto

Jedynie zarejestrowani użytkownicy mogą komentować zawartość tej strony.

Zarejestruj nowe konto

Załóż nowe konto. To bardzo proste!

Zarejestruj się

Zaloguj się

Posiadasz już konto? Zaloguj się poniżej.

Zaloguj się
  • Ostatnio przeglądający   0 użytkowników

    • Brak zarejestrowanych użytkowników przeglądających tę stronę.
×
×
  • Dodaj nową pozycję...