Celuj, pal, leć! Czysty fizyczny obłęd, potężne uderzenia i nieskończona walka o topkę.
Find a file
2026-05-19 21:38:59 +02:00
autoloads integracja z serwerem do leaderboarda dawida 2026-05-19 01:46:54 +02:00
cannon fix input bug when holding before transitioned into level 2026-05-19 21:38:59 +02:00
flag add icons for the rolling numbers for the stats, fix them up, restructure, better flag mechanic 2026-05-19 20:46:33 +02:00
fonts restrukturyzacja, nowe fonty, sfxy, soundmanager zajumany z innego projektu, nowy feature (spring shroom) 2026-05-19 01:09:49 +02:00
game restrukturyzacja, nowe fonty, sfxy, soundmanager zajumany z innego projektu, nowy feature (spring shroom) 2026-05-19 01:09:49 +02:00
kra restrukturyzacja, nowe fonty, sfxy, soundmanager zajumany z innego projektu, nowy feature (spring shroom) 2026-05-19 01:09:49 +02:00
misc working shoot force progress bar, funny player placeholder 2026-04-06 18:18:58 +02:00
music restrukturyzacja, nowe fonty, sfxy, soundmanager zajumany z innego projektu, nowy feature (spring shroom) 2026-05-19 01:09:49 +02:00
player move _on_player_stopped, _on_player_shot to signals within player: player_stopped, player_shot. this makes it easier to create scripts that depend on these events, without adding external function calls and child references in the player. also added animated hbox stats. 2026-05-19 21:36:21 +02:00
sfx restrukturyzacja, nowe fonty, sfxy, soundmanager zajumany z innego projektu, nowy feature (spring shroom) 2026-05-19 01:09:49 +02:00
sky gameover.kra export 2026-05-01 15:45:57 +02:00
terrain restrukturyzacja, nowe fonty, sfxy, soundmanager zajumany z innego projektu, nowy feature (spring shroom) 2026-05-19 01:09:49 +02:00
textures/icons add icons for the rolling numbers for the stats, fix them up, restructure, better flag mechanic 2026-05-19 20:46:33 +02:00
.editorconfig initial commit 2026-04-05 11:20:01 +02:00
.gitattributes initial commit 2026-04-05 11:20:01 +02:00
.gitignore gitignore do buildów + export presety 2026-05-19 01:56:15 +02:00
default_bus_layout.tres restrukturyzacja, nowe fonty, sfxy, soundmanager zajumany z innego projektu, nowy feature (spring shroom) 2026-05-19 01:09:49 +02:00
export_presets.cfg gitignore do buildów + export presety 2026-05-19 01:56:15 +02:00
LICENSE.md add LICENSE.md 2026-05-19 09:05:54 +02:00
project.godot readme 2026-05-19 01:16:26 +02:00
README.md Update README.md 2026-05-19 08:47:43 +02:00

Ikonka Toss the Wolf

Toss the Wolf

Godot Engine Jolt Physics GDScript Platform Status

Poniższa dokumentacja opisuje architekturę, główne moduły oraz mechaniki gry Toss the Wolf. Projekt został zrealizowany w silniku Godot 4.6.2, wykorzystuje Jolt Physics jako silnik fizyczny oraz renderowanie w trybie Mobile.

Roadmap

  • Dodać więcej elementów interaktywnych
    • Obiekty Powietrzne
      • Latający kibel
      • Latające kolce
      • Wybuchające ptaki z przyczepianymi detonatorami
      • Chmury burzowe spowalniające i paraliżujące gracza na ok. 1 sekundę
      • Latające Kowadła
      • UFO: Statek kosmiczny porywa wilka na ułamek sekundy i „wypluwa” go 500 pikseli dalej z pełną prędkością.
    • Obiekty Lądowe
      • Miny lądowe paraliżujące gracza, ale dające mu duży boost.
      • Czołg z Newgrounds, przejeżdza gracza dając mu mały impuls do góry, większy do przodu.
  • Nowe biomy
    • Bagno: Teren ze zwiększonym tłumieniem liniowym (linear damping). Uderzenie w niego drastycznie redukuje siłę odbicia.
    • Zamarznięte Jezioro: Powierzchnia o niemal zerowym tarciu. Gracz po upadku może sunąć po niej przez setki metrów, jeśli upadł pod odpowiednim kątem.
  • Zastosować wzorzec projektowy (object pooling) w generatorze terenu, by jeszcze bardziej go usprawnić
  • Dodać lekkie kierowanie graczem w kierunku kursora (lewym przyciskiem myszy) po wystrzale
  • Strzelanie w gracza pistoletem + ammunicja którą można zdobywać w locie. Strzelanie gdy gracz leci w dół podbija go bardziej
  • Integracja i uwierzytelnianie za pomocą Newgrounds - osiągnięcia, zapisy, tablice wyników w chmurze
  • Inne wyrzutnie
    • Proca Gigantów z mechaniką naciągania jak w Angry Birds. Strzela strzałą - nabicie kilku żywych przeszkód daje impuls graczowi
    • Wulkaniczny Gejzer - wyrzuca wilka idealnie pionowo w górę; gracz musi użyć wiatru lub własnego ekwipunku, by skierować lot do przodu.
    • Wyrzutnia Rakietowa - słaby impuls początkowy, ale ogromne przyspieszenie nabierane w pierwszych sekundach lotu, dopóki rakieta nie wybuchnie.
    • Działo Grawitacyjne = zamiast nadawać maksymalny pęd, wystrzał drastycznie obniża skalę grawitacji wilka na pierwsze 10 sekund lotu.

Architektura Globalna (Autoloads / Singletons)

W grze zaimplementowano scentralizowany system zarządzania stanem oparty na wzorcu Singleton (Autoload). Gwarantuje to łatwy dostęp do najważniejszych danych i funkcji z poziomu każdego węzła w drzewie sceny.

🌐 Globals

Prosty skrypt przechowujący globalny stan sesji. Zapisuje na bieżąco wektor pozycji gracza (player_position), flagę stanu ładowania (is_loading) oraz pozwala na globalne wyłączenie kontroli gracza (disable_controls).

SignalBus

Centralna szyna zdarzeń. Optymalizuje komunikację między węzłami, unikając bezpośrednich referencji.

  • Aktualnie odpowiedzialny głównie za optymalizację logiki terenu co 0.2 sekundy emituje sygnał tick_terrain, zamiast zmuszać każdy chunk terenu do aktualizacji w klatce (w _process).

🎬 LevelManager

Moduł obsługujący płynne przejścia pomiędzy scenami. Udostępnia metodę restart(), która przeładowuje główną scenę (game.tscn) używając efektów zanikania ekranu (fade_in, fade_out) trwających 1 sekundę, kontrolując przy tym flagę blokady w Globals.

💾 SaveManager

Zarządza systemem zapisu najlepszego wyniku (personal_best).

  • Odczytuje i zapisuje dane z/do pliku user://savegame.save w formacie JSON.
  • Posiada zabezpieczenie sprawdzające, czy nowy osiągnięty dystans (pobierany z armaty) jest rzeczywiście większy od poprzedniego rekordu. Jeśli tak, emituje sygnał new_personal_best, na który reagują elementy interfejsu (np. Flaga).
  • Generowanie Nicku (username): Przy pierwszym uruchomieniu gry, gdy plik zapisu nie istnieje, skrypt używa funkcji generate_random_username() do stworzenia identyfikatora gracza. Ten identyfikator jest trwale zapisywany w pliku JSON i wykorzystywany do identyfikacji gracza na serwerze wyników.

Więcej o tym w sekcji Save Manager.

🎵 SoundManager

Zarządza systemem audio w grze, obsługując niezależnie muzykę i efekty dźwiękowe.

  • Odtwarzacz SFX: Wykorzystuje dynamicznie tworzony AudioStreamPolyphonic, wspierając do 64 nakładających się na siebie dźwięków jednocześnie (maksymalna polifonia). Dzięki temu nasilone akcje, takie jak szybkie uderzenia o ziemię (wywołujące pliki audio z BLOOD_SPLATTER_SOUNDS), nie "ucinają" się nawzajem.
  • Odtwarzacz Muzyki: Implementuje system inteligentnych przejść (crossfade). Funkcja play_music() korzysta z drzewa Tweenów (krzywe TRANS_EXPO, EASE_IN i EASE_OUT), by miękko wyciszyć aktualnie odtwarzany utwór do -80.0 dB, podmienić ścieżkę dźwiękową i łagodnie przywrócić jej głośność.

Mechaniki Główne

💣 Armata (Cannon)

Moduł odpowiedzialny za celowanie, ładowanie i wystrzał gracza.

  • Ładowanie strzału: Kiedy gracz przytrzymuje przycisk, skrypt oblicza siłę strzału. Wykorzystuje funkcję ping-pong i clampowaną krzywą wykładniczą (exp_clamped), aby wskaźnik siły płynnie rósł i malał w zakresie od 0.0 do 1.0, dając graczowi lepsze wyczucie "timingu".
  • Wystrzał: Zwolnienie przycisku aplikuje ostateczną siłę impulsywną (mnożnik MAX_FORCE = 7000.0) za pomocą osi lokalnej obiektu (global_transform.x). Wystrzał odtwarza specjalny efekt dźwiękowy (SFX) przy użyciu zintegrowanego SoundManagera.
  • Śledzenie postępu: Armata odpowiada również za przeliczanie przebytego dystansu względem początkowego punktu strzału (start_pos) i aktualizację wartości do UI z zaokrągleniem do jednego miejsca po przecinku. Oblicza moment, w którym gracz całkowicie wyhamuje w powietrzu lub na ziemi.

🐺 Gracz (Player)

Główny fizyczny obiekt gry, dziedziczący po RigidBody2D.

  • Fizyka i Kolizje: Opiera się na silniku Jolt. W metodzie _on_body_entered nasłuchuje zderzeń z podłożem (collision layer 2).
  • System obrażeń (Bloodsplats): Jeśli gracz uderzy w podłoże, a jego wektor prędkości (długość linear_velocity) przekracza stałą MIN_IMPACT (1700.0), system tworzy instancję obiektu BLOODSPLAT (bloodsplat.gd), który dla urozmaicenia wizualnego losuje swoją klatkę animacji z atlasu (obliczane za pomocą randi_range na bazie hframes i vframes), po czym zostaje osadzony w hierarchii obiektu terenu.
  • Koniec lotu: Zatrzymanie się gracza uruchamia funkcję _on_player_stopped(), która wyświetla ekran Game Over i wysyła polecenie zapisu postępu do SaveManager.

🎥 Kamera (Camera2D)

Dynamiczna kamera śledząca gracza na bieżąco. Po przekroczeniu pierwszych 20 metrów lotu, kamera płynnie zmienia swoje przesunięcie (offset). Używa funkcji lerp, dodając dynamiczny offset w osi Y bazujący na wektorze opadania gracza (linear_velocity.y / 40). Dzięki temu kamera patrzy w kierunku lotu gracza, znacząco poprawiając widoczność toru lotu na osi pionowej (clampowane miedzy -120 a 120 pikseli).

🖥️ Interfejs i Scena Główna

  • Game (game.gd): Pełni rolę głównego węzła scalającego środowisko startowe. Kontroluje bazowe referencje, m.in. dla węzła armaty.
  • Przycisk Resetu (reset_button.gd): Element interfejsu (UI) pojawiający się na ekranie końcowym lotu gracza (Game Over). Nasłuchuje wbudowanego sygnału pressed, po którym błyskawicznie chowa sam siebie i wywołuje na obiekcie LevelManager procedurę restart(), wznawiając nową rundę.

🌍 Tablica Wyników Online (Leaderboard)

Zintegrowany system sieciowy pozwalający na rywalizację z innymi graczami, zaimplementowany w skrypcie label_scores.gd i powiązany z kontrolką UI (RichTextLabel).

  • Komunikacja HTTP: Gra wykorzystuje węzeł HTTPRequest do komunikacji z zewnętrznym serwerem (API pod adresem IP zdefiniowanym w stałej SERVER_URL). Komunikacja opiera się na wymianie pakietów w formacie JSON (metody GET i POST).
  • Automatyczne przesyłanie postępów: Skrypt jest podłączony do szyny SaveManager i nasłuchuje sygnału new_personal_best. Gdy tylko gracz ustanowi nowy rekord na swoim urządzeniu, gra wywołuje funkcję submit_score(), wysyłając parę username oraz score do bazy danych, a po otrzymaniu kodu 200 OK odświeża lokalną tablicę.
  • Dynamiczne wyświetlanie (TOP 10): Pobrana z serwera lista najlepszych wyników jest parsowana z JSONa i formatowana jako tekst. Dzięki włączonej opcji bbcode_enabled w RichTextLabel, skrypt iteruje po wpisach i porównuje pobrane nazwy użytkowników z lokalnym zmienną SaveManager.username. Jeśli nastąpi dopasowanie, wynik aktualnego gracza zostaje pogrubiony i podświetlony na żółto (tagi [color=yellow]), znacznie poprawiając czytelność własnego pozycjonowania w rankingu.

Moduły Wizualne

🚩 Flaga Rekordu (Flag Shader)

Flaga wskazująca najlepszy do tej pory wynik gracza wykorzystuje zaawansowany shader (flag_wave.gdshader) typu canvas_item.

  • Animuje wierzchołki materiału używając funkcji trygonometrycznych (sinus) bazujących na upływie czasu (TIME) i zmiennych UV.
  • Pozwala na dostosowanie parametrów takich jak amplituda, częstotliwość i szybkość falowania.
  • Za pomocą parametru pole_side potrafi sztucznie wygasić (wytłumić) falowanie z odpowiedniej strony tekstury (tam, gdzie flaga dotyka masztu), korzystając z funkcji smoothstep, dając realistyczny efekt przypięcia materiału. Co więcej, posiada zaprogramowany animowany „wjazd” w kadr (Tween na bazie osi X), z jednoczesnym kręcącym się licznikiem metrów za każdym razem, gdy padnie nowy rekord.

Generacja Terenu

Node odpowiedzialny za proceduralne, pseudo-losowe generowanie nieskończonego terenu w grze Toss the Wolf. System dynamicznie ładuje fragmenty mapy oraz elementy interaktywne na podstawie wybranego środowiska, dbając jednocześnie o optymalizację pamięci poprzez automatyczne usuwanie niewidocznych obiektów.

TerrainGenerator (główny kontroler)

Główny Node2D który zarządza logiką powstawania mapy. Istnieje on jako lokalny node w scenie Game.

  • Metoda start_generator(biome_name) ładuje dane wybranego biomu i pregeneruje początkowy pas terenu (domyślnie 16 chunków). Powinna zostać wywołana przed jakąkolwiek inną operacją generatora.
  • Pierwsze 6 chunków (UNPOPULATED_CHUNK_COUNT) jest celowo pozbawionych elementów interaktywnych, zapewniając bezpieczną strefę startową na początku rundy.
  • System opiera się na sygnale SignalBus.tick_terrain. Oblicza dystans i dynamicznie dostawia nowe segmenty, utrzymując stały bufor wygenerowanego terenu przed pozycją gracza (domyślnie 4 chunki wyprzedzenia).

BiomeData (Resource)

Zasób danych przechowujący konfigurację unikalną dla konkretnego środowiska (np. grassy). Definiuje dwie pule obiektów gotowych do instancjowania:

  • chunks (Array[PackedScene]) - kolekcja wariantów podłoża.
  • features (Array[PackedScene]) - kolekcja możliwych do wylosowania elementów interaktywnych.

TerrainChunk (segment terenu)

Pojedynczy skrawek mapy o stałej szerokości 1000px.

Każdy nowo powołany chunk (poza strefą startową) wywołuje metodę populate_features(). Szansa na postawienie wylosowanego elementu interaktywnego w wyznaczonym punkcie (Marker2D) wynosi 20% (1 na 5, zdefiniowane przez stałą FEATURE_RARITY).

Każdy TerrainChunk nasłuchuje sygnału ticków terenu i automatycznie zwalnia pamięć (queue_free()), gdy znajdzie się w odległości 3000px za graczem, dbając o stałe, niskie zużycie pamięci.

BiomeFeature

Dedykowany obiekt pojawiający się na chunku (maksymalnie jeden element na segment). Zwykle jest to w pełni oskryptowany Node2D (np. grzyb odbijający z folderu f_bounce_shroom) realizujący własną logikę poprzez interakcję fizyczną z obiektami RigidBody2D, a konkretnie graczem. Uderzenie wywołuje apply_impulse(), nadając graczowi nagłe przyspieszenie, odpala lokalną animację aktywacji (np. sprężynowania) i wywołuje dźwięk za pomocą SoundManager.play_sfx().

Przepływ działania (w skrócie)

  1. Start: Uruchomienie rundy wywołuje start_generator("nazwa_biomu"), co konfiguruje dane z BiomeData.
  2. Pregeneracja: Generator stawia początkowe 16 chunków, w tym bezpieczny bufor startowy wolny od interakcji.
  3. Synchronizacja: Pętla nasłuchująca SignalBus.tick_terrain na bieżąco analizuje współrzędną X gracza.
  4. Rozbudowa: Gdy gracz zbliża się do granicy pregenerowanego terenu, dodawane są kolejne chunki z 20% szansą na wygenerowanie BiomeFeature.
  5. Czyszczenie: Fragmenty mapy, które gracz minie o 3000px, są bezpowrotnie niszczone.

Save Manager

Save Manager to Autoload który zarządza zapisywaniem i wczytywaniem postępu gracza (aktualnie jedynie najlepszym wynikiem personal_best).

Zmienna personal_best przechowuje lokalnie najwyższy zdobyty dotychczas wynik (przebyty dystans w “metrach”).

Przy pierwszym uruchomieniu gry, gdy plik zapisu nie istnieje, skrypt używa funkcji generate_random_username(). Łączy ona losowy przymiotnik (np. "Szalony", "Krwawy") z losowym rzeczownikiem (np. "Wilk", "Kibel") oraz liczbą (10-99), tworząc unikalny identyfikator gracza (np. "PoteznyKibel99"). Ten identyfikator jest trwale zapisywany w pliku JSON i wykorzystywany do identyfikacji gracza na serwerze wyników.

Funkcja save_game()

Pobiera aktualny dystans za pomocą cannon.get_distance(), skaluje go (dzieląc przez 100.0) i zaokrągla do jednego miejsca po przecinku metodą snapped(). Zapis do pliku następuje wtedy, gdy nowo obliczony dystans jest większy niż dotychczasowy (personal_best). Gdy warunek jest spełniony, aktualizuje zmienną personal_best, emituje zintegrowany sygnał na magistralę, po czym tworzy nową strukturę danych JSON do zapisu w dedykowanym pod ścieżką user://savegame.save.

Funkcja load_game()

Odpowiedzialna za odczyt danych z pliku zapisanego przez save_game(). Zwraca wartość typu float. Najpierw sprawdza, czy plik user://savegame.save istnieje. Jeśli go nie ma, natychmiast zwraca 0.0. Gdy plik zostanie znaleziony, otwiera go za pomocą FileAccess.READ, pobiera zawartość jako string tekstowy i przetwarza go za pomocą wbudowanego obiektu JSON. Jeśli parsowanie zakończy się sukcesem (if parse_result == OK) i zebrane dane zawierają klucz personal_best, zwracana jest jego wartość dla całego projektu.