python-arcade-oo/dzien3_4_platformowka
Oskar Kapala 7c33b6bb63 scaffold: 5-dniowy kurs OOP + arcade
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-03 10:24:17 +02:00
..
gra.py scaffold: 5-dniowy kurs OOP + arcade 2026-08-03 10:24:17 +02:00
README.md scaffold: 5-dniowy kurs OOP + arcade 2026-08-03 10:24:17 +02:00

Dni 34 — platformówka wg oficjalnego tutoriala

Podstawa: Simple Platformerhttps://api.arcade.academy/en/latest/tutorials/platform_tutorial/index.html

Tutorial jest po angielsku i ma 14 kroków. Robimy go po kolei, ale nie kopiuj całych plików — przepisuj kod ręcznie do gra.py i po każdym kroku uruchamiaj:

python dzien3_4_platformowka/gra.py
git add -A && git commit -m "dzien3: krok 5 — grawitacja"

Assety (grafika, dźwięki) — tutorial używa paczki Kenney'a, pobierz z https://kenney.nl/assets do katalogu assets/. Arcade ma też wbudowane zasoby dostępne przez ścieżki ":resources:images/..." — na start to wystarczy i nic nie trzeba pobierać.


Dzień 3 — gracz, platformy, fizyka, skok, kamera

Kroki 17 tutoriala.

  • Krok 1 — Install and Open a Window. Klasa okna, __init__ z super(), on_draw() z self.clear(). To już umiesz z dnia 1 — przelatujemy szybko.
  • Krok 2 — Textures and Sprites. arcade.Sprite(ścieżka, scale). Zwróć uwagę: teraz sprite ma obrazek, a nie kolorowe koło.
  • Krok 3 — Many Sprites with SpriteList. Osobne listy: player_list, wall_list. Ułóż podłogę w pętli for x in range(0, 1250, 64).
  • Krok 4 — Add User Control. on_key_press / on_key_release ustawiają change_x.
  • Krok 5 — Add Gravity. arcade.PhysicsEnginePlatformer(player_sprite, walls=wall_list, gravity_constant=1.0). To jest KOMPOZYCJA: okno ma silnik fizyki (self.physics_engine), a nie jest silnikiem fizyki. Dziedziczenie = „jest czymś”, kompozycja = „ma coś”. Nie myl tych dwóch. Skok: w on_key_press sprawdź self.physics_engine.can_jump() i ustaw change_y = PLAYER_JUMP_SPEED. W on_update() wołaj self.physics_engine.update() — silnik sam przesuwa gracza i zatrzymuje go na ścianach (nie wołaj tu player_list.update(), bo ruch policzyłby się dwa razy).
  • Krok 6 — Resetting. Wydziel metodę setup() i zawołaj ją z __init__. Dzięki temu restart gry to jedno wywołanie.
  • Krok 7 — Adding a Camera. W arcade 3.x klasa nazywa się arcade.Camera2D (stare tutoriale pokazują arcade.Camera — to 2.x). Dwie kamery: jedna śledzi gracza (świat), druga stoi w miejscu (GUI/punkty).

Koniec dnia 3: gracz biega po platformach, skacze, kamera jedzie za nim. Commit: dzien3: platformowka - ruch, skok, kamera.


Dzień 4 — monety, dźwięki, wrogowie, poziomy, ekran końca

Kroki 814 tutoriala.

  • Krok 8 — Collecting Coins. arcade.check_for_collision_with_list + remove_from_sprite_lists() (znasz z dnia 2).
  • Krok 9 — Adding Sound. arcade.load_sound(...) w setup(), arcade.play_sound(...) przy zebraniu monety i przy skoku. Dźwięki wczytuj RAZ w setup(), nie w on_update() — inaczej gra zacznie zwalniać.
  • Krok 10 — Adding a Score. Licznik punktów + arcade.draw_text na kamerze GUI.
  • Krok 11 — Using a Scene. arcade.Scene zamiast ręcznie trzymanych list. To znowu kompozycja: scena ma listy sprite'ów i wie, w jakiej kolejności je rysować.
  • Krok 12 — Loading a Map From a Map Editor. Mapa z pliku .tmx (edytor Tiled), arcade.load_tilemap.
  • Krok 13 — More Types of Layers. Warstwy: platformy ruchome, kolce, tło.
  • Krok 14 — Multiple Levels. Numer poziomu w atrybucie self.level, wczytywanie pliku mapa_{self.level}.tmx.

Zadania własne (poza tutorialem)

  • Wrogowie. Wykorzystaj klasę Enemy z dnia 2 — przenieś ją tutaj i dostosuj do platformówki (np. wróg chodzi po platformie i zawraca na jej końcu). Kolizja gracza z wrogiem = utrata życia.

  • Ekran końca gry. Zrób go przez arcade.View: klasa GameView (rozgrywka) i klasa GameOverView (napis + „naciśnij ENTER”). Przełączanie: self.window.show_view(GameOverView()). To przedsmak dnia 5 — stany gry jako osobne klasy.

  • ZADANIE OOP DNIA — property health (0100).

    Dodaj graczowi punkty życia tak, żeby nie dało się ustawić wartości spoza zakresu 0100 — nawet przez pomyłkę w innym miejscu kodu.

    class Player(arcade.Sprite):
        def __init__(self, sciezka, scale):
            super().__init__(sciezka, scale)
            self._health = 100        # podkreślnik = "to jest wewnętrzne, nie ruszaj z zewnątrz"
    
        @property
        def health(self):
            """Getter — działa jak zwykły odczyt atrybutu: print(gracz.health)"""
            return self._health
    
        @health.setter
        def health(self, wartosc):
            """Setter — uruchamia się przy `gracz.health = 120` i pilnuje zakresu."""
            # TODO: przytnij wartość do przedziału 0-100
            #       (podpowiedź: max(0, min(100, wartosc)))
            # TODO: jeśli po przycięciu jest 0 — ustaw self.zywy = False
            ...
    

    Sens property: z zewnątrz gracz.health -= 30 wygląda jak zwykłe działanie na atrybucie, ale pod spodem wykonuje się TWÓJ kod z walidacją. Nie trzeba pisać gracz.set_health(gracz.get_health() - 30) ani pamiętać o sprawdzaniu zakresu w każdym miejscu, gdzie gracz obrywa.

    Sprawdź, że działa:

    gracz.health = 150   # -> 100
    gracz.health = -20   # -> 0, i gracz przestaje żyć
    
    • Narysuj pasek życia (arcade.draw_lbwh_rectangle_filled) o szerokości proporcjonalnej do gracz.health.

Koniec dnia 4: kompletna platformówka z monetami, dźwiękiem, wrogami, paskiem życia i ekranem końca. Commit: dzien4: platformowka - monety, dzwieki, wrogowie, health property.


Ściąga — API arcade 3.x

Co Jak
czyszczenie ekranu self.clear() (nie arcade.start_render())
odświeżenie listy sprite_list.update(delta_time) (nie on_update)
metoda w klasie sprite def update(self, delta_time=1/60, *args, **kwargs):
kamera arcade.Camera2D (nie arcade.Camera)
prostokąt arcade.draw_lrbt_rectangle_filled / draw_lbwh_rectangle_filled
kolor tła self.background_color = arcade.color.X