kategoria: Blitz
[#1] poruszanie obiektów w określonym kierunku
Witam
Piszę sobie taką kolejną wprawkę w BlitzBasicu, ale problem jaki mam dotyczy ogólnego algorytmu. Chcę poruszać obiekt A w kierunku obiektu B
Określam ich odległości:

TX = A.x - B.x
TY = A.y - B.y

ilość kroków np s=80
wtedy przyrosty dla pozycji x,y obiektu A obliczam tak

dx=TX/s
dy=TY/s
i wszystko było by pięknie tylko problem w tym, że to zawsze jest te 80 kroków. Jeśli obiekty są bliżej siebie to nadal będzie 80 kroków i obiek A będzie leciał w kierunku B wolniej ale zawsze to będzie te 80 kroków. Chciałbym aby prędkość była ta sama niezależnie od odległości A i B od siebie. Robiłem jakieś triki i obliczałem ilość kroków na podstawie odległości ale kod się jakoś niepotrzebnie komplikuje no i nie jest to do końca to o co mi chodzi.

Podpowiedzcie coś... Z góry dzięki.
[#2] Re: poruszanie obiektów w określonym kierunku

@retronav, post #1

link Obadaj Algorithm for integer arithmetic. Przerób go na pikselki i zobacz jak działa. Powodzenia!
[#3] Re: poruszanie obiektów w określonym kierunku

@retronav, post #1

szeroki uśmiech juz nieistotne szeroki uśmiech


Ostatnia aktualizacja: 09.03.2019 14:12:25 przez peceha
[#4] Re: poruszanie obiektów w określonym kierunku

@asman, post #2

dzięki
ale hm... no nie wiem...
bo już na pierwszy rzut oka widać że to nie zadziała gdy np x1 = x0 +1 czyli odległość między nimi w osi x to tylko 1 pixel (a w osi y np 100 pixeli). pętla wykona się tylko raz i co dalej?
no chyba że czegoś nie łapię?

[edit]
ah... OK nie doczytałem "all cases" - sorki

Ostatnia aktualizacja: 09.03.2019 14:36:08 przez retronav
[#5] Re: poruszanie obiektów w określonym kierunku

@retronav, post #1

Możesz sobie tx i ty określić na twardo w pikselach na klatkę. Jeśli w danej klatce abs(bx-ax) < tx to robisz ax = bx, tak samo z Y. Jeśli chcesz by to zajęło maksymalnie 80 klatek, to policz tx,ty dla reprezentatywnej odległości, np. gdy dystans po x to maksymalnie 160 pikseli: tx = 160/80.
[#6] Re: poruszanie obiektów w określonym kierunku

@asman, post #2

Nie da to jednakowej predkosci tak jak pisal autor watku. Ilosc krokow bedzie max(dx, dy). Mozliwe, ze jest to dla ciebie wystarczajace ale niestety rozwiazanie ktore da ci dobry wynik zaklada policzenie odleglosci. Potem np przyrostowo na fixed-point (wymagana bedzie wieksza precyzja niz punkty ekranowe). Niestety koszt policzenia kroku to pierwiastek i dzielenie a wiec pewnie jakis lut do tego.
[#7] Re: poruszanie obiektów w określonym kierunku

@kiero, post #6

@teh_Kain
zapewne chodziło ci o dx, dy a nie tx,ty, ale
tak jak pisze kiero choć w Blitzu jest Abs() to wolał bym nie wołać takich funkcji.
Też pomyślałem o tablicy w której wartości odpowiadają przedziałom odległości i przypisanym im krokom, ale nie pozbędę się tego Abs().

niestety mam wrażenie że algorytm lini też mi nie wiele pomoże i wprowadza jakieś niepotrzebne skomplikowanie. chciałbym zostać przy dx i dy dodawanym co ramkę do pozycji x,y obiektu A.

to co robię to zaimplementowanie pocisków lecących w stronę gracza, a tych pocisków chcę żeby leciało na raz kilka. Liczenie tego wszystkiego dla każdego będzie dużym obciążeniem a mam wrażenie że da się to jakoś sprytnie liczyć. będę knuł dalej.
[#8] Re: poruszanie obiektów w określonym kierunku

@retronav, post #7

Ta, miałem na myśli dx,dy.

Możesz przy generowaniu pocisku rozkminiać czy leci w lewo i w prawo i na tego bazie determinować warunek końcowy - gdy A leci w kierunku B w lewo, to sprawdzasz if(xa < xb) { xb = xa; } a jak w prawo to odwrotny warunek. Ale wtedy masz dwa zagnieżdżone ify i nie wiem czy będzie szybciej, na pewno kod będzie bardziej porąbany. ;) Z ABSem za wolno działa?

Ostatnia aktualizacja: 11.03.2019 12:59:45 przez teh_KaiN
[#9] Re: poruszanie obiektów w określonym kierunku

@teh_KaiN, post #8

A to nie może/powinno być tak że dla każdego obiektu powinna być obliczana najpierw odległość bezwględna (raz - chyba że obiekty się poruszają względem siebie) a poźniej dzielona przez określoną szybkość (np. pocisku) da liczbe kroków ?
A współrzędne można interpolować własnie z tą obliczoną liczbą kroków.
[#10] Re: poruszanie obiektów w określonym kierunku

@retronav, post #7

Jezeli to pociski to sprawa sie nieco upraszcza. Koszt ponosisz tylko przy inicjalizacji. Potem masz tylko:

x += dx i y += dy

Problem w tym ze musisz uzyc wiekszej dokladnosci dla x i y niz pozycja ekranowa. Musisz miec kilka bitow po przecinku bo inaczej pociski beda leciec krzywo. Wtedy Dla kazdej ramki masz jedynie 2 dodawania i 2 przesuniecia bitowe (zeby obliczyc pozycje ekranowa) dla obiektu. Cala "ciezka" robota robiona jest raz przy wystrzeliwaniu.

// to na poczatku. 8 bitow po przecinku powinno wystarczyc
dx = x2 - x1; dy = y2 - y1;
l = 256 * predkosc / sqrt (dx * dx + dy * dy); // tutal moze byc lookup
dx = dx * l; dy = dy * l;

// to per-ramka
x += dx; screen_x = x >> 8
y += dy; screen_y = y >> 8
[#11] Re: poruszanie obiektów w określonym kierunku

@retronav, post #7

Z tym algorytmem linii to może faktycznie wyskoczyłem trochę jak filip z konopi.
Na pewno warto się pochylić nad tym co naskrobał kiero.

Przed chwilą znalazłem takie o to ciekawostki dropsa (link). Tu też masz fixed point linie, oczywiście prędkość tu jest ustalona (jeden pixel na ramkę co może być trochę słabe jak zauważył kiero).

A na marginesie: To na tej stronie mnie się podoba Maze generator - jest tak wyczesany, że nadaje się na background w intrze :)
[#12] Re: poruszanie obiektów w określonym kierunku

@retronav, post #1

Uzyj biegunowego ukladu wspolrzednych do przechowywania parametrow obiektu - dla kazdego poruszanego obiektu trzymaj polozenie, odleglosc do pokonania i wektor kierunku. Zmiana wspolrzednych to:
dx = odleglosc * cos (wektor_kierunku);
dy = odleglosc * sin (wektor_kierunku);
Przy okazji zmiana kierunku czy predkosci poruszania obiektu znacznie sie upraszcza - wymaga zmiany tylko jednego parametru (odleglosci lub wektora kierunku).
Stablicuj sin/cos i poruszanie obiektu to beda 2 lookupy, 2 mnozenia i 2 dodawania.
Zakladajac, ze odleglosc do pokonania jest stala, stablicuj odleglosc*cos, odleglosc*sin i wystarcza 2 lookupy i 2 dodawania.
Aha, x, y, dx i dy musi byc fixedpoint aby obiekty plynnie sie poruszaly i szybciejl sie liczylp.
[#13] Re: poruszanie obiektów w określonym kierunku

@docent, post #12

no nie ... z sin i cos to już trochę za daleko kombinujesz
Nie wydaje mi się aby w grach na Amidze gdzie latają pociski aż takie "armaty" stosowano. tym bardziej wektory itp.
odległości nie są stałe. raz wystrzelony pocick ma sobie lecieć w kierunku w którym był w czasie wystrzelenia gracz. jak nie trafi to leci dalej i aż do granic ekranu. tyle.

oczywiście mam na razie na stałoprzecinkach tak jak sugerujecie.

@kiero
Twoja propozycja jest mi najbliższa ale nie bardzo wiem jak ztablocować sqrt w przypadku kiedy odległości pocisku od gracza w trakcie wystrzelenia mogą być w zasadzie dowolne.
[#14] Re: poruszanie obiektów w określonym kierunku

@retronav, post #13

Hej, w temacie napiszę, że w grze Dune 2 do wyliczania odległości między punktami służy o ile dobrze pamiętam wzór:

(uwaga: dx, dy to wartości nieujemne, które oznaczają odległość między punktami odpowiednio na osi x i y):

distance = (min(dx, dy) / 2) + (max(dx, dy)).

Czyli liczymy połowę mniejszej z odległości dx i dy i dodajemy do niej drugą wartość.

W grze wykorzystywane jest to do wyznaczania zasięgu wieżyczek, armat czołgów, a także do generowania okrągłych obszarów jak np. złoża przyprawowe.

Czyli jeśli dla pewnych (dx, dy) distance <= range (odległość jest mniejsza bądź równa zasięgowi), to wówczas pole (dx, dy) jest odległe o co najwyżej range od punktu (0, 0).

Nie wiem czy znajdzie to zastosowanie w przypadku kolegi i czy jest wystarczająco precyzyjne, ale myślę, że może się przydać.

Ostatnia aktualizacja: 11.03.2019 16:56:06 przez Hexmage960
[#15] Re: poruszanie obiektów w określonym kierunku

@retronav, post #13

Jezeli sa praktycznie dowolne to tablica odpada, nie wiem czy bym sie przejmowal tablicowaniem jezeli liczysz to tylko raz... Ale powiedzmy ze musisz wiec jedziemy. Glowny koszt to sqrt() + dzielenie.

- Liczymy na intach w petli np tak. Naiwne podejscie ale tak jak napisalem, mozliwe ze wystarczajace. Na pewno lepsze niz liczenie na floatach na golej 68000.
- Liczymy przyblizona wartosc. Odpada wtedy mnozenie i sumowanie pod sqrt() ale dostajemy wartosc przyblizona co spowoduje nie do konca plynny ruch (ale moze akceptowalny, maks blad podaja jako 5%). Np tak. Zostaje koszt dzielenia. Pewnie wybralbym to rozwiazanie. 3 mnozenia ale odpadaja 2 dla danych wejsciowych.
- Przerzucamy sie na floaty i liczymy przyblizona wartosc dla 1/sqrt(). Np tak Ale to wymaga juz uzycia bibliotek matematycznych. Za to odpada nam dodatkowo dzielenie (zastepowane mnozeniem).
[#16] Re: poruszanie obiektów w określonym kierunku

@retronav, post #13

Za daleko? Przeciez to najprostsze rozwiazanie Twojego problemu i zadne armaty - to matematyka ze szkoly podstawowej :)
Chyba w kazdym demie gdzie jest "sinus" scroll albo pixele czy wektory 3d jest sin/cos table i zaloze sie, ze wiekszosc gier (moze oprocz tych najprostszych) korzysta z tego rodzaju obliczen.

Zauwaz, ze w mojej propozycji Twoje wymaganie jest spelnione - wystrzeliwujesz pocisk w okreslonym kierunku, zdefiniowanym przez wektor kierunku i jego dlugosc, w Twoim przypadku mozesz dlugosc traktowac jako predkosc (czyli droge, ktora ma pokonac w jednej iteracji/jednostce czasu). Wektor kierunku masz z polozenia gracza, dlugosc sobie ustalasz i voila, wszystko samo sie liczy. Wektor kierunku w Twoim przypadku to moze byc kat pod jakim gracz jest ustawiony wzgl. np. wspolrzednej x.
Zmieniajac dlugosc mozesz zmieniac predkosc pociskow a modyfikujac wektor kierunku mozesz np. zrobic samonaprowadzajace sie pociski (wektor kierunku uzyskasz z atan2(y2-y1, x2-x1) albo liczac dot product z wektorow k, zbudowanych z punktu 0,0 i P1 i 0,0 i P2) . Wykrywanie, czy pocisk jest poza ekranem to zaaplikowanie zwyklego bounding boxu na wspolrzednych pocisku.
Oczywiscie, mozesz kombinowac z sqrt, ale po pierwsze pierwiastki sa bardzo czasochlonne do policzenia, a po drugie czy bedzie to prostsze? watpie.
[#17] Re: poruszanie obiektów w określonym kierunku

@docent, post #16

@docent
tablice sin i cos to nie problem, (przychodzę ze świata C64 gdzie wszystko się tablicuje ;)) ja po prostu nie kumam co to jest ten wektor i jak miałbym go obliczać a potem wybierać daną z tablicy. jeśli Atan to to jest kolejne miejsce obliczeń które chciałbym unikać

co do sqrt, to tak jak napisałem piszę to w Blitzu gdzie taka funkcja jest. Co prawda kiero tutaj dobrze wywnioskował, tzn jeśli to napiszę i zadziała w Blitzu to pokuszę się być może o wersję w asm'ie a tam wszystko musi być na integerach. Blitz ma typ danych .q to są stałprzecinkowe liczby po 16 bitów na część całkowitą i 16 bitów na ułamkową na razie na tym jadę. Są oczywiście szybsze niż float'y.

@kiero
czuję że to ma sens, ale potrzebuję to przetrawić. za dużo informacji jak na raz ;)

zrobięteż wersję totalnie toporną (tablica wartości dla dx i dy w zależności od Abs(ax-bx)) i zobaczę jak w praktyce wizualnie wygląda.
szczegółami
[#18] Re: poruszanie obiektów w określonym kierunku

@docent, post #16

W tym rozwiazaniu sa tylko 2 "problemy".

1: Trzeba znac kat wystrzalu. To sie sprowadza do arctan(). Mozna tablicowac oczywiscie ale trudniej bo to jest dx/dy. Jezeli nie uzyjesz atan() to masz i tak normalizacje. W sumie to sie sprowadza dokladnie do tego co ja napisalem jakby pomyslec;) Tylko ja licze powiedzmy sin/cos na poczatku jako przyrosty. Oba rozwiazania sa tak samo zlozone obliczeniowo. Koszt jest na inicjalizacje a potem per-ramka juz jest tanio.

2: Nie mozna robic liczenia pozycji inkrementacyjnie na ramke. Niby ok bo mamy liczenie wzgledem czasu (super jak framerate nie jest staly) ale w grze to nie jestem pewien. Liczenie poprzez dodawanie delty ma taka zalete ze to tylko dodawanie + shift. Jak mamy w postaci parametrycznej (wzgledem <t>) to juz niestety mnozenie.

Ostatnia aktualizacja: 11.03.2019 19:28:36 przez kiero

Ostatnia aktualizacja: 11.03.2019 19:30:38 przez kiero
[#19] Re: poruszanie obiektów w określonym kierunku

@kiero, post #18

Nie zgadzam sie co do podobnej zlozonosci obliczeniowej. Sqrt jest kosztowne i trudno go stablicowac, sin/cos banalny do stablicowania i przez to b. szybki.
Do okreslenia kata strzalu nie potrzeba zadnych obliczen. kat wystrzalu = kat glownego obiektu, ktory strzela (heading) - przeciez to oczywiste.
Glowny obiekt tez musi byc w tym samym systemie wspolrzednych, tzn ma pozycje x,y, kierunek patrzenia (kat) i predkosc poruszania sie.

Co do pkt 2, wystarczy przyjac, ze odleglosc jest zdefiniowana na jednostke czasu, ktora jest ramka. Wtedy nie ma zadnego mnozenia, tylko dodaje sie wyliczone wspolrzedne do pozycji pocisku.
[#20] Re: poruszanie obiektów w określonym kierunku

@docent, post #19

"kat wystrzalu = kat glownego obiektu, ktory strzela (heading) - przeciez to oczywiste." ale musi wiedziec gdzie strzelac...
[#21] Re: poruszanie obiektów w określonym kierunku

@kiero, post #10

OK wersja kiero z Sqrt() działa.
no ale używa pierwiastka. musze to jakoś zmierzyć jak bardzo to jest czasochłonne.
co prawda liczę ten pierwiastek tylko raz gdy spawn'uje pocisk ale zawsze...
na dzisiaj kończę ale jutro powalczę jeszcze.

fajna dyskusja się z tego zrobiła. :)

[edit]
I tak jak kiero pisze to musi u mnie być wywoływane cyklicznie co ramkę, a pewnie ostatecznie nawet co 3-4 ramki, kiedy to będę spawnował pociski.

Ostatnia aktualizacja: 11.03.2019 22:33:19 przez retronav
[#22] Re: poruszanie obiektów w określonym kierunku

@retronav, post #17

W takim razie sprobuje to wyjasnic na ponizszym obrazku :)
|           ^
 |         /
 |       d/ \
 |       /   | alfa
y|      * ...+
 |         d
 +---------------------
        x

d - odleglosc do przebycia w jednostce czasu, predkosc
alfa - kat pomiedzy wektorem gwiazdka-daszek a osia x
x, y - wspolrzedne na ekranie
* - statek
Tworzysz 2 tablice kazda 256 pozycji
1 zawierajaca sin(tablepos*360/256) - tablepos od 0 do 255
2 zawierajaca cos(tablepos*360/256) - tablepos od 0 do 255
Zalozenie jest takie, ze tablica 256 pozycji pokrywa 360 stopni, czyli 1 krok to 360/255 stopnia a alfa moze byc max 255.

- statek porusza sie w kierunku alfa, z predkoscia d.
- wystrzeliwujac pocisk, bedzie on przemieszczal sie w kierunku alfa z predkoscia d2 - z reguly wieksza od d statku)
Co ramke jesli liczone dx i dy wszystkich aktywnych obiektow (statku i pociskow) wg podanego wzoru
dx= d*cos(alfa)
dy= d*sin(alfa)
a z nich nowe wspolrzedne:
x=x+dx; y=y+dy;
; mnozenie mozna wyeliminowac gdy pociski poruszaja sie ze stala predkoscia,
; wartosc cos (alfa) pobiera sie z tablicy costable[alfa]

Nastepnie robione sa sprawdzenia:
- Jesli wspolrzedne pocisku poza ekranem, usuwasz pocisk
- Jesli wspolrzedne pocisku=bbox statku przeciwnika, usuwasz pocisk, zwiekszasz damage obiektu (ew. usuwasz jako trafiony/zniszczony)
Nastepnie testowanie co gracz wcisnal:
- Gdy gracz naciska lewy kursor, alfa=alfa-1;
- Gdy gracz naciska prawy kursor, alfa=alfa+1;
- Gdy gracz naciska kursor w gore, d=d+1;
- Gdy gracz naciska kursor w dol, d=d-1;
- Gdy gracz naciska fire, dodajesz nowy pocisk o wspolrzednych x,y statku, kierunku alfa i predkosci d2
Oczywiscie wartosc 1 moze byc zastapiona inna w zaleznosci od potrzeb.

Ostatnia aktualizacja: 11.03.2019 23:36:29 przez docent

Ostatnia aktualizacja: 11.03.2019 23:40:25 przez docent
[#23] Re: poruszanie obiektów w określonym kierunku

@docent, post #22

Ehhh, moze poczytaj to co ja pisze a potem odpisuj bo to co piszesz to oczywista oczywistosc... Nie musisz mi pisac jak dziala twoje tablicowanie, jak dziala samo poruszanie pocisku. To sa banaly i w moim przypadku po inicjalizacji wszystko wyglada juz tak samo. Wszystko rozbija sie o inicjalizacje i dalej nie napisales mi skad wziales kat alfa pomiedzy punktami. Takie bylo zalozenie oryginalnego pytania.
[#24] Re: poruszanie obiektów w określonym kierunku

@kiero, post #23

Jakbys nie zauwazyl, to objasnienie jest nie dla ciebie tylko dla retronav.
Co do czytania to moze sam zacznij czytac to, co pisza inni - w poscie 16 napisalem, skad mozesz wziac kat pomiedzy dwoma obiektami (atan2). Z reszta to widac z "rysunku", wiec nie wiem z czym masz problem. Atan mozna duzo latwiej stablicowac niz sqrt, mozna go tez calkiem dobrze przyblizyc za pomoca paru mnozen i dodawan z bledem na poziomie 0.08-0.09 stopnia
[#25] Re: poruszanie obiektów w określonym kierunku

@docent, post #24

Moja wina, źle numer postu sprawdziłem, fakt. I nie, ja nie mam żadnego problemu... Dalej będę twierdził ze tak jak napisałem na początku koszt inicjalizacji jest praktycznie identyczny a koszt na ramkę identyczny. Z mojej strony koniec tematu.
[#26] Re: poruszanie obiektów w określonym kierunku

@kiero, post #15

Chyba to trochę zoptymalizowałem wczoraj
użyłem tego linka http://www.flipcode.com/archives/Fast_Approximate_Distance_Functions.shtml
którego zapodał kiero. implementacja tej funkcjo odległości jest bajecznie prosta w Blitzu a 5% błąd jest w ogóle nie widoczny. Bulety lecą w kierunku gracza a hitboxy będą odpowiednio ustawione więc te 5% odchylenia nie robi żadnej różnicy. No i nie używam SQRT tylko kilka ifów i mnożeń
[#27] Re: poruszanie obiektów w określonym kierunku

@kiero, post #25

Dalej będę twierdził ze tak jak napisałem na początku koszt inicjalizacji jest praktycznie identyczny a koszt na ramkę identyczny. Z mojej strony koniec tematu.
No coz, niektore rzeczy warto sprawdzic zanim wyda sie tak pryncypialna opinie.
Tak jak napisalem wczesniej, mylisz sie. Moje rozwiazanie, zoptymalizowane w taki sposob jak opisalem (uzywajac tablic) jest mniej wiecej 3.5-4 razy szybsze od wersji z sqrt.
Jest takze szybsze o 10%-20% od rozwiazania, ktore znalazl retronav z przyblizonym wyliczaniem dystansu. Dodatkowo jest dokladne, czego nie mozna powiedziec o wyliczaniu przyblizonym, dajacym ~ 5% blad.
Na stronie www.PPA.pl, podobnie jak na wielu innych stronach internetowych, wykorzystywane są tzw. cookies (ciasteczka). Służą ona m.in. do tego, aby zalogować się na swoje konto, czy brać udział w ankietach. Ze względu na nowe regulacje prawne jesteśmy zobowiązani do poinformowania Cię o tym w wyraźniejszy niż dotychczas sposób. Dalsze korzystanie z naszej strony bez zmiany ustawień przeglądarki internetowej będzie oznaczać, że zgadzasz się na ich wykorzystywanie.
OK, rozumiem