Wizja
Najpierw może
odgórna wizja jak to powinno wyglądać. Ponieważ jest wiele obiektów z którymi
kolidujemy powinniśmy, jakoś rozróżniać czy obiekt ma podlegać kolizji czy nie.
Osiągniemy to tworząc kategorię które mogą między sobą kolidować w zależności
jak sobie to zdefiniujemy. Po co ? Weźmy sytuację gdzie nastąpiła kolizja i
jakiś element powinien zniknąć, a co za tym idzie nie powinno więcej tych
kolizji już występować. Wczytując mapę mamy całą warstwę obiektów, co więcej
ustawiamy że bohater się z nią zderza. Obiekty z którymi się zderzyliśmy
powinniśmy jakoś naznaczać, aby nie było powtórnie z nimi kolizji. To co się
robi w praktyce w tym momencie to zmienia kategorię danego obiektu. Np. na taką
z którą nie możemy kolidować. A teraz wszystko powoli.
Kategorie filtra
Tworzymy najpierw
zmienne finalne które będą dzieliły na kategorie. Tworzymy więc w klasie
głównej gry WordCharger
public static final short DEFAULT_BIT = 1; public static final short BATTERY_HERO_BIT = 2; public static final short WORDNOTE_BIT = 4; public static final short DESTROYED_BIT = 8
Kategorie w
swojej budowie wymaga podania wartości bitowej, typu zmiennego short, którego
zakres pozwala nam osiągnąć przedział [-32768, 32767]. Wielkość typu short jest
ustalona na 2 bajty. Przeliczając wielkość bajta na bity, jednemu bajtu
przypada 8 bitów, więc z 2 bajtów robi się tym sposobem 16 możliwych bitów.
Każdy taki bit to odrębna kategoria którą możemy stworzyć. Ponieważ każdy bit jest
przesunięty w ciągu w lewo, zamieniając to na wartość dziesiętną uzyskujemy
właśnie te wartości widziane powyżej.
0000000000000001
0000000000000010
0000000000000100
0000000000001000
…
uzyskanie
kolejnych wartości dziesiętnej jest możliwe dzięki potęgowaniu dwójki do
kolejnych potęg z zakresu (1-16). Przy czym pierwsza wartość będzie równa 1, a ostatnia 65536. Daje nam
to pokrycie całego zakresu zaczynając od przedziału ujemnego.
Ustawianie kategorii i masek
Każdemu obiektowi
teraz powinniśmy poustawiać kategorie. Potrzebujemy więc na początku ustawiać
filtry dla fixture bohatera. Najpierw przypiszemy fixture bohaterowi kategorię
wcześniej zdefiniowaną. Ważna kolejność, dlatego koniecznie filter należy
umieścić po definicji fixture. Więc w metodzie defineBatteryHero dopisujemy
fixtureDef.filter.categoryBits = WordCharger.BATTERY_HERO_BIT;
Drugą sprawą jest
ustawić maski. Maski służą ustalaniu z jakimi kategoriami może kolidować dany
fixture.
fixtureDef.filter.maskBits = WordCharger.DEFAULT_BIT | WordCharger.WORDNOTE_BIT;
w ten sposób
określamy że nasz bohater, a dokładnie jego fixture może kolidować z kategorią normalną
oraz kategorią oznaczoną WORDNOTE_BIT.
Teraz w klasie
InteractiveTileObject tworzymy metodę ustawiającą kategorię filtra. Robimy to w
tym miejscu ponieważ będzie to metoda uniwersalna dla klas dziedziczącej po
niej. Metoda w parametrze powinna przyjmować wybrana kategorie którą chcemy
przypisać.
public void setCategoryFilter(short filterBit) { // TODO Filter filter = new Filter(); filter.categoryBits = filterBit; fixture.setFilterData(filter); }
Wewnątrz tworzymy
nowy filter, oraz od razu temu obiektowi przypisujemy to co zostało przesłane (filterBit)
przy wywołaniu tej metody. Bierzemy w następnym kroku fixture, do którego mamy
dostęp jako że jest to pole obowiązujące w całej klasie i ustawiamy stworzony
filter metodą setFilterData. setFilterData jest jedną z zdefiniowanych odgórnie
metod którą posiada ten „klocek libGDX” Filter.
Zmienne nastroje notki
Pora przejść do
klasy WordNote i tu osobno już sprecyzować jakiej dokładnie kategorii chcemy ten
obiekt przypisać.
setCategoryFilter(WordCharger.WORDNOTE_BIT);
od tego momentu
od utworzenia WordNote będzie właśnie tej kategorii. My chcemy zmienić tą
kategorię podczas kolizji. Dlatego w metodzie onHit() dopisujemy
setCategoryFilter(WordCharger.DESTROYED_BIT);
Co widzimy?
Nastąpiła kolizja z WordNote. Liczy się tylko jeden z komunikatów, drugi dla
testów był akurat wynikiem kolizji z tą notką wyżej. Jak widać postać może wejść w pole gdzie
znajduje się obiekt. Brak tu kolizji. Jest to właśnie efekt działania filtra.
Po kolizji zmieniliśmy kategorię filtra WordNote na DESTROYED_BIT, a wracając
wcześniej do kodu gdzie ustalaliśmy maski dla fixture bohatera określiliśmy aby
kolizja mogła występować tylko dla kategorii z etykietką DEFAULT_BIT oraz
WORDNOTE_BIT. Dla przypomnienia powtórnie odpowiedzialna ta sama linia kodu,
aby nie szukać
fixtureDef.filter.maskBits = WordCharger.DEFAULT_BIT | WordCharger.WORDNOTE_BIT;
Jesteśmy już w
stanie wyłączać kolizję pomiędzy obiektami. Jednak co dalej będziemy chcieli to
aby po kolizji obiekt zniknął.
Wyciąganie pojedynczej komórki
Przechodząc do
samej tabliczki wiemy że jest ona częścią całej zdefiniowanej jednej warstwy z
pliku mapy TiledMap. My jednak nie chcemy niszczyć całej warstwy, a
poszczególne elementy. Należy powiedzieć w tym miejscu, że cała mapa jest
złożona z pojedynczych komórek, tak przecież tworzyliśmy ją w edytorze
stawiając „stemple” kafelek. Wczytując mapę do obiektu TiledMap nie utraciliśmy
możliwości odwoływania się do poszczególnych kafelek. Podczas kontaktu w
trakcie kolizji wiemy właściwie jaka jest dokładna pozycja body elementów
biorących w nich udział. Dzięki czemu możemy odpowiednio przeliczyć i określić
w ten sposób, która to kafelka. Tworzymy więc metodę zwracającą konkretną
kafelke
public TiledMapTileLayer.Cell getCell() { }
Wewnątrz na początku
odwołujemy się do warstwy, w naszym przypadku jest to warstwa 4, licząc od 0 będzie
3;
TiledMapTileLayer layer = (TiledMapTileLayer) map.getLayers().get(3);
Biorąc pozycję x i
dzieląc ją na długość kafelki uzyskamy, która to jest kafelka. Dodatkowo należy
jeszcze uwzględnić skalowanie które kiedyś zrobiliśmy. Należy cały ten proces
odwrócić. Jest to nic innego jak odwrócenie ułamka 70 / WordCharger.PPM.
Dodatkowo rzutujemy na typ (int), kafelki są całymi liczbami, a nie typem zmiennoprzecinkowym
float. Całość zwracamy jako efekt wywołania całej metody przy pomocy słowa
kluczowego return.
return layer.getCell((int) (body.getPosition().x * WordCharger.PPM / 70), (int)(body.getPosition().y * WordCharger.PPM / 70));
Wstawianie pustego kafla
Czas skorzystać z
dobrodziejstwa które udało się stworzyć. Przechodząc do klasy WordNote w
metodzie onHit dopisujemy
getCell().setTile(null);
Odpalając grę i
kolidując z notką efekt następujący
Z notatki
pozostał tylko no cóż … obszar debugownia. Co mówi że obiekt istnieje ale brak
kolizji i ustawiliśmy tile na null. Muszę się przyznać że już fajnie popykać
pozbijając trochę notek ;d
Tyle na dziś
Brak komentarzy:
Prześlij komentarz