Pamięta ktoś jeszcze czasy kiedy w telewizji leciały programy Reality Show typu BigBrother, Dwa Światy itp. Tym jakże krótkim wstępem chcę wprowadzić was w dzisiejszy wpis, w którym zajmiemy się stworzeniem kamery podążającej za postacią gracza. Wpis zaczniemy od sprawdzenia obecnego stanu naszego projektu, później chwilę zastanowimy się co chcemy osiągnąć, a na koniec realizujemy nasz plan.
Obecny stan projektu
Otóż obraz gry ograniczony jest do niewielkiego obszaru widzianego na ekranie, w chwili gdy nasz bohater przekracza ten obszar po prostu znika z naszego pola widzenia, można powiedzieć staje się duchem, gdzieś jest ale go nie ma. Możemy to zobaczyć poniżej.
Przemyślenia i ich implementacja
Na początku chcielibyśmy, aby kamera śledziła ruchy gracza (naszej żółtej kropki). Co nie będzie jakimś wielkim wyzwaniem, ponieważ biblioteka libgdx ma w sobie wbudowaną klasę OrthographicCamera odpowiedzialną za obsługę kamery. Dla naszych obecnych testów,obszar gry – nasza późniejsza mapa będzie miała rozmiar 5000px na 5000px. Wykorzystując wspomnianą wcześniej klasę, możemy uzyskać efekt, gdzie nasz bohater będzie zawsze znajdował się w środku kamery nie zależnie czy będziemy w punkcie (0,0), czy (5000,5000). Na razie zapiszmy kod, który nam to umożliwi i zobaczmy jak to wygląda w praktyce.
Na początek dodajemy zmienną klasy OrthographicCamera.
private OrthographicCamera camera;
Inicjalizujemy nową zmienną w metodzie create() oraz ustawiamy naszej kamerze zoom równy 0.2.
camera = new OrthographicCamera(5000,5000); camera.zoom = (float) 0.2;
Następnie zmieniamy inicjalizację klasy Player, tak aby początkowa pozycja gracza była równa środkowi planszy podanej w konstruktorze klasy OrthographicCamera.
player = new Player(camera.viewportWidth / 2f, camera.viewportHeight / 2f);
Następnie w metodzie update() należy ustawić jej odświeżanie co każdą klatkę, tak aby kamera poruszała się wraz z bohaterem.
camera.update(); batch.setProjectionMatrix(camera.combined); camera.position.set(player.x, player.y, 0);
Dzięki tym kilku linijką uzyskaliśmy efekt, o którym pisałem wcześniej, mamy kamerę śledzącą naszego bohatera. Jednak pojawią się problemy w chwili, gdy bohater dochodzi do końca mapy. Jeden z problemów to fakt, że wychodzi poza obszar mapy. Natomiast drugi z nich, że kamera pokazuje obszar poza mapą czego nie chcemy. Dla ułatwienia stworzymy prostokąt z czerwoną obwódką, który będzie symbolizował granice mapy.
Tworzymy dwie zmienne Klasy Texture oraz Pixmap, dzięki którym stworzymy wspomnianą wcześniej granicę mapy.
private Texture texture; private Pixmap pixmap;
Następnie w podobny sposób jak już robiliśmy tworzymy prostokąt, jednak tym razem niewypełniony w środku.
pixmap = new Pixmap(5000, 5000, Pixmap.Format.RGBA8888); pixmap.setColor(Color.RED); pixmap.drawRectangle(0,0, 5000, 5000); texture = new Texture(pixmap); pixmap.dispose();
Problem związany z pokazywaniem obszaru poza mapą został zaprezentowany na screenie powyżej.
Pierw zajmiemy się wychodzeniem bohatera poza mapę. Otóż wystarczy zrefaktoryzować kod odpowiedzialny za poruszanie się bohaterem, ograniczając jego ruchy to 5000px na 5000px.
Kod ten wygląda teraz następująco
if(Gdx.input.isKeyPressed(Input.Keys.W) && player.y < 5000-2*player.radius){ player.y += 5; } if(Gdx.input.isKeyPressed(Input.Keys.S) && player.y > 0){ player.y -= 5; } if(Gdx.input.isKeyPressed(Input.Keys.A) && player.x > 0){ player.x -= 5; } if(Gdx.input.isKeyPressed(Input.Keys.D) && player.x < 5000-2*player.radius) { player.x += 5; }
Teraz musimy przemyśleć co zrobić aby kamera przestała się ruszać w odpowiednim momencie, tak aby nie pokazywała obszaru poza mapą.
Powyżej zamieszczam swoje notatki, które pomogły mi w rozwiązaniu tego problemu. Najmniejszy prostokąt to kamera, czyli obraz widziany na naszym ekranie. Większy prostokąt to obszar, po którym kamera się porusza. Zaś największy prostokąt to mapa wraz z obszarem, gdzie kamera jest statyczna. Teraz pozostaje już tylko to zapisać w javie i zobaczyć czy uzyskaliśmy pożądany efekt.
// ustawienie kamery tak aby mapa była maksymalnie do krańców ekranu // ustawienie kamery z lewej strony i prawej strony // operacje dla środka ekranu if(player.x > 500 && player.x < 4500) { if(player.y > 500 && player.y < 4500) { camera.position.set(player.x, player.y, 0); }else{ if(player.y < 500){ camera.position.set(player.x, 500, 0); }else{ camera.position.set(player.x, 4500, 0); } } } // operacje dla krańców ekranu if(player.x < 500 || player.x > 4500) { if(player.y < 500 || player.y > 4500){ if(player.x < 500 && player.y < 500){ camera.position.set(500, 500, 0); } }else { if (player.x < 500) { camera.position.set(500, player.y, 0); } else { camera.position.set(4500, player.y, 0); } } }
Efekt naszej dzisiejszej pracy
Podsumowanie
Dziś udało się nam wykonać, bardzo ciekawy i zarazem ważny element gry. Jak widać było wraz z kolejnymi linijkami pojawiały się nowe problemy do rozwiązania. Jednak przy pomocy logicznego myślenia oraz zapisków w notesie udało się nam je rozwiązać. Projekt z każdym wpisem nabiera coraz lepszych kształtów, lecz nadal jest to wersja, która ma za zadanie testowanie rozwiązań backendowych. Jak już wspominałem frontendem zajmiemy się później. Zatem pozostaje czekać na kolejne wpisy rozwijające ten projekt.
Pozdrawiam,
sirmarbug