W poprzedniej części, nauczyliśmy się tworzyć okno, obsługiwać pętle zdarzeń i wyświetlać obrazki na ekranie. W tej części nauczymy się tworzyć duszki i poruszać nimi.
Co to są duszki
Duszki (ang. sprites), to małe ruchome obrazki wyświetlane na ekranie. Są nimi np, postacie, potworki wszelkie ruchome elementy gry. Duszki mogą być statyczne, które nie zmieniają kształtu ani wyglądu i animowane. Najpierw zajmiemy się duszkami statycznymi.
Tworzymy duszka
Tworzymy więc jakiś obrazek, którym będziemy sterować w formacie PNG, oczywiście bez tła, albo pobierz gotowy, który przygotowałem.
Ładujemy naszego duszka do programu, będzie on dostępny przez self.player_image, oraz inicjujemy pozycje duszka na ekranie.
self.player_image = pygame.image.load('spaceship.png')
self.speed = 1.2 # szybkość poruszania duszka
self.player_x = 50 # pozycja x duszka na ekranie
self.player_y = 30 # pozycja y duszka na ekranie
Poruszanie duszkiem
Aby poruszać naszym duszkiem, musimy dodać obsługę klawiszy W, S, A, D. Dalej będzie odrobinę matematyki, ale jeśli ktoś poważnie myśli o tworzeniu gier, to bez matematyki się nie obejdzie. Spójrz na wykres:

Mamy na niej 2 osie, oś X i Y, które oznaczają kierunek poruszania się duszka, możemy odczytać z niego, że podstawiając do współrzędnych XY odpowiednie wartości, możemy poruszać duszkiem w dowolnym kierunku. Czyli:
w góre: X = 0 i Y = -1 w dół: X = 0 i Y = 1 w lewo X = -1 i Y = 0 w prawo X = 1 i Y = 0
Łatwo zauważyć, że odpowiednio łącząc wartości X i Y, można poza kierunkami góra, dół, prawo i lewo, dodać pośrednie, np jednocześnie w górę i prawo, będzie to X = -1 i Y = -1. Skoro wiemy już jak wygląda ustalanie kierunku poruszania, przejdźmy do kodu odczytu stanu klawiszy.
keys = pygame.key.get_pressed() # odczytujemy stan klawiszy
if keys[K_s]:
self.move(0,1) # ruch w dol
if keys[K_w]:
self.move(0,-1) # ruch w gore
if keys[K_d]:
self.move(1,0) # ruch w prawo
if keys[K_a]:
self.move(-1,0) # ruch w lewo
Jak widać, wywoływana jest metoda self.move(x,y), która odpowiednio przelicza parametry pozycji duszka.
Poniżej przedstawiam wzór na obliczenie współrzędnych duszka.
pos_x = pos_x + (dirx * speed)
pos_y = pos_y + (diry * speed)
Oznacza to tyle, ze do każdej pozycji X lub Y dodajemy odpowiednią wartość kierunku -1,0 lub 1 z naszej tabelki powyżej, gdzie po pomnożeniu przez współczynnik prędkości, ustalamy nowe współrzędne duszka.
def move(dirx,diry):
self.player_x = self.player_x + (dirx * self.speed)
self.player_y = self.player_y + (diry * self.speed)
Następnie wymazujemy zawartość ekranu (można samego duszka, ale dla uproszczenia czyścimy całość), i wyświetlamy duszka na nowych współrzędnych, co da nam wrażenie poruszania.
self.screen.fill((0,0,0)) # czyscimy ekran, mało wydajne ale wystarczy self.surface.blit(self.player_image,(self.player_x,self.player_y))
Mamy już wszystkie części programu, aby wyświetlić i poruszać naszym duszkiem. Cały program wygląda tak.
import pygame # importujemy biblioteki pygame
from pygame.locals import * # importujemy nazwy [QUIT, KEYDOWN,K_ESCAPE] itp.
from sys import exit # importujemy funkcje systemowa exit
screen_size = (800,600) # ustalamy rozmiar ekranu
class IsoGame(object):
def __init__(self):
pygame.init() # incjalizujemy biblioteke pygame
flag = DOUBLEBUF # wlaczamy tryb podwojnego buforowania
# tworzymy bufor na grafike
self.surface = pygame.display.set_mode(screen_size,flag)
# zmienna stanu gry
self.gamestate = 1 # 1 - run, 0 - exit
self.player_image = pygame.image.load('spaceship.png')
self.speed = 1.2 # szybkosc poruszania duszka
self.player_x = 50 # pozycja x duszka na ekranie
self.player_y = 30 # pozycja y duszka na ekranie
self.tree_image = pygame.image.load('tree.png') # ladujemy obrazek do pamieci
self.loop() # glowna petla gry
def move(self,dirx,diry):
""" poruszanie duszkiem """
self.player_x = self.player_x + (dirx * self.speed)
self.player_y = self.player_y + (diry * self.speed)
def game_exit(self):
""" funkcja przerywa dzialanie gry i wychodzi do systemu"""
exit()
def loop(self):
""" glowna petla gry """
while self.gamestate==1:
for event in pygame.event.get():
if event.type==QUIT or (event.type==KEYDOWN and event.key==K_ESCAPE):
self.gamestate=0
keys = pygame.key.get_pressed() # odczytujemy stan klawiszy
if keys[K_s]:
self.move(0,1) # ruch w dol
if keys[K_w]:
self.move(0,-1) # ruch w gore
if keys[K_d]:
self.move(1,0) # ruch w prawo
if keys[K_a]:
self.move(-1,0) # ruch w lewo
self.surface.fill((0,0,0)) # czyscimy ekran, malo wydajne ale wystarczy
self.surface.blit(self.tree_image, (10,20)) # gracz zaslania obrazek
# umieszczamy gracza
self.surface.blit(self.player_image,(self.player_x,self.player_y))
self.surface.blit(self.tree_image, (220,20)) # obrazek zaslania gracza
pygame.display.flip() # przenosimy bufor na ekran
self.game_exit()
if __name__ == '__main__':
IsoGame()
Wyjaśnienia wymagają linie 57 i 62. Linia 57 wyświetla drzewo, wcześniej niż gracza, dzięki czemu, nasz statek kosmiczny zasłania je. Natomiast linia 62, wyświetla inne drzewo, po wyświetleniu gracza, dzięki czemu drzewo zasłania nasz statek. Wniosek płynie z tego jeden. Wszystkie grafiki, które gracz ma przesłaniać, wyświetlamy zanim umieścimy gracza na ekranie, a wszystkie grafiki, które mają zasłaniać gracza, wrzucamy na ekran, po narysowaniu gracza.
Po uruchomieniu programu, zobaczymy taki ekran.

Klawiszami W, S, A, D poruszamy statkiem. Klawisz [ESC] zamyka okno.
Pobierz plik isogame_tut2.zip
Animacja
Pora na animowane duszki. Animacja to nic innego, jak wyświetlanie różnych klatek, tego samego obiektu, w różnych pozach, różnym kształcie, czy jak w naszym przykładzie, przy poruszaniu, będzie wyświetlana klatka, która będzie sugerowała włączone silniki naszego pojazdu. Klatki animacji mogą znajdować się w osobnych plikach, lub wszystkie w jednym. My zastosujemy drugi sposób, ponieważ jest to znacznie wygodniejsze. Mamy więc taki obrazek

Witać, że nasza animacja składać się będzie z 3 klatek. Pierwsza klatka, będzie wyświetlana zawsze, gdy duszkiem nie poruszamy. Gdy zaczniemy nim poruszać, na zmianę będą wyświetlane klatki nr 2 i 3.
Zmodyfikujemy nasz kod ładujący, aby wycinał klatki. Każda klatka musi mieć identyczny rozmiar, w naszym przypadku jest to 127x49px, jeśli pominiemy ramkę, będzie to 125x47px. Ramka jest tak naprawdę niepotrzebna, ale znacznie ułatwia pozycjonowanie każdej klatki w programie graficznym. Kod ładujący, będzie wyglądał teraz tak:
images = pygame.image.load('spaceship2.png') # wczytujemy grafike
frame_rect = pygame.Rect(1,0,125,47) # ustalamy wielkosc ramki
self.player_image = [None] * 3 # tworzymy pusta liste, do przechowywania klatek
self.player_frame = 0 # numer aktualnie wyswietlanej klatki
# w petli wycinamy kazda ramke i umieszczamy w tablicy,
# dzieki temu ze maja taki sam rozmiar jest to bardzo proste
for im in range(0,3):
frame_rect.top = im*48+1 # ustawiamy obszar wycinania klatki +1px ramki
self.player.image[im] = images.subsurface(frame_rect) # wycinamy
Komentarze w kodzie wszystko wyjaśniają. Linia 8, przesuwa wycinany obszar o wysokość klatki,
czyli mamy kolejno (1,0,124,47), (49,0,124,47), (98,0,124,47). Dwa pierwsze parametry określają początek klatki [left,top], dwa ostatnie odpowiednio szerokość i wysokość klatki, a ponieważ ona się nie zmienia, to zostawiamy te wartości bez zmian.
Teraz modyfikujemy główną pętle gry. Dodajemy
player_anim = 0 # wylaczamy animacje
if keys[K_s]:
self.move(0,1) # ruch w dol
player_anim = 1
if keys[K_w]:
self.move(0,-1) # ruch w gore
player_anim = 1
if keys[K_d]:
self.move(1,0) # ruch w prawo
player_anim = 1
if keys[K_a]:
self.move(-1,0) # ruch w lewo
player_anim = 1
if player_anim == 1:
self.player_frame+=1 # ustawiamy kolejna klatke
# gdy aktualna klatka wieksza niz 2, to animujemy od nowa
if self.player_frame > 2:
self.player_frame = 1
else:
self.player_frame = 0 # gdy gracz sie nie porusza, wylaczamy silniki
Na koniec modyfikujemy kod, odpowiedzialny za wyświetlenie gracza
self.surface.blit(self.player_image[self.player_frame],(self.player_x,self.player_y))
Zmienna player_anim, to flaga, która informuje, czy gracz się porusza. Potrzebujemy jej, aby przestawiać animacje. Zachęcam do eksperymentów, np. zmianą prędkością poruszania duszka. Nie będę umieszczał, po raz kolejny kodu w całości na stronie, cały kod z obrazkami, możesz pobrać, jako paczkę.
Pobierz plik isogame_tut2a.zip
I jak zwykle zrzut ekranu, jak to wygląda

W następnej lekcji ciąg dalszy duszków, oraz porozmawiamy sobie o kolizjach.