Artykuł "niespodzianka" na temat nowo wstawionej znienacka pozycji, którą mogłeś(-aś) już ujrzeć w sekcji gier 💛. Pojawiła się nowa produkcja, którą udało mi się szybko skleić (bo w niecały miesiąc 😯!), aby sobie odkurzyć wiedzę z języka JavaScript 📖. "Frog Guy", bo taki tytuł nosi nowa gierka, to klon kolejnej innej znanej produkcji z lat .80, "Frogger" 🐸! Zapraszam do środka 😀!
"FROGGER". TROCHĘ O ORYGINALE I O SWOIM KLONIE
Produkcja firmy Konami z 1981 roku już wiele razy doczekała się od programistów nowych klonów, co widać po samych filmach na YouTube ▶️. Nic w tym dziwnego, bo sama gra choć mała w zawartości, to stanowi świetne ćwiczenie umiejętności programistycznych 🏋️♀️. Na początek, krótkie wyjaśnienie.
Co to za gra?
"Frogger" to gra, w której steruje się żabką i Twoim zadaniem jest "przeprowadzić" ją do 5 wolnych miejsc u góry mapy ℹ️. Gdy zajmiesz jedno z miejsc, to pojawia się kolejna żabka i tę samą czynność należy powtórzyć jeszcze 4 razy, aż wszystkie zostaną "umieszczone" na wszystkich miejscach 🐸.
Liczy się szybka reakcja i przewidywalność ⏩, gdyż po drodze trzeba ominąć jezdnię, po której jeżdżą samochody 🚗 (i tak, dobrze myślisz, są zabójcze dla Ciebie 💀), a następnie przejść jeszcze przez rzekę, po której pływają drewniane belki oraz żółwie 🐢, i trzeba je wykorzystać jako platformę 😁. Żółwiki od czasu do czasu lubią się chować, co uatrakcyjnia (i utrudnia 🙂) rozgrywkę ❤️.
Postanowiłem stworzyć mój własny klon gry "Frogger" (repozytorium jest dostępne na moim GitHubie) i tak powstał "Frog Guy" 😊. Ciekawostką niech będzie fakt, iż nie użyłem żadnego zewnętrznego narzędzia - silnika, frameworka, nawet biblioteki 😱! Całość gry to płótno HTML ("canvas"), szczypta formatowania CSS, a reszta to tylko czysty JavaScript 🚀🚀🚀!
Niżej masz zrzut ekranu z efektu końcowego wersji 1.0 🧨!
![]() |
Zrzut ekranu z gry "Frog Guy".
Trochę o implementacji
Teraz co nieco o szczegółach prac. Złożenie wszystkiego do kupy zajęło mi 24 dni ⏰. W ciągu jednej doby spędzałem jakieś 3-5 godzin, więc moim zdaniem poszło sprawnie i jestem zadowolony 👍. Było trochę łamania głowy, lecz na szczęście nie tak, jak przy klonie "Battle City" 😉.
Nie będę Cię zanudzać opisywaniem każdego elementu (bo jak jesteś ciekawy(-a), to możesz sobie zerknąć do repozytorium) 😊, lecz przytoczę parę takich najciekawszych części, które uznałem za najbardziej podchwytliwe 💥.
Podział mapy na części (i kafelki)
To był jeden z najcięższych puzzli 🧩. Wizualnie, mapa na której znajdują się obiekty, to prostokątna przestrzeń składająca się z rzędów różnego typu. Szerokość jest uzależniona od liczby miejsc dla żabek, aby zachować spójność i nie było rysowania miejsca "do połowy" 😜. Co więcej, wysokość (czyli liczba wierszy) na typ także jest nieregularna (np. chodnik ma jeden wiersz, a rzeka składa się z pięciu) 🧠.
Wiedziałem, że bezpośrednie operowanie na współrzędnych nie wchodzi w grę na dłuższą metę, bo dużo trudniej dodawałoby się nowe implementacje, więc trzeba było podejść do tego inaczej.
W moim klonie, mapa jest budowana z pojedynczych kafelków przez zaprogramowany system 🤖. Najpierw dodawane są miejsca dla żabek. Domyślnie jest 5, więc szerokość mapy przyjmie 15 kafelków po 8x8 każdy (ponieważ jedno miejsce przyjmuje szerokość 24 pikseli, zatem: 24 / 8 = 3). Do utworzonej grupy obiektów zostaje umieszczonych 5 obrazów ("sprite'ów"). Wewnątrz nich są jeszcze zaimplementowane pozycje dla żabek, aby jeszcze bardziej "związać" je dla zachowania zgodności z grafiką. Tak powstała grupa jest dodawana do listy ☑️.
Potem system przechodzi do utworzenia kolejnej warstwy (idąc od góry, więc następna jest rzeka) i postępuje podobnie. Wprowadzając parametry, tworzy przestrzeń o wymiarach 15x5 kafelków, dodaje "sprite'y", nakłada odpowiednio pozycję, dodaje do grupy, a grupa jest dodawana do listy ☑️. Z resztą pozostałych części mapy postępuje analogicznie, aż do chodnika, na którym stoi nasz zielony bohater 🐸.
Implementacja tego wszystkiego dała do wiwatu, jednak przyniosła pozytywny efekt 👍, bo później takie rzeczy, jak dodawanie obiektów na odpowiednich rzędach czy wykrywanie na jakim rodzaju terenu stoi gracz, były już bardzo proste do zaimplementowania i wprowadzania przyszłościowych zmian 😊.
Grupowanie obiektów i nieregularna liczba sztuk
W grze są tylko 2 rodzaje obiektów pływających na rzece, aczkolwiek przyjmują różne wielkości. Drewniana belka może być raz krótsza, raz dłuższa, a jedna grupa żółwi może składać się z 2 lub 3 sztuk ustawionych obok siebie 🙂. Łamigłówka przyjęła dwie twarze: graficzną i w materii wykrywania kolizji 😳!
Graficznie, drewnianą belkę trzeba było pociąć na 3 części 👇:
- lewy koniec,
- środek,
- prawy koniec.
Następnie wiedząc, że aby była ona wizualnie spójna, minimalnie musi przyjmować lewy i prawy koniec. Zatem należało umożliwić wprowadzenie do parametru liczbę środkowych kafelków. W taki sposób była generowana w rzeczywistości grupa pojedynczych kafelków, a całość prezentowała się jak jedna belka, która może być dowolnie długa, jak będę chciał 🌟.
Żółw nie potrzebował takiej przeróbki bowiem, z uwagi na animację, wystarczyło dodać obiekt do grupy i zdecydować ile sztuk ma być osadzonych w jednej grupie. Tyle 😄.
Wykrywanie kolizji musiało uwzględnić grupowanie obiektów, tak aby znów była spójność z tym, co gracz widzi na ekranie 👀. Lewy górny róg pierwszego obiektu, to jednocześnie lewy górny róg całej grupy, a jej szerokość to liczba obiektów przemnożona przez szerokość każdego z obrazka z osobna (8 pikseli) 🧠.
Udźwiękowienie
Ostatnia rzecz to dźwięki 🎶. W JavaScript zaskoczyły mnie mało przyjemnie 2 sprawy.
Po pierwsze 1️⃣, nie da się prosto pobrać czasu trwania klipu dźwiękowego z samego pliku (można co prawda kombinować poprzez metodę "onloadedmetadata", lecz byłoby trudno to pogodzić z inicjalizacją poszczególnych elementów gry).
Po drugie 2️⃣, nie można odtwarzać tego samego dźwięku, dopóki nie skończy grać, a to mi było potrzebne głównie do dźwięku przemieszczenia się żabki przez gracza, bo możesz naciskać prędzej, niż skończy się dźwięk ☺️.
Aby nie przedłużać czasu na szukanie jakichś niekonwencjonalnych sposobów, podszedłem do obu kwestii następująco: czas trwania dźwięku wstawiłem jako parametr i przypisywanie go w konstruktorze, a dźwięk gdy ma się odpalać jeszcze w trakcie grania tego samego dźwięku, tworzy za każdym razem nową instancję, zamiast korzystać z przechowywanej 😮. Tylko tak można sprawić, by dany dźwięk odpalał się w czasie, gdy jeszcze gra (wtedy de facto są to 2 różne instancje tego samego dźwięku) 🎵.
![]() |
Logo gry "Frog Guy".
I to tyle 🙂. Gra nie otrzymała zwiastuna, bo to taki mały projekt zrobiony na potrzeby repozytorium ℹ️.

