[#1] Kolizje w grach platformowych 2d
Witam
W kontekście różnych dyskusji tutaj i na eab i jako że zacząłem coś tam dłubać mam kilka pytań odnośnie fizyki (na początek kolizji) w grach platformowych na Amidze.
Napisałem taki proof-of-concept i nawet jakoś działa ale chcę troche posłuchać od bardziej doświadczonych koderów.

Jak dobrze zrobić kolizje głównego bochatera (i wrogow też) na platformach?

W tej chwili robię to tak że sprawdzam mapę (tilesy 16x16) czy 16 pixeli pod bohaterem jest blok o konkretnym numerze. i jakoś to działa ale nie dokładnie poza tym nie mogę zrobić np pochyłej kładki aby bohater chodził po niej z dokładnością pixela. niedokładności jakie mam to np także to że sprawdzam z dokładnością do 16 pixeli bo taki jest rozmiar tile albo np to że czasami bohater ląduje mi w połowie tile'a...

podyskutujmy to może się to przyda nie tylko mnie.
mam zresztą wiele innych pytań bo piszę i piszę i coraz więcej pytań mam w, wydawało by się prostej grze jaka chodzi mi po głowie.
[#2] Re: Kolizje w grach platformowych 2d

@retronav, post #1

Kiedyś zrobiłem to tak że część kolorów była przeznaczona na tło a część na pierwszy plan. Przy skoku lub poruszaniu się sprawdzałem czy pod nogami postaci są kolory z pierwszego planu. Dodam tylko że programowałem w Amosie.
[#3] Re: Kolizje w grach platformowych 2d

@retronav, post #1

Jeśli liczba kafelków jest ograniczona (postać nie rusza się po gigantycznej bitmapie rysowanej paintem i wczytywanej na raz), to dla każdego kafelka na 16px szerokiego trzymasz 16 wartości, które Ci mówią o wysokości terenu na danym pikselu. Jak za dużo danych, to zmniejszasz to do 8 lub 4, zwłaszcza jeśli np. dx jest zawsze równy wielokrotności 2. Sprawdzasz jaki kafel jest pod Tobą i patrzysz na jego dane.

Jeśli y idzie w górę i pasków jest 16, pozycja postaci jest uwiązana do jego lewego dołu, to:
srodekPostaciX = pozycjaPostaciX + szerPostaci/2;
rodzajKafla = kafle[srodekPostaciX / 16][(pozycjaPostaciY-1) / 16];
wysokoscPaska = paskiDanych[rodzajKafla][srodekPostaciX & 15];
dopuszczalnyY = kafelY*16 + wysokoscPaska;
pozycjaPostaciY = max(pozycjaPostaciY, dopuszczalnyY);


Czy coś tam, kod to syf, ale idea mam nadzieję jasna. A jak masz bitmapowe tło, to masz przekichane. ;)

Ostatnia aktualizacja: 29.06.2017 17:12:18 przez teh_KaiN
[#4] Re: Kolizje w grach platformowych 2d

@teh_KaiN, post #3

W grze Benefactor w przypadku platformy pochyłej jest to zrealizowane dokładnie tak, jak to napisał teh_KaiN i tą metodę polecam.

A jak masz bitmapowe tło, to masz przekichane. ;)

W przypadku bitmapy o dowolnym kształcie możesz użyć specjalnej własności Blittera (a jak mniemam bohater jest nim rysowany).

Otóż Blitter posiada flagę (tzw. Zero Flag), która jest zapalana gdy wynikiem operacji graficznej są same zera (wszystkie bity w kanale D są zerami). Można użyć tego by wykryć kolizję pomiędzy dwoma obiektami o dowolnym kształcie.

Jak wiesz do rysowania obiektów animowanych o nieregularnym kształcie używa się tzw. maski. Maska ma zapalone bity tam, gdzie powinna znaleźć się grafika obiektu, zaś zgaszone tam, gdzie powinno znaleźć się tło.

Żeby wykryć kolizję między dwoma obiektami robisz prostą operację Blittera D = AB, gdzie A i B to maski tych obiektów. Robisz to dokładnie raz (bo maska to zawsze jeden bitplan). Kanał D możesz wyłączyć.

Jeśli Zero Flag jest zapalony to oznacza, że obiekty nie kolidują ze sobą, bo nie znalazły się żadne piksele wspólne. W przeciwnym przypadku obiekty kolidują ze sobą.

W przypadku kolizji z platformą, najlepiej trzymać maskę grafiki, która może kolidować z bohaterem w osobnym buforze.

Jeszcze dodam, że w praktyce tej metody nie stosowałem, ale wykrywanie kolizji w graphics.library już tak.

Ostatnia aktualizacja: 29.06.2017 17:49:24 przez Hexmage960
[#5] Re: Kolizje w grach platformowych 2d

@Hexmage960, post #4

Jeszcze wkleję dla zobrazowania kolizji za pomocą Blittera:

[#6] Re: Kolizje w grach platformowych 2d

@Hexmage960, post #4

Dzięki @Hexmage, dzięki @teh-kain
całość na razie piszę w Blitzu (może nawet tak zostawię) i bezpośrebnio blittera nie dotykam.
jak siądę do gry to będzie to na początek na pewno coś prostego. może coś jak moje gierki na c64 sprzed lat. do tego właśnie jest mi potrzebna podstawowa mechanika i kolizje

@teh_kain
co do twojego algorytmu to mam to prawie tak samo oprócz tej ostatniej linijki z max(,) natomiast nie wpadłem aby sprawdzać środek bohatera... zastosuję.

mam kolejne 2 pytanka:
- jak zrealizowali byście podskakiwanie? tzn zrobić tablicę sinusa w górę a w dół po prostu przyspieszać (tak na razie robię) czy jest jakiś sprytny sposób aby nie robić sinusa?
- samo wykrycie przycisku joya i przypisanie pozycji dy bohatera robić w przerwaniu?
[#7] Re: Kolizje w grach platformowych 2d

@retronav, post #6

do skoku to ja bym chyba ease-in i ease-out zrobił

Natomiast jeśli chodzi o kolizje - to u siebie (w Amosie) wykrywałem to przez sprawdzenie koloru pixela w obrębie postaci - jeden z kolorów był po prostu użyty jako "maska" obszaru w którym mógł się poruszać ludek (lub który rozwalał statek kosmiczny).
Sprawdzenie 4 narożników (akurat tak były przygotowane spritey postaci) czy w ich lokalizacjach jest poszukiwany kolor - i tyle.
[#8] Re: Kolizje w grach platformowych 2d

@retronav, post #1

A to nie wystarczy skorzystać ze sprajtów i bobów?
Chyba właśnie po to głównie są aby nie głowić się nad kolizjami.
.
[#9] Re: Kolizje w grach platformowych 2d

@retronav, post #6

Nie wiem czy będziesz potrzebował sinusa w ogóle, ale podejścia są różne, kwestia eksperymentu i zostawienia tego, które działa najlepiej. Spojrzałem do kodu megadrive'owego vilqa i widzę że robiłem to tak:

W tym kodzie Y z tego co pamiętam ma zero u góry i rośnie w dół.

#define JUMP_SPEED        (-12)
#define DOUBLE_JUMP_SPEED (-9)
#define MAX_JUMPS         (2)
	// Jump process
	if (jumpPressed && !vilqSlide && jumpCount < MAX_JUMPS) {
		if (jumpCount == 0 && vilqSpeedY == 0) {
			SND_startPlayPCM_XGM(SFX_JUMP_SINGLE, 1, SOUND_PCM_CH4);
			vilqSpeedY = JUMP_SPEED;
			++jumpCount;
		} else {
			SND_startPlayPCM_XGM(SFX_JUMP_DOUBLE, 1, SOUND_PCM_CH4);
			vilqSpeedY = DOUBLE_JUMP_SPEED;
			if (jumpCount == 0) {
				++jumpCount;
			}
			++jumpCount;
		}
		jumpPressed = 0;
	}
	// Y speed - gravity
	if (vilqSpeedY < 5)
		++vilqSpeedY;
	// Y movement
	if (vilqY < -vilqSpeedY)
		vilqY = 0;
	else if (vilqY >= 224) {
		dead = DEAD_FALL;
		return;
	} else {
		vilqY += vilqSpeedY;
	}


Potem gdzieś warunek na dotknięcie podłogi:

if(...) {
				// Vilq dotyka podłogi
				vilqY = gornaKrawedzTileaPodPostacia;
				vilqSpeedY = 0;
				jumpCount = 0;
}


Sinusa żadnego nie ma, bo droga spadającego ciała to funkcja kwadratowa. Dość dobrze to odwzorowuje prędkość skoku nadawana raz, którą potem co klatkę zbijasz grawitacją.

Na Amidze dżoja w przerwaniu nie robię, tylko raz na klatkę zrzucam stan rejestru joya i potem ten zrzucony odpytuję w różnych miejsach kodu, by wynik mieć stały na przestrzeni klatki i nie zwalniać 68k - gadanie z CIA odbywa się z prędkością 700kHz.

Ostatnia aktualizacja: 30.06.2017 10:31:15 przez teh_KaiN
[#10] Re: Kolizje w grach platformowych 2d

@rePeter, post #8

A te kolizje nie sa przypadkiem wykrywane tylko pomiedzy bobami i spritami
A z tlem to juz nie?
[#11] Re: Kolizje w grach platformowych 2d

@WojT_GL, post #10

Z tego co pamiętam, kolizje z tłem też były wykrywane "sprzętowo", chyba trzeba wydzielić konkretne bitplany na tło, musiałby się wypowiedzieć czynny programista.
.
[#12] Re: Kolizje w grach platformowych 2d

@rePeter, post #11

Tak, Amiga pozwala sprzętowo wykrywać kolizję pomiędzy dwoma grupami duszków, pomiędzy grupą duszków i playfieldem oraz pomiędzy dwoma playfieldami.

Amiga posiada dwa playfieldy. Jeden to bitplany parzyste 0, 2, 4, 6, a drugi to bitplany nieparzyste 1, 3, 5, 7.

Playfieldy mogą być wyświetlane niezależnie od siebie. Można wydzielić np. jeden playfield na pierwszy plan (kolidujący z bohaterem), zaś drugi na tło.

Co do grup duszków, to istnieją 4 grupy po 2 duszki. 0-1, 2-3, 4-5 i 6-7.

Biblioteka graphics.library pozwala na tworzenie Spriteów i Bobów oraz wykrywanie kolizji, ale ta biblioteka oferuje bardzo powolną implementację.

Ostatnia aktualizacja: 30.06.2017 15:49:53 przez Hexmage960
[#13] Re: Kolizje w grach platformowych 2d

@Hexmage960, post #12

...ale
mam wrażenie że w większości gier to chyba jednak nie było stosowane.
no bo:
co jeśli mam bohatera jako sprite'a ale tło nie jest puste a ma jakieś kafelki (np cegły) wtedy kolizja bitmapy z duszkiem?
inna rzecz sprity były bardzo często wykorzystywane np jako tło w paralaxie (np w risky woods http://codetapper.com/amiga/sprite-tricks/.
ale może się mylę...?
[#14] Re: Kolizje w grach platformowych 2d

@retronav, post #13

co jeśli mam bohatera jako sprite'a ale tło nie jest puste a ma jakieś kafelki (np cegły) wtedy kolizja bitmapy z duszkiem?

Tak, kolizja sprite'a i playfieldu czyli obrazu złożonego z 1-4 bitplanów. Ten playfield może zawierać elementy, które kolidują z bohaterem, np. właśnie cegły, platformy.

Dodatkowo drugi playfield może zawierać grafikę tła, która nie będzie wchodzić w interakcję z duszkami, jakieś chmury na niebie itp.

Ostatnia aktualizacja: 30.06.2017 15:43:26 przez Hexmage960
[#15] Re: Kolizje w grach platformowych 2d

@retronav, post #13

@retronav. Powiem tak, sprzętowa kolizja w Amidze jest dla mnie osobiście dziwna i ja jej nie polecam. Oczywiście zrobisz jak będziesz chciał. Wpierw poczytaj na EAB co mówi phx o clxcon. Jak pamięta to kolizja nie jest wykrywana przed wyświetleniem hw sprajtów. Czyli w praktyce musisz czekać na koniec ramki albo na początek nowej.

Otaczanie bobów kolorem i sprawdzanie kolizji za pomocą hardware też jest do bani, bo i tak musisz sprawdzić hitboxa z którym obiektem się zderzyłeś. Poza tym otoczka może niektórych denerwować, design bobów musi być zmieniony i boby są szersze i wyższe co wpływa na ich ilość. Dodatkowo jak masz jeszcze bliterem sprawdzać maski to i tak swoje kosztuje a po za tym i tak musisz wiedzieć z którym obiektem chcesz to sprawdzać czyli znowu hitbox.

Kolizja sprajt do sprajt jak dobrze pamiętam to też trzeba ogarnąć który duszek (parzysty czy nie parzysty) spotkał parzystego czy nie. Czyli znowu sprawdzanie hitboxa.

Pomyśl o multipleksowaniu sprajtów jako pocisków, i tak będziesz musiał sprawdzać hitboxy.
Uważam podobnie jak Photon, że kolizja piksel perfection nie zawsze jest dobra. Według mnie gra ma lepszą grywalność gdy hitbox przeciwnika jest mniejszy (czyli czasem Cię pikselkiem dotknie i zrobi straszonko) a większy hitbox jak zbierasz itemki.
[#16] Re: Kolizje w grach platformowych 2d

@asman, post #15

Powiem tak, sprzętowa kolizja w Amidze jest dla mnie osobiście dziwna i ja jej nie polecam

no właśnie też mi się tak wydaje. i przecucie mi mówi (i pisałem wcześniej) że w grach każdy koder robił to softwareowo i po swojemu.

ale:
na razie dzięki wszystkim za pomoc i uwagi. szczególnie @teh_kain dzięki za przykładowy kod.

jest weekend więc pewnie będzie czas się pobawić. stay tuned.

TM
[#17] Re: Kolizje w grach platformowych 2d

@retronav, post #1

Znalazłem chwię by pochylić się nad tym tematem.

Ogólnie to niezła kobyła i z tego to można całkiem niezły artek napisać.

Zarysowałeś problem bardzo ogólnie i ciężko odpowiedzieć w paru słowach jakie podejście do kolizji wybrać. Dużo zależy od tego jak Twój bohater ma się poruszać. Ja tu rozróżniam 3 przypadki.
1. Ruch skokowy na przykład Robbo, ruch co 16 pikseli co 4 ramkę. Jeśli byśmy chcieli ruch co jedną ramkę to wtedy Robbo by za szybko biegał.
+ Łatwa jak barszcz kolizja
- Ten skokowy ruch nie każdemu może się podobać.

2. Ruch płynny ale o szerokości tilesa (zakładam że szerokość tilesa = wysokość tilesa). Tak na przykład jest robione w Alter Ego. Znajdziesz na youtube to lepiej zrozumiesz. Tu najważniejsze jest synchro. Postaci zawsze przemieszczają się o określoną ilość pikseli (w Alter Ego o 8 pikseli). I wtedy jest robiona kolizja jak w przypadku pierwszym.
+ Dosyć łatwa kolizja
- Nie tak łatwo wprowadzić zmienną szybkość postaci, bo można stracić synchro.

3. Ruch płynny. Czyli wtedy zostają hot spoty, czyli taki punkt który dodajemy do aktualnej pozycji i wtedy obliczamy gdzie jesteśmy. W niektórych przypadkach wystarczy jeden hot spot. Ja na przykład w BlazingGuns używam co najmniej dwóch.
+ nie ma problemu z przyspieszaniem i zwalnianiem
- kolizja - tu trzeba przysiąśc i ją napisać :)

Bardzo często używa się w osobnej tablicy kolizji i osobnej tablicy graficznych tilesów. Wtedy upraszcza to bardzo sprawdzanie warunków. Bo dekorów możesz mieć kilka -kilkanaście a wszystkie one są oznaczone jako TILE_WALL. Tablica kolizji może być inna na przykład tam mogą być tilesy 8x8 a dekory stawiasz jako 16x8.

W necie znajdziesz masę róznych artków i przykładów w róznych językach. Kwestia adaptacji do swojego projektu. Na szybko znalazłem kilka.

The Guide to Implementing 2D Platformers
Sonic Physics Guide
2D Gravity Platformer
11 Tips for making a fun platformer
[#18] Re: Kolizje w grach platformowych 2d

@asman, post #17

Ogólnie to niezła kobyła i z tego to można całkiem niezły artek napisać

dokładnie. właśnie dla tego jak zacząłem się zastanaiać - doszedłem do wniosku że to nie jest takie banalne jak myślałem i stąd ten wątek.
a cieszy mnie ten wątek już podwójnie bo: a) robi się fajna dyskusja, b) widzę że wiele rzeczy "wymyśliłem" podobnie.

np:
mam teraz 2 mapy. jedna to mapa samej grafiki (kafelki 16x16) a druga to mapa kolizji. mam tam oznaczone nie tylko ściany ale i diamenty albo przeszkody. myślę też że dodam tam pozycje gdzie będą się spaw'nować wrogowie.
co do twoich linków to dzięki - przeglądam. sam znalazłem wcześniej kilka innych i już sporo poczytałem do tego momentu.
a co do artykułu... no cóż ponieważ ten mini projekt nabiera rozmiarów i zaczyna IMO być ciekawy chyba zaczną go opisywać na swoim blogu, albo przynajmniej jakieś screeny powrzucam.
[#19] Re: Kolizje w grach platformowych 2d

@asman, post #17

Pierwszy link z postu asemana goraco polecam - sam z niego korzystalem. W zasadzie wyczerpuje on temat w zakresie kolizji w grach 2d. Pewnie... Mozna udziwniac i kombinowac jednak to co jest tam zawarte to w zasadzie standard i 99% gier 2d korzysta z jednego z przedstawionych tam algorytmow.

Co do skakania to faktycznie robi sie za pomoca sinusa ale przy kilkunastu obiektach na ekranie zaczyna sie z tego robic kompletnie niepotrzebne obciazanie procesora, szczegolnie ze wynik za kazdym razem bedzie DOKLADNIE TAKI SAM. O ile na Amdze takie obciazenie jest niezbyt zauwazalne o tyle na takich 8bitowcach to jest bezsensowne zarzniecie CPU. W grach 2d przy takiej rozdzialce jak ma Amiga to bez sensu liczyc to az tak dokladnie, wiec od siebie polecam przymierzyc ile ten skok powinien max w pixelach wynosic, rozbic na ilosc krokow, przeliczyc raz a nastepnie wyniki wrzucic do jakiejs tablicy i z tego korzystac.

PS: ciesze sie ze taki temat powstal, z pewnoscia bardzo wielu poczatkujacych programistow gier na tym skorzysta.

Ostatnia aktualizacja: 01.07.2017 12:29:23 przez Axi0maT
[#20] Re: Kolizje w grach platformowych 2d

@retronav, post #18

Witam ponownie
Tak jak pisałem wcześniej podsyłam próbkę tego nad czym pracuję.
retronavigator.com

Jest to krótki filmik z działania (jak do tej pory) enginu do platformówki 2D.
nic więcej nie napiszą na razie - obejrzyjcie....
[#21] Re: Kolizje w grach platformowych 2d

@retronav, post #20

Całkiem dobrze się zapowiada OK
[#22] Re: Kolizje w grach platformowych 2d

@retronav, post #20

OK

Kompozycja grafiki podobna jak w komercyjnym projekcie gry "Dream Of Rowan"
wiec tym tekstem "sorry for lame gfx made in 5 minutes" wlasnie rozwaliles komus salon sprzedazy
[#23] Re: Kolizje w grach platformowych 2d

@retronav, post #20

WOW, nieźle zasuwa OK
[#24] Re: Kolizje w grach platformowych 2d

@retronav, post #20

Jak na start, wokol czego bedziesz budowal przyszla gre to jest bardzo spoko. Widac tam jakies problemy jeszcze przy wskakiwaniu na platforme od dolu ale jest to dobry punkt zaczepienia do dalszych praca :) trzymam kciuki (mam tylko nadzieje ze grafika jest 100% robocza ;) bo bohater wyglada gorzej niz koszmarnie).
[#25] Re: Kolizje w grach platformowych 2d

@retronav, post #20

Fajowo się zapowiada OK
[#26] Re: Kolizje w grach platformowych 2d

@teh_KaiN, post #9

wracam do tematu po urlopie.

Potem gdzieś warunek na dotknięcie podłogi:


@teh_kain
właśnie to dotknięcie podłogi mi coś nie wychodzi. co widać było na filmiku który podlinkowałem.
tzn sprawdzam pozycję postaci,dziele przez 16 (rozmiar tila) aby wiedzieć jaki til mam pod spodem i jeśli to jest platforma to robię tak jak ty sugerujesz.
tyle tylko że sprawdzam co 16 pixeli więc stąd niedokładności w obliczeniach i raz postać ląduje w połowie tile, innym razem kilka pixeli poniżej krawędzi, itp...
nie bardzo mam pomysł jak to dokładnie wyliczać aby postać zatrzymywała się dokładnie na krawędzi tile'a.
[#27] Re: Kolizje w grach platformowych 2d

@retronav, post #26

@retronav
Musisz zrobić korektę domniemanego ruchu i to wszystko. Czyli jeśli wyliczasz pozycję bohatera na którego działa grawitacja. to robisz tmpY = posY + Gravity. Teraz wyliczasz pozycje na planszy i jeśli dotyka tilesa to musisz zrobić korektę do niego. Bardziej technicznie to musisz obciąć dolne 4 bity takiej tmpY a zrobisz to za pomocą odpowiedniego and. W asemblerze jeśli masz pozycje zapisaną na słowie to robisz and z górnymi 12 bitami ($fff0). Ważna sprawa to wielkość Gravity, nie może ona przekroczyć wysokości tilesa, bo wtedy postać ominie tilesa pod sobą przy takiej dużej Gravity.
[#28] Re: Kolizje w grach platformowych 2d

@asman, post #27

@asman
Dzięki za szybką odpowiedź.
całość piszę w Blitzu bo mam tu za darmo stałoprzecinkowe liczby i na takich właśnie robię grawitację.
zrobiłem "dirty hack" i po skończeniu spadania wyrównuję pozycję do krotności 16 czyli jeśli jest np jest ypos=162 to równam do 160 (o te 2 pixele sprite spadł za daleko)

Na razie działa ale czasami widać mały przeskok jak sprite wraca na właściwą pozycję.
wrócę do tego jeszcze na razie mam jeszcze sporo innych rzeczy do zaimplementowania.
[#29] Re: Kolizje w grach platformowych 2d

@retronav, post #28

Nie wiem jak to masz tam zaimplementowane ale mi to wygląda na to że najpierw pokazujesz sprajta ze złą pozycją a potem robisz korektę, i dlatego napisałem domniemaną pozycję. Czyli taką po dodaniu grawitacji ale to jeszcze nie jest pozycja sprajta. Staje się ona pozycją dopiero gdy nastąpi ewentualna korekcja.

Z tymi innymi rzeczami do implementacji to ja się złapałem na tym, że za dużo zostawiłem na potem i teraz jestem w tak ciemnym zadzie ...

Ostatnia aktualizacja: 24.07.2017 20:21:38 przez asman
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