kategoria: Hollywood
[#1] [Hollywood] Prosta pętla i wykrywanie kolizji
Postanowiłem spróbować stworzyć prostą, jednoplanszową "labiryntówkę" w Hollywood.
Co może być prostszego? Ładujemy parę plików graficznych, ustawiamy tło i sprite'a, a następnie poruszamy nim za pomocą klawiatury:

LoadBrush(1, "labirynt_01.png", {Transparency=#BLACK})
LoadBrush(2, "podloga.png")
DisplayBrush(2, 1, 1)
DisplayBrush(1, 1, 1)
LoadSprite(1, "magazynier.png")

startpos_x=225
startpos_y=235

pos_x=startpos_x
pos_y=startpos_y
DisplaySprite(1, pos_x, pos_y)

StartTimer(1)

While quit = False
	If IsKeyDown("LEFT") Then pos_x=pos_x-1
	DisplaySprite(1, pos_x, pos_y)
	If IsKeyDown("RIGHT") Then pos_x=pos_x+1
	DisplaySprite(1, pos_x, pos_y)
	If IsKeyDown("UP") Then pos_y=pos_y-1
	DisplaySprite(1, pos_x, pos_y)
	If IsKeyDown("DOWN") Then pos_y=pos_y+1
	DisplaySprite(1, pos_x, pos_y)
	WaitTimer(1, 10)
Wend


Wszystko pięknie ładnie, wyświetla się tło, wyświetla się sprite i poruszamy nim po ekranie. Co prawda możemy poza ten ekran wyjść (co jest bez sensu), ale to nie jest w tym momencie istotne.

Spróbowałem dodać jeszcze detekcję kolizji tak, żeby nasz "ludek" mógł się poruszać tylko w zdefiniowanym przez nas "labiryncie" - w prosty sposób. Co jest kolorem "czarnym" (zdefiniowanym jako przezroczysty w nagłówku) to jest dozwolone. Jeśli natomiast wykryjemy kolizję ze ścianą, to dalej iść się nie da.

Pierwszy pomysł jaki miałem to taki, żeby ludek nie mógł dalej iść przy wykryciu kolizji, ale to sprawiało, że czepiał się ściany jak naszedł na nią jednym pikselem i dalej nic nie dało się zrobić. No to wymyśliłem inaczej - do każdego ifa dodałem jeszcze taki kwiatek:

If IsKeyDown("LEFT") Then pos_x=pos_x-1
	DisplaySprite(1, pos_x, pos_y)
		If Collision (#SPRITE_VS_BRUSH, 1, 1, 1, 1) Then pos_x=pos_x+1
		DisplaySprite(1, pos_x, pos_y)


Jak widać, w trochę mało elegancki sposób "cofam ten sęk", tzn. z powrotem przypisuję współrzędnej x wartość pierwotną jeśli narysowany sprajt nakłada się z tłem. To działa, ale tylko "teoreticznie", bo okazuje się, że jak trochę połażę po labiryncie to tu i ówdzie da się wejść w ścianę i ludek albo zaczyna "chodzić" wewnątrz ściany po jakimś dziwnym ukosie, albo się teleportuje w inne miejsce.

Pytanie brzmi - gdzie popełniłem błąd? I czy błąd leży po mojej stronie, czy po stronie funkcji detekcji kolizji?
Jak chcecie to wrzucę gdzieś archiwum z całością (skrypt, plik wykonywalny, użyte grafiki).
[#2] Re: [Hollywood] Prosta pętla i wykrywanie kolizji

@recedent, post #1

Ja bym sprobowal tak: jesli idzies np. w lewo i doszlo do kolizji to w jakies zmiennej KOL_LEWO dajesz TRUE.
Przy wybieraniu w dalszym ciagu kierunku lewo, sprawdzasz czy ta zmienna jest TRUE czy FALSE.
Jesli FALSE mozesz sprajta przesunac dalej, jesli TRUE to nie.
Wiadomym jest ze jesli zmienisz kierunek np. na prawo i dalo sie zrobic krok zmienna ta ustawiasz na FALSE.

Mam tylko pewne obawy jak cos takiego zachowa sie jesli sprajt dotknie rogu np dol + lewo.

Ostatnia aktualizacja: 23.05.2021 23:03:18 przez Phibrizzo
[#3] Re: [Hollywood] Prosta pętla i wykrywanie kolizji

@recedent, post #1

Pytanie brzmi - gdzie popełniłem błąd? I czy błąd leży po mojej stronie, czy po stronie funkcji detekcji kolizji?

Wydaje mi się, że błąd leży w sposobie użycia komendy IF Hollywood.

Używasz jednolinijkowego If .. Then przez co mimo że w Twoim kodzie jest wcięcie, to komenda cofająca Sprite'a w przypadku kolizji jest wykonywana zawsze w głównej pętli, a powinna tylko w klauzuli, gdy poruszamy Sprite'a w danym kierunku.

Poprawna forma według mnie powinna wyglądać następująco:

If IsKeyDown("LEFT")
	pos_x=pos_x-1
	DisplaySprite(1, pos_x, pos_y)
	If Collision (#SPRITE_VS_BRUSH, 1, 1, 1, 1)
		pos_x=pos_x+1
		DisplaySprite(1, pos_x, pos_y)
	EndIf
Endif

Warto też rozdzielić poszczególne ruchy tak, by tylko jeden był wykonywany za pomocą sekwencji If ... ElseIf ... EndIf. Całość:

If IsKeyDown("LEFT")
	pos_x=pos_x-1
	DisplaySprite(1, pos_x, pos_y)
	If Collision (#SPRITE_VS_BRUSH, 1, 1, 1, 1)
		pos_x=pos_x+1
		DisplaySprite(1, pos_x, pos_y)
	EndIf
ElseIf IsKeyDown("RIGHT")
	pos_x=pos_x+1
	DisplaySprite(1, pos_x, pos_y)
	If Collision (#SPRITE_VS_BRUSH, 1, 1, 1, 1)
		pos_x=pos_x-1
		DisplaySprite(1, pos_x, pos_y)
	EndIf
ElseIf IsKeyDown("UP")
	pos_y=pos_y-1
	DisplaySprite(1, pos_x, pos_y)
	If Collision (#SPRITE_VS_BRUSH, 1, 1, 1, 1)
		pos_y=pos_y+1
		DisplaySprite(1, pos_x, pos_y)
	EndIf
ElseIf IsKeyDown("DOWN")
	pos_y=pos_y+1
	DisplaySprite(1, pos_x, pos_y)
	If Collision (#SPRITE_VS_BRUSH, 1, 1, 1, 1)
		pos_y=pos_y-1
		DisplaySprite(1, pos_x, pos_y)
	EndIf
EndIf


Ostatnia aktualizacja: 24.05.2021 04:24:06 przez Hexmage960
1
[#4] Re: [Hollywood] Prosta pętla i wykrywanie kolizji

@Hexmage960, post #3

A nie da się jakoś najpierw sprawdzić czy następny pixel da kolizję i tylko w razie otrzymania odpowiedzi negatywnej zmienić położenie?
[#5] Re: [Hollywood] Prosta pętla i wykrywanie kolizji

@pisklak, post #4

to juz nie bedzie kolizja sprite'u z tlem
[#6] Re: [Hollywood] Prosta pętla i wykrywanie kolizji

@juen, post #5

Ale może być jeśli kolor tła będzie unikalny i sprawdza się po kolorze. Zresztą ten kod w sumie to właśnie robi. Tylko że chyba nie da się sprawdzić kolizji nie ruszając sprita.

Ostatnia aktualizacja: 24.05.2021 07:33:35 przez pisklak
[#7] Re: [Hollywood] Prosta pętla i wykrywanie kolizji

@juen, post #5

@Pisklak

Tylko że chyba nie da się sprawdzić kolizji nie ruszając sprita.


Według mnie chyba da się to osiągnąć manipulując parametrami x i y funkcji Collision():

Poniżej na przykładzie podaję 2 (zamiast 1) jako parametr x w przypadku przemieszczania Sprite'a w lewo. Funkcja powinna wówczas sprawdzić kolizję, tak jakby Brush był przesunięty o jeden w prawo.

Zaznaczam, że nie wiem czy to zadziała, bo nie sprawdzałem w praktyce.

If IsKeyDown("LEFT") And Not Collision (#SPRITE_VS_BRUSH, 1, 1, 2, 1)
	pos_x=pos_x-1
	DisplaySprite(1, pos_x, pos_y)
Endif


Ostatnia aktualizacja: 24.05.2021 07:37:48 przez Hexmage960
1
[#8] Re: [Hollywood] Prosta pętla i wykrywanie kolizji

@Hexmage960, post #7

Jeśli działa to o to właśnie mi chodziło OK
[#9] Re: [Hollywood] Prosta pętla i wykrywanie kolizji

@pisklak, post #6

no na tym polega wlasnie sprzetowe wykrywanie kolizji sprite'a. dla kazdego innego przypadku bedzie to programowe wykrywanie
[#10] Re: [Hollywood] Prosta pętla i wykrywanie kolizji

@Hexmage960, post #3

Dzięki za pomoc. Wygląda na to, że faktycznie te wielokrotne If-y sprawiały kłopoty. Kiedy testuję kod z postu nr 3, postać zachowuje się poprawnie...

...z tą różnicą że można się poruszać tylko w jednym kierunku na raz (co nie dziwi zważywszy na to jak teraz wszystko jest rozpisane), ale to można (myślę) poprawić dodając dodatkowe reguły dla dwóch klawiszy wciśniętych na raz. Efekt "wchodzenia w ścianę" widać nieznacznie i tylko kiedy się uprzemy i trzymamy klawisz kierunku stojąc przy ścianie. Wygląda to nawet pociesznie - jakby postać odbijała się od przeszkody.

Natomiast przy wykorzystaniu kodu z postu nr 7 (konkretnie w taki sposób):

While quit = False
	If IsKeyDown("LEFT") And Not Collision (#SPRITE_VS_BRUSH, 1, 1, 2, 1)
	pos_x=pos_x-1
	DisplaySprite(1, pos_x, pos_y)
	EndIf

	If IsKeyDown("RIGHT") And Not Collision (#SPRITE_VS_BRUSH, 1, 1, 0, 1)
	pos_x=pos_x+1
	DisplaySprite(1, pos_x, pos_y)
	EndIf

	If IsKeyDown("UP") And Not Collision (#SPRITE_VS_BRUSH, 1, 1, 1, 2)
	pos_y=pos_y-1
	DisplaySprite(1, pos_x, pos_y)
	EndIf

	If IsKeyDown("DOWN") And Not Collision (#SPRITE_VS_BRUSH, 1, 1, 1, 0)
	pos_y=pos_y+1
	DisplaySprite(1, pos_x, pos_y)
	EndIf

	WaitTimer(1, 10)
Wend


mimo że nie dałem 'Else If' - wygląda na to, że wszystko działa poprawnie.
2
[#11] Re: [Hollywood] Prosta pętla i wykrywanie kolizji

@recedent, post #10

No to czekamy z niecierpliwością na następcę Superfroga ok, racja

A tak zdefiniowane IFy jak w pierwszym poście to chyba nie mogły działać. Nie znam się na Hollywood ale if...then odnosi się do rozkazów w jednej linii zazwyczaj. Także rozkazy pod takim ifem będą się zawsze wykonywały.

Ostatnia aktualizacja: 24.05.2021 11:25:29 przez pisklak
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