4.1. Pong (str)
Wersja strukturalna klasycznej gry w odbijanie piłeczki zrealizowana z użyciem biblioteki PyGame.

4.1.1. Pole gry
Tworzymy plik pong_str.py
w terminalu lub w wybranym edytorze, zapisujemy na dysku
i wprowadzamy poniższy kod:
1#! /usr/bin/env python2
2# -*- coding: utf-8 -*-
3
4import pygame
5import sys
6from pygame.locals import *
7
8# inicjacja modułu pygame
9pygame.init()
10
11# szerokość i wysokość okna gry
12OKNOGRY_SZER = 800
13OKNOGRY_WYS = 400
14# kolor okna gry, składowe RGB zapisane w tupli
15LT_BLUE = (230, 255, 255)
16
17# powierzchnia do rysowania, czyli inicjacja pola gry
18oknogry = pygame.display.set_mode((OKNOGRY_SZER, OKNOGRY_WYS), 0, 32)
19# tytuł okna gry
20pygame.display.set_caption('Prosty Pong')
21
22# pętla główna programu
23while True:
24 # obsługa zdarzeń generowanych przez gracza
25 for event in pygame.event.get():
26 # przechwyć zamknięcie okna
27 if event.type == QUIT:
28 pygame.quit()
29 sys.exit()
30
31 # rysowanie obiektów
32 oknogry.fill(LT_BLUE) # kolor okna gry
33
34 # zaktualizuj okno i wyświetl
35 pygame.display.update()
36
37# KONIEC
Na początku importujemy wymagane biblioteki i inicjujemy moduł pygame
.
Dużymi literami zapisujemy nazwy zmiennych określające właściwości pola gry,
które inicjalizujemy w instrukcji pygame.display.set_mode()
.
Tworzy ona powierzchnię o wymiarach 800x400 pikseli i 32 bitowej głębi kolorów,
na której umieszczać będziemy pozostałe obiekty. W kolejnej instrukcji ustawiamy tytuł okna gry.
Programy interaktywne, w tym gry, reagujące na działania użytkownika, takie jak ruchy czy kliknięcia myszą, działają w tzw. głównej pętli, której zadaniem jest:
przechwycenie i obsługa działań użytkownika, czyli tzw. zdarzeń (ruchy, kliknięcia myszą, naciśnięcie klawiszy),
aktualizacja stanu gry (np. obliczanie przesunięć elementów) i rysowanie go.
Zadanie z punktu a) realizuje pętla for
, która odczytuje kolejne zdarzenia
zwracane przez metodę pygame.event.get()
. Za pomocą instrukcji warunkowych
możemy przechwytywać zdarzenia, które chcemy obsłużyć, np. naciśnięcie przycisku
zamknięcia okna: if event.type == QUIT
.
Instrukcja oknogry.fill(BLUE)
wypełnia okno zdefiniowanym kolorem.
Jego wyświetlenie następuje w poleceniu pygame.display.update()
.
Uruchom aplikację, wydając w terminalu polecenie:
~$ python pong_str.py
4.1.2. Paletka gracza
Planszę gry już mamy, pora umieścić na niej paletkę gracza. Poniższy kod wstawiamy przed pętlą główną programu:
22# paletka gracza #########################################################
23PALETKA_SZER = 100 # szerokość
24PALETKA_WYS = 20 # wysokość
25BLUE = (0, 0, 255) # kolor wypełnienia
26PALETKA_1_POZ = (350, 360) # początkowa pozycja zapisana w tupli
27# utworzenie powierzchni paletki, wypełnienie jej kolorem,
28paletka1 = pygame.Surface([PALETKA_SZER, PALETKA_WYS])
29paletka1.fill(BLUE)
30# ustawienie prostokąta zawierającego paletkę w początkowej pozycji
31paletka1_prost = paletka1.get_rect()
32paletka1_prost.x = PALETKA_1_POZ[0]
33paletka1_prost.y = PALETKA_1_POZ[1]
Elementy graficzne tworzymy za pomocą polecenia
pygame.Surface((szerokosc, wysokosc), flagi, głębia)
.
Utworzony obiekt możemy wypełnić kolorem: .fill(kolor)
.
Położenie obiektu określimy pobierając na początku prostokątny obszar (Rect),
który go reprezentuje, metodą get_rect()
. Następnie podajemy współrzędne
x
i y
wyznaczające położenie w poziomie i pionie.
Informacja
Początek układu współrzędnych w Pygame to lewy górny róg okna głównego.
Położenie obiektu można ustawić również podając nazwane argumenty:
obiekt_prost = obiekt.get_rect(x = 350, y =350)
.Położenie obiektów klasy
Rect
(prostokątów) możemy odczytwyać wykorzystując właściwości, takie jak:.x, .y, .centerx, .right, .left, .top, .bottom
.
Omówiony kod utworzy obiekt reprezentujący paletkę gracza, ale trzeba ją jeszcze
umieścić na planszy gry. W tym celu użyjemy metody .blit()
, która służy
rysowaniu jednego obrazka na drugim. Poniższy kod musimy wstawić w pętli głównej
przed instrukcją wyświetlającą okno.
47 # narysuj w oknie gry paletki
48 oknogry.blit(paletka1, paletka1_prost)
Pozostaje uruchomienie kodu.
4.1.3. Ruch paletki
W pętli przechwytującej zdarzenia dopisujemy zaznaczony poniżej kod:
35# pętla główna programu
36while True:
37 # obsługa zdarzeń generowanych przez gracza
38 for event in pygame.event.get():
39 # przechwyć zamknięcie okna
40 if event.type == QUIT:
41 pygame.quit()
42 sys.exit()
43
44 # przechwyć ruch myszy
45 if event.type == MOUSEMOTION:
46 myszaX, myszaY = event.pos # współrzędne x, y kursora myszy
47
48 # oblicz przesunięcie paletki gracza
49 przesuniecie = myszaX - (PALETKA_SZER / 2)
50
51 # jeżeli wykraczamy poza okno gry w prawo
52 if przesuniecie > OKNOGRY_SZER - PALETKA_SZER:
53 przesuniecie = OKNOGRY_SZER - PALETKA_SZER
54 # jeżeli wykraczamy poza okno gry w lewo
55 if przesuniecie < 0:
56 przesuniecie = 0
57 # zaktualizuj położenie paletki w poziomie
58 paletka1_prost.x = przesuniecie
59
60 # rysowanie obiektów
61 oknogry.fill(LT_BLUE) # kolor okna gry
62
63 # narysuj w oknie gry paletki
64 oknogry.blit(paletka1, paletka1_prost)
65
66 # zaktualizuj okno i wyświetl
67 pygame.display.update()
Chcemy sterować paletką za pomocą myszy. Zadaniem powyższego kodu jest
przechwycenie jej ruchu (MOUSEMOTION
), odczytanie współrzędnych kursora
z tupli event.pos
i obliczenie przesunięcia określającego nowe położenie paletki.
Kolejne instrukcje warunkowe korygują nową pozycję paletki, jeśli wykraczamy
poza granice pola gry.
Przetestuj kod.
4.1.4. Piłka w grze
Piłkę tworzymy podobnie jak paletkę. Przed pętlą główną programu wstawiamy poniższy kod:
35# piłka #################################################################
36P_SZER = 20 # szerokość
37P_WYS = 20 # wysokość
38P_PREDKOSC_X = 6 # prędkość pozioma x
39P_PREDKOSC_Y = 6 # prędkość pionowa y
40GREEN = (0, 255, 0) # kolor piłki
41# utworzenie powierzchni piłki, narysowanie piłki i wypełnienie kolorem
42pilka = pygame.Surface([P_SZER, P_WYS], pygame.SRCALPHA, 32).convert_alpha()
43pygame.draw.ellipse(pilka, GREEN, [0, 0, P_SZER, P_WYS])
44# ustawienie prostokąta zawierającego piłkę w początkowej pozycji
45pilka_prost = pilka.get_rect()
46pilka_prost.x = OKNOGRY_SZER / 2
47pilka_prost.y = OKNOGRY_WYS / 2
48
49# ustawienia animacji ###################################################
50FPS = 30 # liczba klatek na sekundę
51fpsClock = pygame.time.Clock() # zegar śledzący czas
Przy tworzeniu powierzchni dla piłki używamy flagi SRCALPHA
, co oznacza,
że obiekt graficzny będzie zawierał przezroczyste piksele. Samą piłkę rysujemy
za pomocą instrukcji pygame.draw.ellipse(powierzchnia, kolor, prostokąt)
.
Ostatni argument to lista zawierająca współrzędne lewego górnego i prawego dolnego
rogu prostokąta, w który wpisujemy piłkę.
Ruch piłki, aby był płynny, wymaga użycia animacji. Ustawiamy więc liczbę
generowanych klatek na sekundę (FPS = 30
) i przygotowujemy obiekt zegara,
który będzie kontrolował czas.
Teraz pod pętlą (nie w pętli!) for
, która przechwytuje zdarzenia, umieszczamy kod:
78 # ruch piłki ########################################################
79 # przesuń piłkę po obsłużeniu zdarzeń
80 pilka_prost.move_ip(P_PREDKOSC_X, P_PREDKOSC_Y)
81
82 # jeżeli piłka wykracza poza pole gry
83 # z lewej/prawej – odwracamy kierunek ruchu poziomego piłki
84 if pilka_prost.right >= OKNOGRY_SZER:
85 P_PREDKOSC_X *= -1
86 if pilka_prost.left <= 0:
87 P_PREDKOSC_X *= -1
88
89 if pilka_prost.top <= 0: # piłka uciekła górą
90 P_PREDKOSC_Y *= -1 # odwracamy kierunek ruchu pionowego piłki
91
92 if pilka_prost.bottom >= OKNOGRY_WYS: # piłka uciekła dołem
93 pilka_prost.x = OKNOGRY_SZER / 2 # więc startuję ze środka
94 pilka_prost.y = OKNOGRY_WYS / 2
95
96 # jeżeli piłka dotknie paletki gracza, skieruj ją w przeciwną stronę
97 if pilka_prost.colliderect(paletka1_prost):
98 P_PREDKOSC_Y *= -1
99 # zapobiegaj przysłanianiu paletki przez piłkę
100 pilka_prost.bottom = paletka1_prost.top
Na uwagę zasługuje metoda .move_ip(offset, offset)
, która przesuwa prostokąt
zawierający piłkę o podane jako offset
wartości. Dalej decydujemy, co ma się dziać,
kiedy piłka wyjdzie poza pole gry. Metoda .colliderect(prostokąt)
pozwala sprawdzić,
czy dwa obiekty nachodzą na siebie. Dzięki temu możemy odwrócić bieg piłeczki
po jej zetknięciu się z paletką gracza.
Piłkę trzeba umieścić na polu gry. Podaną niżej instrukcję umieszczamy poniżej polecenia rysującego paletkę gracza:
108 # narysuj w oknie piłkę
109 oknogry.blit(pilka, pilka_prost)
Na koniec ograniczamy prędkość animacji wywołując metodę .tick(fps)
,
która wstrzymuje wykonywanie programu na podaną jako argument liczbę klatek na sekundę.
Podany niżej kod trzeba dopisać na końcu w pętli głównej:
114 # zaktualizuj zegar po narysowaniu obiektów
115 fpsClock.tick(FPS)
Teraz możesz już zagrać sam ze sobą! Przetestuj działanie programu.
4.1.5. AI – przeciwnik
Dodamy do gry przeciwnika AI (ang. artificial inteligence), czyli paletkę sterowaną programowo.
Przed główną pętlą programu dopisujemy kod tworzący paletkę AI:
53# paletka ai ############################################################
54RED = (255, 0, 0)
55PALETKA_AI_POZ = (350, 20) # początkowa pozycja zapisana w tupli
56# utworzenie powierzchni paletki, wypełnienie jej kolorem,
57paletkaAI = pygame.Surface([PALETKA_SZER, PALETKA_WYS])
58paletkaAI.fill(RED)
59# ustawienie prostokąta zawierającego paletkę w początkowej pozycji
60paletkaAI_prost = paletkaAI.get_rect()
61paletkaAI_prost.x = PALETKA_AI_POZ[0]
62paletkaAI_prost.y = PALETKA_AI_POZ[1]
63# szybkość paletki AI
64PREDKOSC_AI = 5
Tu nie ma nic nowego, więc od razu przed instrukcją wykrywającą kolizję piłki
z paletką gracza (if pilka_prost.colliderect(paletka1_prost)
)
dopisujemy kod sterujący ruchem paletki AI:
111 # AI (jak gra komputer) #############################################
112 # jeżeli piłka ucieka na prawo, przesuń za nią paletkę
113 if pilka_prost.centerx > paletkaAI_prost.centerx:
114 paletkaAI_prost.x += PREDKOSC_AI
115 # w przeciwnym wypadku przesuń w lewo
116 elif pilka_prost.centerx < paletkaAI_prost.centerx:
117 paletkaAI_prost.x -= PREDKOSC_AI
118
119 # jeżeli piłka dotknie paletki AI, skieruj ją w przeciwną stronę
120 if pilka_prost.colliderect(paletkaAI_prost):
121 P_PREDKOSC_Y *= -1
122 # uwzględnij nachodzenie paletki na piłkę (przysłonięcie)
123 pilka_prost.top = paletkaAI_prost.bottom
Samą paletkę AI trzeba umieścić na planszy, po instrukcji rysującej paletkę gracza dopisujemy więc:
134 # narysuj w oknie gry paletki
135 oknogry.blit(paletka1, paletka1_prost)
136 oknogry.blit(paletkaAI, paletkaAI_prost)
Pozostaje zmienić kod odpowiedzialny za odbijanie piłki od górnej krawędzi
planszy (if pilka_prost.top <= 0
), żeby przeciwnik AI mógł przegrywać.
W tym celu dokonujemy zmian wg poniższego kodu:
102 if pilka_prost.top <= 0: # piłka uciekła górą
103 # P_PREDKOSC_Y *= -1 # odwracamy kierunek ruchu pionowego piłki
104 pilka_prost.x = OKNOGRY_SZER / 2 # więc startuję ze środka
105 pilka_prost.y = OKNOGRY_WYS / 2
Teraz można już zagrać z komputerem :-).
4.1.6. Liczymy punkty
Co to za gra, w której nie wiadomo, kto wygrywa… Dodamy kod zliczający i wyświetlający punkty. Przed główną pętlą programu wstawiamy poniższy kod:
66# komunikaty tekstowe ###################################################
67# zmienne przechowujące punkty i funkcje wyświetlające punkty
68PKT_1 = '0'
69PKT_AI = '0'
70fontObj = pygame.font.Font('freesansbold.ttf', 64) # czcionka komunikatów
71
72
73def drukuj_punkty1():
74 tekst1 = fontObj.render(PKT_1, True, (0, 0, 0))
75 tekst_prost1 = tekst1.get_rect()
76 tekst_prost1.center = (OKNOGRY_SZER / 2, OKNOGRY_WYS * 0.75)
77 oknogry.blit(tekst1, tekst_prost1)
78
79
80def drukuj_punktyAI():
81 tekstAI = fontObj.render(PKT_AI, True, (0, 0, 0))
82 tekst_prostAI = tekstAI.get_rect()
83 tekst_prostAI.center = (OKNOGRY_SZER / 2, OKNOGRY_WYS / 4)
84 oknogry.blit(tekstAI, tekst_prostAI)
Po zdefiniowaniu zmiennych przechowujących punkty graczy, tworzymy obiekt czcionki
z podanego pliku (pygame.font.Font()
). Następnie definiujemy funkcje,
których zadaniem jest rysowanie punktacji graczy. Na początku tworzą one nowe obrazki
z punktacją gracza (.render()
), pobierają ich prostokąty (.get_rect()
),
pozycjonują je (.center()
) i rysują na głównej powierzchni gry (.blit()
).
Informacja
Plik wykorzystywany do wyświetlania tekstu (freesansbold.ttf
)
musi znaleźć się w katalogu ze skryptem.
W pętli głównej programu musimy umieścić wyrażenia zliczające punkty. Jeżeli piłka ucieknie górą, punkty dostaje gracz, w przeciwnym wypadku AI. Dopisz podświetlone instrukcje:
122 if pilka_prost.top <= 0: # piłka uciekła górą
123 # P_PREDKOSC_Y *= -1 # odwracamy kierunek ruchu pionowego piłki
124 pilka_prost.x = OKNOGRY_SZER / 2 # więc startuję ze środka
125 pilka_prost.y = OKNOGRY_WYS / 2
126 PKT_1 = str(int(PKT_1) + 1)
127
128 if pilka_prost.bottom >= OKNOGRY_WYS: # piłka uciekła dołem
129 pilka_prost.x = OKNOGRY_SZER / 2 # więc startuję ze środka
130 pilka_prost.y = OKNOGRY_WYS / 2
131 PKT_AI = str(int(PKT_AI) + 1)
Obie funkcje wyświetlające punkty również trzeba wywołać z pętli głównej,
a więc po instrukcji wypełniającej okno gry kolorem (oknogry.fill(LT_BLUE)
)
dopisujemy:
153 # rysowanie obiektów ################################################
154 oknogry.fill(LT_BLUE) # wypełnienie okna gry kolorem
155
156 drukuj_punkty1() # wyświetl punkty gracza
157 drukuj_punktyAI() # wyświetl punkty AI
4.1.7. Sterowanie klawiszami
Skoro możemy przechwytywać ruch myszy, nic nie stoi na przeszkodzie,
aby umożliwić poruszanie paletką za pomocą klawiszy.
W pętli for
odczytującej zdarzenia dopisujemy:
114 # przechwyć naciśnięcia klawiszy kursora
115 if event.type == pygame.KEYDOWN:
116 if event.key == pygame.K_LEFT:
117 paletka1_prost.x -= 5
118 if paletka1_prost.x < 0:
119 paletka1_prost.x = 0
120 if event.key == pygame.K_RIGHT:
121 paletka1_prost.x += 5
122 if paletka1_prost.x > OKNOGRY_SZER - PALETKA_SZER:
123 paletka1_prost.x = OKNOGRY_SZER - PALETKA_SZER
Naciśnięcie klawisza generuje zdarzenie pygame.KEYDOWN
.
Dalej w instrukcji warunkowej sprawdzamy, czy naciśnięto klawisz kursora
lewy lub prawy i przesuwamy paletkę o 5 pikseli.
Wskazówka
Kody klawiszy możemy sprawdzić w dokumentacji Pygame.
Uruchom program i sprawdź, jak działa. Szybko zauważysz, że wciśnięcie strzałki porusza paletką, ale żeby poruszyła się znowu, trzeba naciskanie powtarzać. To niewygodne, paletka powinna ruszać się dopóki klawisz jest wciśnięty. Przed pętlą główną dodamy więc poniższy kod:
86# powtarzalność klawiszy (delay, interval)
87pygame.key.set_repeat(50, 25)
Dzięki tej instrukcji włączyliśmy powtarzalność wciśnięć klawiszy. Przetestuj, czy działa.
4.1.8. Zadania dodatkowe
Zmodyfikuj właściwości obiektów (paletek, piłki) takie jak rozmiar, kolor, początkowa pozycja.
Zmień położenie paletek tak, aby znalazły się przy lewej i prawej krawędzi okna, wprowadź potrzebne zmiany w kodzie, aby poruszały się w pionie.
Dodaj trzecią paletkę, która co jakiś czas będzie „przelatywać” przez środek planszy i zmieniać w przypadku kolizji tor i kolor piłki.
4.1.9. Materiały
Źródła:
Materiały Python 101
udostępniane przez
Centrum Edukacji Obywatelskiej na licencji
Creative Commons Uznanie autorstwa-Na tych samych warunkach 4.0 Międzynarodowa.
- Utworzony:
2025-04-12 o 10:21 w Sphinx 7.3.7
- Autorzy: