Discount week - September
Pouze tento týden sleva až 80 % na e-learning týkající se Swift
30 % bodů zdarma na online výuku díky naší Slevové akci!

Lekce 4 - Pygame - Pong - Prostředí a herní objekty

Posledně, v lekci Pygame - Pong - Příprava, jsme si zjistili, které znalosti potřebujeme k úspěšnému vytvoření naší první hry Pong v pygame. Teď nám tedy již nic nebrání se do ní rovnou pustit! Hra bude vypadat takto:

PyONG – Hra Pong v pygame a Pythonu

Definice prostředí

Podobně jako v našich předchozích kódech, i nyní musíme vytvořit pevný základ naší hry.

Příprava pygame

Řekněme, že hru budeme připravovat na rozlišení 1920x1080, ale bude spustitelná s rozlišením libovolným. Proto si vytvoříme oddělené proměnné display a screen. Zároveň by se nám asi líbilo, aby okno mělo nějaký titulek, který by reprezentoval naši hru. K tomu slouží pro nás nová metoda pygame.display.set_caption(name), která nastaví titulek okna na hodnotu name.

Poslední věc, která by se nám mohla hodit, je proměnná round_tick. Tu si vytvoříme a budeme ji inkrementovat každým krokem během kola, bude nám fungovat jako časovač. Toho využijeme například, když budeme chtít zrychlit míč každých pár sekund.

Třída Game

Naše hry by měly mít objektovou architekturu a ideálně by všechny objekty ve hře měly být instance samostatných tříd. Pygame nám k tomu i nabízí několik tříd, ze kterých můžeme své objekty oddědit.

Jelikož je to naše první pygame hra, strukturu souboru si trochu zjednodušíme, nicméně se bude stále jednat o objekt. Celou hru implementujeme jako třídu Game, ve které budeme nastavovat všechny její atributy. To hlavně abychom se vyhnuli zbytečnému předávání proměnných funkcím hry přes parametry nebo dokonce přes nebezpečné globální proměnné. Takto budou ze všech metod třídy dostupné. Třída Game bude nyní vypadat takto:

import pygame

class Game:
     def __init__(self):
        pygame.init()
        self.running = True
        self.display: pygame.Surface = pygame.display.set_mode((1366, 768))
        pygame.display.set_caption("PyONG")
        self.screen = pygame.Surface((1920, 1080))
        self.round_tick = 0
        self.clock = pygame.time.Clock()
        self.FPS = 30  # maximální počet FPS

Příprava písem

Tento výukový obsah pomáhají rozvíjet následující firmy, které dost možná hledají právě tebe!

Vždy je dobrý nápad nemíchat mnoho druhů písem v jedné aplikaci. Proto si vybereme jedno písmo, které budeme používat. Jelikož budeme kreslit skóre, u kterého je žádoucí, aby pozice jednotlivých znaků zůstala vždy stejná, mohli bychom dojít k tom, že se nám nejvíce hodí písmo s pevnou šířkou znaků (monospace).

Pokud bychom ale byli nerozhodní, které z těch všech nainstalovaných písem si máme vybrat, mohli bychom za nás nechat vybrat takové písmo náš program podle toho, zda název písma obsahuje text 'mono':

from random import choice
    # ...
    def __init__(self):
        # ...
        font_name = choice([x for x in pygame.font.get_fonts() if 'mono' in x.lower()])

Známe-li přímo jméno písma, které chceme použít, upravíme tento kód podobně, jako jsme si ukázali v minulé lekci.

Pak nám již zbývá pouze vytvořit jednotlivá písma. Budeme určitě potřebovat jedno menší, na stálé zobrazování skóre a druhé větší, na vypisování výzev a informací:

# ...
self.font_score = pygame.font.SysFont(font_name, 30)
self.font_info = pygame.font.SysFont(font_name, 50)

Příprava herních objektů

Základní pygame prostředí máme nachystané, přejděme k herním objektům.

Hráči

V naší hře budou dva hráči. První hráč bude vlevo a druhý vpravo. Oba se budou moci pohybovat nějakou rychlostí. Zároveň, jelikož jsou oba hráči obdélníky, byla by škoda je rovnou jako pygame obdélníky nevytvořit, když k tomu máme připravenou třídu. Každý hráč také bude mít skóre a u hráče číslo 2 budeme chtít vědět, zda-li místo něj hraje počítač:

# ...
player_size = (50, 200)
self.player_speed = 10

# umisti hrace 1 ze zacatku vlevo doprostred
self.player1_orig = pygame.Rect((0, self.screen.get_height() // 2), player_size)
# a vytvor jeho kopii, abychom pri kazdem kole se mohli jednoduse vratit k puvodni pozici
self.player1 = self.player1_orig.copy()
self.player1_score = 0

# hrace cislo 2 umisti vpravo doprostred
self.player2_orig = pygame.Rect((self.screen.get_width() - player_size[0], self.screen.get_height() // 2), player_size)
self.player2 = self.player2_orig.copy()
self.player2_score = 0
self.player2_ai = False  # True pokud misto hrace c. 2 hraje pocitac

Míč

Podobně jako hráče si vytvoříme také míč. Ten se ale, na rozdíl od hráčů, kde směr pohybu určuje vstup od uživatele, může pohybovat libovolným směrem. Budeme si tedy muset uložit jeho současný směr. Míč se také postupem času může zrychlovat až do určité maximální rychlosti:

ball_size = (20, 20)
# umísti mic doprostred herni plochy
self.ball_orig = pygame.Rect((self.screen.get_width() // 2, self.screen.get_height() // 2), ball_size)
self.ball = self.ball_orig.copy()
self.ball_direction = 0  # nastavi se na zacatku kazdeho kola, hodnoty <0; 360)
self.ball_speed_orig = 15
self.ball_speed_max = self.ball_speed_orig * 4
self.ball_speed = self.ball_speed_orig

Abychom si usnadnili výpočty a zaručili, že míč nebude mít nikdy hodnotu směru mimo rozsah, napíšeme si rovnou metodu, pomocí které budeme jeho směr nastavovat:

def set_ball_direction(self, val: int):
    if abs(val) >= 360:
        # zmensi mozny rozsah hodnot na (-360; 360) pomoci zjisteni zbytku po deleni
        val %= 360
    if val < 0:
        # prevede zapornou velikost uhlu na jeji kladnou reprezentaci v kruznici
        val = 360 + val
    self.ball_direction = val

Hranice obrazovky

Poslední objekty, které budeme vytvářet, sice nebudou viditelné, ale přesto jsou vysoce důležité. Jedná se o hranice obrazovky, které si vytvoříme jako pygame obdélníky. Díky tomu pak nebudeme muset porovnávat souřadnice každého dalšího objektu, jestli náhodou neopustil obrazovku, ale místo toho nám bude stačit porovnat kolizi dvou obdélníků. Tyto obdélníky budou vždy pokrývat celou jednu hranu herní plochy, to nás asi nepřekvapí. Co by nás ale mohlo překvapit, je jejich tloušťka. Ta musí být minimálně tak velká jako maximální rychlost míče, jinak by se totiž mohlo stát, že by míč při vyšších rychlostech naše okraje prostě přeskočil. Tento jejich přesah promítneme za hranice viditelné části herní plochy:

def __init__(self):
# ...
    self.top = pygame.Rect((0, -self.ball_speed_max), (self.screen.get_width(), self.ball_speed_max))
    self.bottom = pygame.Rect((0, self.screen.get_height()), (self.screen.get_width(), self.ball_speed_max))
    self.left = pygame.Rect((-self.ball_speed_max, 0), (self.ball_speed_max, self.screen.get_height()))
    self.right = pygame.Rect((self.screen.get_width(), 0), (self.ball_speed_max, self.screen.get_height()))

A máme hotovo! Tedy alespoň máme hotovy naše objekty.

Herní cyklus

Pokračovat budeme tím, že si vytvoříme klasický herní cyklus, který jsme v předchozích lekcích dělali již několikrát:

# ...
def main(self):
    while self.running:
        # UDALOSTI
        for event in pygame.event.get():
            if event.type == pygame.QUIT or (event.type == pygame.KEYUP and event.key == pygame.K_q):
                self.running = False
        # KRESLENI
        pygame.transform.scale(self.screen, self.display.get_size(), self.display)
        pygame.display.flip()
        self.clock.tick(FPS)
        self.screen.fill((0, 0, 0))

if __name__ == '__main__':
    Game().main()

Tento náš základní herní cyklus běží rychlostí maximálně FPS snímků za sekundu. V každé své iteraci zkontroluje, zda-li někdo nepoužil klávesu Q, aby se hra vypnula, popř. její vypnutí nebylo vyžádáno jinak. Pokud ne, tak vykreslí plochu screen na obrazovku.

V příští lekci, Pygame - Pong - Logika stavů hry a dokončení, se budeme věnovat stavům hry.


 

Předchozí článek
Pygame - Pong - Příprava
Všechny články v sekci
Pygame - Tvorba her v Pythonu
Článek pro vás napsal Adam Hlaváček
Avatar
Jak se ti líbí článek?
1 hlasů
vývoji užitečných aplikací zjednodušujících každodenní život
Aktivity (3)

 

 

Komentáře

Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zatím nikdo nevložil komentář - buď první!