124 lines
4.8 KiB
Python
124 lines
4.8 KiB
Python
|
|
"""
|
||
|
|
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 ją u siebie, podmieniamy tamtą wersję na własną.
|
||
|
|
|
||
|
|
Tej metody NIGDY nie wołamy sami — arcade woła ją 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()
|