python-arcade-oo/dzien1/01_okno.py

124 lines
4.8 KiB
Python
Raw Permalink Normal View History

"""
Dzień 1, krok 1 pierwsze okno.
Cel: zobaczyć, że "klasa" to nic strasznego to przepis na obiekt, który
biblioteka arcade sama za nas uruchomi i sama będzie wołać jego metody.
Uruchom:
python dzien1/01_okno.py
"""
import arcade
# Stałe piszemy WIELKIMI literami. To zwykłe zmienne globalne — po to,
# żeby rozmiar okna zmieniać w jednym miejscu, a nie w pięciu.
SZEROKOSC = 800
WYSOKOSC = 600
TYTUL = "Dzień 1 — moje pierwsze okno"
# ----------------------------------------------------------------------------
# KLASA = przepis na obiekt.
#
# Zapis `class MyGame(arcade.Window)` znaczy: "MyGame jest rodzajem
# arcade.Window". To DZIEDZICZENIE. Nasza klasa dostaje za darmo wszystko,
# co potrafi okno z biblioteki: otwiera się, reaguje na mysz, na klawiaturę,
# odświeża się 60 razy na sekundę. My dopisujemy tylko to, co ma być NASZE.
#
# arcade.Window nazywamy klasą BAZOWĄ (albo rodzicem/nadklasą),
# a MyGame — klasą POCHODNĄ (albo dzieckiem/podklasą).
# ----------------------------------------------------------------------------
class MyGame(arcade.Window):
"""Okno naszej gry."""
def __init__(self):
"""
KONSTRUKTOR metoda wołana automatycznie w momencie tworzenia
obiektu, czyli gdy niżej piszemy `MyGame()`.
`self` to sam tworzony obiekt. Każda metoda w klasie dostaje go jako
pierwszy argument dzięki temu wie, na czyich danych pracuje.
W wywołaniu `self` się NIE podaje: piszemy `okno.on_draw()`,
a Python sam podstawia `okno` pod `self`.
"""
# super() to "mój rodzic", czyli arcade.Window.
# Tu mówimy: "rodzicu, wykonaj swój konstruktor z takimi parametrami".
# Bez tej linii okno w ogóle by się nie utworzyło — to rodzic zna
# wszystkie szczegóły otwierania okna w systemie.
super().__init__(SZEROKOSC, WYSOKOSC, TYTUL)
# Atrybuty obiektu — zmienne, które "żyją" wewnątrz obiektu i są
# widoczne we WSZYSTKICH metodach tej klasy (przez self.).
# W kodzie proceduralnym trzymalibyśmy je w zmiennych globalnych.
self.background_color = arcade.color.DARK_BLUE
self.licznik_klatek = 0
def on_draw(self):
"""
NADPISANIE METODY: arcade.Window ma już metodę on_draw(), ale pustą.
Definiując u siebie, podmieniamy tamtą wersję na własną.
Tej metody NIGDY nie wołamy sami arcade woła za nas przy każdej
klatce (~60 razy na sekundę). To jest tzw. odwrócenie sterowania:
my nie piszemy pętli głównej, my tylko wypełniamy gotowe miejsca.
"""
# W arcade 3.x czyścimy ekran przez self.clear().
# (W starych tutorialach do 2.x było arcade.start_render() — to inna
# funkcja o zupełnie innym znaczeniu, nie używaj jej tutaj.)
self.clear()
arcade.draw_text(
"Cześć! To jest obiekt klasy MyGame.",
x=50,
y=WYSOKOSC / 2,
color=arcade.color.WHITE,
font_size=22,
)
arcade.draw_text(
f"Klatka nr {self.licznik_klatek}",
x=50,
y=WYSOKOSC / 2 - 40,
color=arcade.color.GOLD,
font_size=16,
)
# TODO 1: dorysuj koło na środku ekranu.
# arcade.draw_circle_filled(środek_x, środek_y, promień, kolor)
# np. arcade.draw_circle_filled(SZEROKOSC / 2, 120, 40, arcade.color.RED)
# TODO 2: dorysuj prostokąt (np. "podłogę" na dole ekranu).
# W arcade 3.x są dwie wygodne wersje:
# arcade.draw_lrbt_rectangle_filled(left, right, bottom, top, kolor)
# arcade.draw_lbwh_rectangle_filled(left, bottom, width, height, kolor)
# Wybierz jedną i narysuj pas o wysokości 40 pikseli przy dolnej krawędzi.
def on_update(self, delta_time: float):
"""
Druga metoda wołana automatycznie ~60 razy na sekundę tu zmieniamy
stan gry (a w on_draw tylko rysujemy to, co już wyliczone).
delta_time to czas w sekundach, jaki minął od poprzedniej klatki
(zwykle ok. 0.016 s). Przyda się w dniu 2, żeby ruch był równy
niezależnie od szybkości komputera.
"""
self.licznik_klatek += 1
def on_key_press(self, symbol: int, modifiers: int):
"""Kolejna nadpisana metoda — arcade woła ją po wciśnięciu klawisza."""
if symbol == arcade.key.ESCAPE:
self.close()
def main():
# TU powstaje obiekt: MyGame() uruchamia __init__ i zwraca gotowe okno.
# Zmienna `okno` to jedna konkretna INSTANCJA klasy MyGame.
okno = MyGame()
# arcade.run() startuje pętlę główną: w kółko woła on_update() i on_draw()
# naszego obiektu, aż okno zostanie zamknięte.
arcade.run()
if __name__ == "__main__":
main()