Menu

  • Home
  • Flask Tutorial
  • WebGL
  • Kontakt

Alicja | Theme by Theme in Progress | Proudly powered by WordPress

Alicja & IT
  • Home
  • Flask Tutorial
  • WebGL
  • Kontakt

Gra w Pythonie – PyGame – Przeszkody – #5

March 21, 2017PyGame Standard

W poprzednim odcinku nasz dinozaur już skakał, a jego tło poruszało się – dokładnie tak, jak w oryginale. Nadszedł czas na implementację najfajniejszej części tej minigry, czyli kaktusów :). Do dzieła!

Klasa “Kaktus”?

Zacznijmy od samych obrazków. Z właściwej aplikacji wyłapałam cztery rodzaje kaktusów:

 

 

 

Oczywiście w grze są one obracane (a czasem chyba też zmniejszane/zwiększane), ale póki co, możemy oprzeć naszych “przeciwników” na tych czterech obrazkach, bez dodatkowych utrudnień.

Kaktusy muszą respawnować się w losowych miejscach – często w grupach, nie większych niż cztery rośliny. Większej grupy oczywiście nie dałoby się przeskoczyć.

Napiszmy więc klasę kaktus, na podstawie której, wraz z przebiegiem gry, stworzymy poszczególne obiekty:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Cactus(pygame.sprite.Sprite):
    def __init__(self):
        pygame.sprite.Sprite.__init__(self)
        cactusImg = []
        cactusImg.append(pygame.image.load('kaktus1.png'))
        cactusImg.append(pygame.image.load('kaktus2.png'))
        cactusImg.append(pygame.image.load('kaktus3.png'))
        cactusImg.append(pygame.image.load('kaktus4.png'))
        rand = random.randint(0,3)
        self.image = cactusImg[rand]
        self.rect = self.image.get_rect()
        self.x = 800
        self.y = 200
        self.rect.move_ip(self.x, self.y)
        self.dx = -10
 
    def update(self):
        self.rect = self.rect.move(self.dx, 0)

Żeby uporządkować obrazy, które mamy do wyboru, zdecydowałam się na użycie tablicy z poszczególnymi ilustracjami. Możemy teraz wylosować numer od 0-3, aby pojawił się jeden z kaktusów.

To, czym wyróżnia się ta klasa od innych, które do tej pory stworzyliśmy, jest niepozorne parę słów w nawiasie tuż za nazwą klasy – pygame.sprite.Sprite. Oznaczają one, że instacje tej klasy będą tak zwanymi “sprajtami”, czyli ruchomymi elementami (postaciami) naszej gry. W przypadku sprite’ów ważne jest, żeby zdefiniować pole self.rect i pobrać kształt prostokąta z obrazka. Dzięki temu będziemy mogli później tworzyć kolizję oraz poruszać postaci. Jak widzisz, w kodzie pojawiają się również nowe funkcje – self.rect.move_ip i self.rect.move – pierwsza z nich przemieszcza sprite’a względem planszy, a druga względem jego własnej pozycji.

W metodzie update(), dokładnie tak jak w przypadku tła, definiujemy ruch sprite’a. Mimo że kod wygląda nieco inaczej, to działać będzie dokładnie tak samo.

Całość nie wygląda zbyt skomplikowanie – przejdźmy więc do samego respawnu i interakcji z naszym T-Rexem.

Respawn przeciwnika

Dzięki temu, że zdefiniowaliśmy kaktusy jako sprite’y, możemy utworzyć ich grupę. Dzięki temu respawny staną się bardzo proste.

Najpierw dodajmy trochę kodu do __init__ klasy Game():

1
2
3
4
5
6
7
8
9
10
class Game:
    def __init__(self):
        self._running = True
        self.dino = Dino()
        self.background = Background()
        self.counter = Counter()
        self.FPS = 60
        self.fpsClock = pygame.time.Clock()
        self.cactuses = pygame.sprite.Group()
        self.respawn = 100

Interesują nas szczególnie dwie ostatnie. W pierwszej tworzymy wspomnianą już grupę, którą upychamy w zmienną self.cactuses, a pod self.respawn podstawiamy 100 – po takim czasie pojawi się pierwszy kaktus. Później będziemy losować tę wartość.

Do pętli while dodajmy inne potrzebne skrypty:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
       while( self._running ):
    
            self.respawn -= 1
            if self.respawn == 0:
                self.cactuses.add(Cactus())
                self.respawn = random.randint(60, 200)
 
            for cactus in self.cactuses:
                is_collided = pygame.sprite.collide_rect(self.dino, cactus)
                if (is_collided):
                    print("KOLIZJA!!!")
                    self._running = False
 
            self.cactuses.update()
            self.cactuses.draw(self._display_surface)
            pygame.display.update()

Z każdym odświeżeniem ekranu self.respawn zmniejsza się o 1 – gdy dojdzie do 0, tworzymy nowego kaktusa (dodając go do grupy) i losując nową wartość respawnu. Liczby między 60 a 200 powodują rzadkie respawny, ale jak tylko dopracujemy kod, by wyświetlać przeszkody również grupami, powinno działać dobrze.

Kolejny blok kodu to wykrywanie kolizji. Dla każdego kaktusa – gdy zetknie się z naszym dinozaurem, is_collided dostaje wartość 1 i gra się zatrzymuje (printując kolizję). Wygląda prosto i tak też działa – opieramy się na kształcie rectangli wybudowanych wokół postaci.

Na koniec update’ujemy wszystkie kaktusy, aby przemieszczały się razem z tłem, i blitujemy je do powierzchni. Z racji, że stanowią grupę sprite’ów możemy skorzystać z metody draw(surface).

Spróbujmy uruchomić grę!

Pojawia się piękny error…

Jak już wspominałam, kolizje oparte są na kształcie rectangli zbudowanych wokół postaci. Zapomnieliśmy zdefiniować recta dla T-Rexa.

Dopracujmy dinozaura

1
2
3
4
5
6
7
8
9
10
class Dino():
    def __init__(self):
        self.x = 10
        self.y = 200
        self.dy = 0
        self.leg_flag = 0
        self.time = 0
        self.dino_Img = pygame.image.load('dino1a1.png')
        self.rect = self.dino_Img.get_rect()
        self.jumping = False

Interesuje nas przedostatni wers – identyczny, jak dla kaktusów.

Aby kolizje mogły działać, musimy jeszcze sprawić, że ruch dinozaura będzie identyczny na rectanglu, co na samym obrazku. Uda nam się to dzięki umieszczeniu kodu:

1
self.rect.topleft = self.x, self.y

na samym dole metody update(). Czas ponownie włączyć grę!

I w końcu jakoś to wygląda :) Jedyny błąd, jaki widać to położenie najmniejszego kaktusa – dodajmy warunek, który w przypadku wylosowania jego numeru, umiejscowi obrazek nieco niżej:

1
2
3
4
5
        if (rand == 2):
            self.y = 218
        else:
            self.y = 200
        self.rect.move_ip(self.x, self.y)

Teraz prezentuje się lepiej.

Grając w naszą wersję gry, możemy spowodować kolizję nawet skacząc w odpowiednim momencie. Dlaczego? Sprawdziłam wysokość skoku w obu wersjach apki, i jak można zauważyć na obrazku:

W oryginale (po lewej) skacze zdecydowanie wyżej. Dopracowanie tego zostawimy jednak na następny raz i wtedy też zajmiemy się grupowaniem kaktusów i ładnym ekranem GAME OVER. See you! :)

  • Gosia

    Czy powstanie kolejna część? :)

    • Alicja

      Cześć – póki co myślę, że niestety nie. Ale śmiało możesz dokończyć grę sama – chętnie zobaczę efekt!

PyGame:

  • Gra w Pythonie – PyGame – Hello World- #1
  • Gra w Pythonie – PyGame – Animacje – #2
  • Gra w Pythonie – PyGame – Poruszanie się postaci – #3
  • Gra w Pythonie – PyGame – Ruchome tło – #4
  • Gra w Pythonie – PyGame – Przeszkody – #5

Facebook

Kontakt

kontakt[at]alicja.it

Kategorie

  • Flask (12)
  • Luźne (2)
  • PyGame (5)
  • Relacje z wydarzeń (3)
  • WebGL (3)