python-arcade-oo/dzien1/02_sprite_ruch.py

136 lines
4.8 KiB
Python
Raw Permalink Normal View History

"""
Dzień 1, krok 2 sprite i sterowanie z klawiatury.
Nowe pojęcia:
* sprite obiekt gry, który ma pozycję, wygląd i prędkość
* SpriteList pojemnik na sprite'y; rysuje i aktualizuje je wszystkie naraz
* change_x / change_y prędkość sprite'a (o ile pikseli przesuwa się w klatce)
Uruchom:
python dzien1/02_sprite_ruch.py
Sterowanie: strzałki. Wyjście: Esc.
"""
import arcade
SZEROKOSC = 800
WYSOKOSC = 600
TYTUL = "Dzień 1 — ruch sprite'a"
PROMIEN_GRACZA = 25
PREDKOSC_GRACZA = 5 # w pikselach na klatkę (arcade przelicza to przez delta_time)
class MyGame(arcade.Window):
"""Okno gry — znowu dziedziczymy po arcade.Window."""
def __init__(self):
super().__init__(SZEROKOSC, WYSOKOSC, TYTUL)
self.background_color = arcade.color.DARK_SLATE_GRAY
# Atrybuty deklarujemy w __init__, nawet jeśli na razie są puste.
# Dzięki temu z jednego miejsca widać, jakie dane ma obiekt.
self.player_list = arcade.SpriteList()
self.player = None
self.setup()
def setup(self):
"""
Metoda pomocnicza nie jest częścią arcade, sami wymyśliliśmy.
Ustawia grę w stan początkowy. Trzymamy to osobno od __init__, bo
później (np. po przegranej) będziemy chcieli zrestartować grę bez
tworzenia nowego okna wystarczy zawołać setup() jeszcze raz.
"""
self.player_list = arcade.SpriteList()
# SpriteCircle to gotowy sprite w kształcie koła — klasa z biblioteki.
# Tworzymy jej instancję: SpriteCircle(promień, kolor).
self.player = arcade.SpriteCircle(PROMIEN_GRACZA, arcade.color.AMAZON)
# center_x / center_y to atrybuty każdego sprite'a — jego pozycja.
self.player.center_x = SZEROKOSC / 2
self.player.center_y = WYSOKOSC / 2
# Wkładamy sprite'a do listy. Od teraz wystarczy operować na liście.
self.player_list.append(self.player)
def on_draw(self):
self.clear()
# SpriteList sam rysuje wszystkie swoje sprite'y — jedno wywołanie.
self.player_list.draw()
arcade.draw_text(
"Strzałki — ruch, Esc — wyjście",
x=10,
y=10,
color=arcade.color.WHITE,
font_size=14,
)
def on_update(self, delta_time: float):
"""
UWAGA na API arcade 3.x:
SpriteList NIE MA metody on_update(). Listę odświeżamy metodą
update(delta_time), a ona woła update() na każdym sprite'cie.
Domyślne Sprite.update() dodaje change_x/change_y do pozycji czyli
samo przesuwanie mamy za darmo. W dniu 2 nadpiszemy update() we
własnej klasie, żeby sprite robił coś więcej.
"""
self.player_list.update(delta_time)
# TODO 1: nie pozwól graczowi wyjechać poza okno.
# Każdy sprite ma atrybuty left, right, bottom, top (krawędzie).
# Przypisanie do nich przesuwa sprite'a, np.:
# if self.player.left < 0:
# self.player.left = 0
# Dopisz analogiczne warunki dla right (> SZEROKOSC),
# bottom (< 0) i top (> WYSOKOSC).
def on_key_press(self, symbol: int, modifiers: int):
"""
Wciśnięcie klawisza USTAWIA prędkość nie przesuwa gracza od razu.
Samo przesuwanie dzieje się w on_update, klatka po klatce.
Dzięki temu ruch jest płynny, a nie skokowy.
"""
if symbol == arcade.key.LEFT:
self.player.change_x = -PREDKOSC_GRACZA
elif symbol == arcade.key.RIGHT:
self.player.change_x = PREDKOSC_GRACZA
elif symbol == arcade.key.UP:
self.player.change_y = PREDKOSC_GRACZA
elif symbol == arcade.key.DOWN:
self.player.change_y = -PREDKOSC_GRACZA
elif symbol == arcade.key.ESCAPE:
self.close()
# TODO 2: dodaj obsługę klawisza SPACE (arcade.key.SPACE).
# Wymyśl efekt i zapisz go w atrybucie obiektu, np.:
# - zmiana koloru gracza: self.player.color = arcade.color.RED
# - "dopalacz": ustaw self.szybki = True i w on_key_press mnóż
# PREDKOSC_GRACZA razy 2 (pamiętaj o wyłączeniu w on_key_release)
# - teleport na środek ekranu
# Ważne: stan trzymamy w self.<coś>, żeby inne metody też go widziały.
def on_key_release(self, symbol: int, modifiers: int):
"""
Puszczenie klawisza ZERUJE prędkość w danej osi.
Bez tej metody gracz po jednym naciśnięciu jechałby w nieskończoność.
"""
if symbol in (arcade.key.LEFT, arcade.key.RIGHT):
self.player.change_x = 0
elif symbol in (arcade.key.UP, arcade.key.DOWN):
self.player.change_y = 0
def main():
MyGame()
arcade.run()
if __name__ == "__main__":
main()