""" 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 ją 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., ż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()