# A pygame multimédiás könyvtár

Károlyi Péter Márton · 2023.01.13.

A pygame egy platformfüggetlen multimédiás függvénykönyvtár. A programozók számára egy egységes felületet biztosít a grafikus megjelenítéshez, hangok megszólaltatásához, billentyűk, egér és botkormányok kezeléséhez. A pygame-mel megírt program működik különféle Windows verziókon, de Linuxokon, Mac OS X-en, és még néhány okostelefonon is.

A pygame egy platformfüggetlen multimédiás modul. A programozók számára egy egységes felületet biztosít a grafikus megjelenítéshez, hangok megszólaltatásához, billentyűk, egér és botkormányok kezeléséhez, miközben az egyes géptípusok, operációs rendszerek különbségeit elfedi. Így a pygame-mel megírt program működik különféle Windows verziókon, de Linuxokon, Mac OS X-en, és még néhány okostelefonon is.

A `pygame.gfxdraw` modullal vonalakat, köröket és egyéb primitíveket rajzolhatunk ki. De van beépített modul szöveg képernyőre írására tetszőleges betűtípussal: `pygame.font`, hang és zene megszólaltatására: `pygame.mixer` és képfájlok (pl. PNG, JPG) kirajzolására is: `pygame.image`.

A könyvtár egyszerűen telepíthető pip-pel, Windowoson a `pip install pygame` parancs beírásával (ha megfelelően van telepítve a Python), Linuxon pedig `pip3 install pygame` paranccsal. Thonny használata esetén a `Tools / Manage Packages` menüponton keresztül érhető el.

## 1. Az első program

Alább látható az első program. Ez kirajzol néhány kört a képernyőre, utána pedig addig vár, amíg a felhasználó be nem zárja az ablakot a nagy piros X-szel.

Az első lépés a pygame könyvtár inicializálása, ezt az `pygame.init()` nevű függvénnyel tehetjük meg. Ez a függvény az összes pygame alrendszert (display, mixer, font) inicializálja.

Ezután létrehozunk egy 440×360 képpont méretű ablakot az `pygame.display.set_mode()` hívással. Ennek egy tuple-ban, zárójelezve kell megadni az ablak méretét, a további paramétereivel az ablak tulajdonságai (pl. átméretehező-e) és a színmélység állítható. Ezeket most alapbeállításon hagyjuk. A következő sorral az ablak címét állítjuk: `pygame.display.setcaption()`, ezután pedig kezdődhet a rajzolás!

    import math
    import pygame
    import pygame.gfxdraw

    def main():
        # pygame inicializálás
        pygame.init()

        # ablak megnyitás
        window = pygame.display.set_mode((440, 360))
        pygame.display.set_caption('pygame példaprogram')

        # színek
        red = pygame.Color(255, 0, 0)
        green = pygame.Color(0, 255, 0)
        blue = pygame.Color(0, 0, 255)

        # pozíció, sugár
        x = 100
        y = 100
        r = 50

        # kör
        pygame.gfxdraw.circle(window, x, y, r, red)
        pygame.gfxdraw.circle(window, x + r, y, r, green)
        pygame.gfxdraw.circle(window, math.floor(x + r * math.cos(3.1415 / 3)), math.floor(y -  r * math.sin(3.1415 / 3)), r, blue)

        x = 280
        y = 100

        # antialias kör
        pygame.gfxdraw.aacircle(window, x, y, r, red)
        pygame.gfxdraw.aacircle(window, x + r, y, r, green)
        pygame.gfxdraw.aacircle(window, math.floor(x + r * math.cos(3.1415 / 3)), math.floor(y -  r * math.sin(3.1415 / 3)), r, blue)

        x = 100
        y = 280

        # kitöltött kör
        pygame.gfxdraw.filled_circle(window, x, y, r, red)
        pygame.gfxdraw.filled_circle(window, x + r, y, r, green)
        pygame.gfxdraw.filled_circle(window, math.floor(x + r * math.cos(3.1415 / 3)), math.floor(y -  r * math.sin(3.1415 / 3)), r, blue)

        x = 280
        y = 280

        # áttetsző színek
        translucent_red = pygame.Color(255, 0, 0, 96)
        translucent_green = pygame.Color(0, 255, 0, 96)
        translucent_blue = pygame.Color(0, 0, 255, 96)

        # áttetsző kör
        pygame.gfxdraw.filled_circle(window, x, y, r, translucent_red)
        pygame.gfxdraw.filled_circle(window, x + r, y, r, translucent_green)
        pygame.gfxdraw.filled_circle(window, math.floor(x + r * math.cos(3.1415 / 3)), math.floor(y -  r * math.sin(3.1415 / 3)), r, translucent_blue)

        # az elvégzett rajzolások a képernyőre
        pygame.display.update()

        # várunk kilépésre
        quit = False
        while not quit:
            event = pygame.event.wait()
            if event.type == pygame.QUIT:
                quit = True

        # ablak bezárása
        pygame.quit()

    main()

A program köröket rajzol, négyféleképpen. Az első három körnél egyszerűen kiszínezi azokat a képpontokat (pixel), amelyek a körívre esnek. A második háromnál ennél okosabb. Ahol a körív nem pont a képpontra esik, ott a szomszédos képpontok között színátmenetet képez. Ezt az eljárást úgy nevezik, hogy antialiasing. Így a rajz szebb, a körív nem annyira recegős.

Kör rajzolásához meg kell adni a felületet, amire rajzolunk, a kör pozícióját, sugarát és a színét. Színt tároló változót a `pygame.Color()`-ral hozhatunk létre, ennek többféleképpen is megadható a kívánt szín, például:

- A három színkomponens (vörös, zöld, kék) és az átlátszatlanság 0-tól 255-ig való megadásával: `pygame.Color(255, 0, 0, 255)`
- A szín HTML jelölésével, hexadecimálisan: `pygame.Color('#FF0000FF')`

Tehát a `255, 0, 0` vagy `'#FF0000'` jelöli a vöröset, a `255, 255, 255` vagy `'#FFFFFF'` pedig a fehéret. A negyedik paraméter az átlátszatlanságot adja meg, ennek 0 értéke a teljesen átlátszót 255 értéke pedig a teljesen átlátszatlant jelenti. Ez látszik a jobb alsó sarokban, ahol a köröknél az érték 255 helyett csak 96. Így azok színei keverednek. Ha nem adunk meg átlátszatlanságot, alapértelmezetten 255 lesz.

Miután elvégeztük az összes rajzolást, meg kell hívni a `pygame.display.update()` függvényt, hogy az elkészült rajzot megjelenítsük. A rajzolások először csak a memóriában történtek, és igazából a hívás hatására kerül ki minden az ablakba. Ez azért előnyös, mert így a felhasználó nem fogja látni, ahogy egyesével jelennek meg az elemek, hanem csak a végeredményt – animációnál ez fontos lesz. A további rajzolásokkal a meglévő képet módosítjuk; az eredmény pedig egy újabb `pygame.display.update()` hatására jelenik meg.

A `pygame.gfxdraw` modul néhány rajzeleme (grafikai primitíve):

- `pygame.gfxdraw.pixel(felület, x, y, szín)` - képpont rajzolása
- `pygame.gfxdraw.line(felület, x1, y1, x2, y2, szín)` - szakasz
- `pygame.gfxdraw.circle(felület, x, y, r, szín)` - kör
- `pygame.gfxdraw.aacircle(felület, x, y, r, szín)` - antialias kör
- `pygame.gfxdraw.filled_circle(felület, x, y, r, szín)` - kitöltött kör
- `pygame.gfxdraw.trigon(felület, x1, y1, x2, y2, x3, y3, szín)` - háromszög
- `pygame.gfxdraw.aatrigon(felület, x1, y1, x2, y2, x3, y3, szín)` - antialias háromszög
- `pygame.gfxdraw.filled_trigon(felület, x1, y1, x2, y2, x3, y3, szín)` - kitöltött háromszög
- `pygame.gfxdraw.rectangle(felület, téglalap, szín)` - téglalap
- `pygame.gfxdraw.box(felület, téglalap, szín)` - kitöltött téglalap

A téglalapok rajzolása annyiban bonyolultabb a többi rajzelemnél, hogy nem koordinátákat kell megadni, hanem téglalap típusú objektumokat, amelyeket `Rect(x, y, szélesség, magasság)` formában lehet létrehozni.

## 2. Események, eseményvezérelt programozás

Az egyszerű, konzolos programok lineárisan működnek: a `print()`-tel mondhatunk valamit a felhasználónak, az `input()`-tal pedig kérdezhetünk tőle valamit. Nem gond az, hogy az `input()` megakasztja a programot, mert amíg nincs meg a bemenő adat, addig úgysem tudna továbbhaladni a program. Egy játéknál, meg általában a grafikus programoknál ez nincs így. A programnak itt egyszerre több bemenete van: a billentyűzetre és az egérre is reagálnia kell, arról nem is beszélve, hogy ha a felhasználó épp nem nyúl semelyikhez, akkor is folytatódnia kell a képernyőn látható eseményeknek. Nem akadhat meg a játék attól, hogy éppen nem nyomtuk meg egyik gombot sem!

Ezért találták ki az eseményvezérelt programozást. A pygame a programhoz beérkező eseményeket összegyűjti (billentyűzet, egérmozdulatok, időzítések, ablak bezárása), és azokat keletkezésük sorrendjében adja nekünk. Ezt a programnak egy eseményhurokban (event loop) kell feldolgoznia, amely nagyon egyszerű:

    while fut_a_program:
        # megvárjuk a következő eseményt
        event = pygame.event.wait()

        # típus szerinti esetszétválasztás
        if event.type == pygame.VALAMI:
            # egyik fajta esemény feldolgozása
            ...
        elif event.type == pygame.MASIK:
            # másik fajta esemény feldolgozása
            ...

A kezelendő esemény a `pygame.event.wait()` függvénnyel kérhetjük le. Ennek típusát a `type` attribútuma tartalmazza, amelynek pár jellemző értéke:

- `pygame.QUIT`: kilépés, a felhasználó az X-re kattintott az ablak fejlécében
- `pygame.MOUSEMOTION`: egérmozgás
- `pygame.MOUSEBUTTONDOWN`: egérgomb lenyomása
- `pygame.KEYDOWN`: billentyű lenyomása

Az `event` objektum az esemény típusától függően további információkat tartalmaz. Billentyű lenyomása esetén például az `event.key` tárolja a lenyomott billentyű kódját. Egérgomb lenyomása esetén pedig az `event.pos` tartalmazza a kurzor pozícióját, az `event.button` pedig a lenyomott gomb azonosítóját. Az `event.pos` attribútum egy tuple, amelynek 0. indexű adata az x koordináta, 1. indexű pedig az y koordináta. Szükség esetén ezt kicsomagolhatjuk két külön változóba is:

    x, y = event.pos    # x = event.pos[0] és y = event.pos[1]

Az alábbi programban rajzolni lehet az egérrel. A működést a kód közepén lévő eseményhurok irányítja. A bal gombbal lehet rajzolni, a jobb gombbal pedig törölni az ablak tartalmát. Az eseményvezérlés kellemes vonása, hogy a program gyakorlatilag semennyire sem terheli le a számítógépet. Amíg nincs esemény, addig ugyanúgy alszik, ahogyan azt egy `input()`-ra várakozás esetén is teszi.

    import pygame
    import pygame.gfxdraw

    def main():
        # pygame inicializálás
        pygame.init()

        # ablak megnyitás
        window = pygame.display.set_mode((440, 360))
        pygame.display.set_caption('pygame példaprogram')

        # kirajzolás, hogy ne üres ablakkal kezdjünk
        pygame.display.update()

        # az eseményvezérelt hurok
        quit = False
        click = False
        prev_x = 0
        prev_y = 0
        while not quit:
            drawn = False

            event = pygame.event.wait()
            # egér kattintás
            if event.type == pygame.MOUSEBUTTONDOWN:
                # bal gomb = 1, középső gomb = 2, jobb gomb = 3
                if event.button == 1:
                    click = True
                    prev_x, prev_y = event.pos
                elif event.button == 3:
                    window.fill(pygame.Color('#000000'))
                    drawn = True

            # egérgomb elengedése
            if event.type == pygame.MOUSEBUTTONUP:
                if event.button == 1:
                    click = False

            # egér mozgás
            if event.type == pygame.MOUSEMOTION:
                x, y = event.pos
                if click:
                    pygame.gfxdraw.line(window, prev_x, prev_y, x, y, pygame.Color('#FFFFFF'))
                    drawn = True
                # a következő mozdulat eseményhez
                prev_x, prev_y = x, y

            # ablak bezárása
            if event.type == pygame.QUIT:
                quit = True

            if drawn:
                pygame.display.update()

        pygame.quit()

    main()

Maga az eseményhurok ennél a progamnál tulajdonképpen egy állapotgép; az egyes események jelentése eltérő attól függően, hogy mik történtek a múltban. Például az egérmozdulatnál csak akkor rajzolunk, ha előzőleg egy kattintás eseményt már feldolgoztunk. Minden mozdulatnál megjegyezzük a koordinátákat, hogy a legközelebbi ugyanilyen eseménynél tudjuk, honnan hova kell húzni a vonalat.

## 3. Időzítők használata

Előbb arról volt szó, hogy a program futásának nem szabad megszakadnia amiatt, mert eseményre vár – és aztán jött egy program forráskódja, amely nem csinál semmit, azaz alszik az események között. Hogy fog akkor a játék tovább futni, amíg a felhasználó nem nyúl se a billentyűzethez, se az egérhez? Nagyon egyszerű: létre kell hozni egy időzítőt, amely adott időközönként generál egy eseményt. Ha létrejön az esemény, annak hatására fel fog ébredni az eseményhurok – de fel fog ébredni a billentyűzet vagy az egér hatására is.

Időzítőt létrehozni az `pygame.time.set_timer()` függvénnyel lehet. Ennek paraméterei a következők: 1) milyen esemény generálódjon, 2) milyen időközönként (ezredmásodperc). A hívás tehát így néz ki:

    pygame.time.set_timer(pygame.USEREVENT, 20)

Az így létrehozott időzítőket kitörölni úgy lehet, hogy az adott eseményhez tartozó időzítőt 0ms-re állítjuk, tehát a `pygame.USEREVENT` időzítőt így:

    pygame.time.set_timer(pygame.USEREVENT, 0)

Amennyiben több időzítőre is szükségünk van a `pygame.USEREVENT` és a `pygame.NUMEVENTS` közötti számokat használhatjuk (pl. `pygame.USEREVENT + 1`).

Az időzítő használatához az eseménykezelő hurkot kell a `pygame.USEREVENT` típusú események feldolgozásával kiegészíteni, tehát a labdát pattogtató program így néz ki:

    import pygame
    import pygame.gfxdraw

    # ablak mérete és labda sugara
    WINDOW = 360
    BALL_R = 10

    # labda helyzete és sebessége
    class Ball:
        def __init__(self):
            self.x = WINDOW // 2
            self.y = WINDOW // 2
            self.vx = 3
            self.vy = 2

    def main():
        # pygame inicializálás
        pygame.init()

        # ablak megnyitás
        window = pygame.display.set_mode((360, 360))
        pygame.display.set_caption('pygame példaprogram')

        # objektum létrehozása
        ball = Ball()

        # időzítő hozzáadása: 20ms; 1000 ms / 20 ms -> 50 fps
        pygame.time.set_timer(pygame.USEREVENT, 20)

        quit = False
        # szokásos eseményhurok
        while not quit:
            event = pygame.event.wait()
            # felhasználói esemény: ilyeneket generál az időzítő függvény
            if event.type == pygame.USEREVENT:
                # kitöröljük az előző pozíciójából (nagyjából)
                pygame.gfxdraw.filled_circle(window, ball.x, ball.y, BALL_R, pygame.Color('#202040'))
                # kiszámítjuk az új helyet
                ball.x += ball.vx
                ball.y += ball.vy
                # visszapattanás
                if (ball.x < BALL_R or ball.x > WINDOW - BALL_R):
                    ball.vx *= -1
                if (ball.y < BALL_R or ball.y > WINDOW - BALL_R):
                    ball.vy *= -1
                # újra kirajzolás, és mehet a képernyőre
                pygame.gfxdraw.filled_circle(window, ball.x, ball.y, BALL_R, pygame.Color('#8080FF'))
                pygame.display.update()

            if event.type == pygame.QUIT:
                quit = True

        # időzítő törlése
        pygame.time.set_timer(pygame.USEREVENT, 0)
        pygame.quit()

    main()

Itt nagyon fontos, hogy csak a kép teljes megrajzolása után hívjuk meg az `pygame.display.update()`-et. Ha a törlés után is meghívnánk, akkor az animáció villódzna (flicker), így viszont szép, folytonos a megjelenítés. Törölni viszont kell, hiszen mindig az előzőleg megrajzolt képet módosítjuk.

## 4. Képfájlok beolvasása

A képfájlok beolvasása egyszerű feladat: a `pygame.image` modulnak van egy `load()` nevű függvénye. Ennek paramétere a betöltendő kép, ami elég sokféle formátumú lehet (a pygame dokumentációja szerint JPG, PNG, GIF (non-animated), BMP, PCX, TGA (uncompressed), TIF, LBM (and PBM), PBM (and PGM, PPM), XPM). A függvény visszatérési értéke a betöltött képet tartalmazó felület, egy `pygame.Surface` típusú objektum.

A felület nagyon hasonló az ablakként létrehozott felületre, csak épp nincs sehol megjelenítve. Ahhoz, hogy a képünk a képernyőn látszódjon azt (vagy annak megfelelő részét) át kell másolnunk az ablak felületére. Ezt a `blit()` nevű függvény segítségével tudjuk megtenni. Ennek első paramétere a másolandó felület, a második paramétere a második paramétere a beillesztés helye, opcionális harmadik paramétere pedig egy `Rect`, ami a másolandó területet jelöli ki. A harmadik paraméter elhagyása esetén a teljes forrásfelületet másoljuk.

Tehát a lenti kód a `window` felület `(82, 74)`-es pozíciójába másolja az `image` felület azon részét, melyet a `(10, 10)` bal felső sarkú, `(62, 62)` méretű téglalap (négyzet) határoz meg.

    window.blit(image, (82, 74), pygame.Rect((10, 10), (62, 62)))

Az alábbi programban kihasználjuk azt, hogy a kép egy részét is lehet másolni. A program tartalmaz egy `Pieces` objektumot, ami az egyes bábuk pozícióját és méretüket tartalmazza. A szokásos inicializálás után a `res` könyvtárban található `pieces.png` nevű képről három sakkbábut másolunk a képernyőre.

    import pygame
    import pygame.gfxdraw

    class Pieces:
        def __init__(self):
            # a figurák koordinátái a képen
            self.W_KING = (10, 10)
            self.W_QUEEN = (72, 10)
            self.W_ROOK = (134, 10)
            self.W_BISHOP = (196, 10)
            self.W_KNIGHT = (258, 10)
            self.W_PAWN = (320, 10)
            self.B_KING = (10, 70)
            self.B_QUEEN = (72, 70)
            self.B_ROOK = (134, 70)
            self.B_BISHOP = (196, 70)
            self.B_KNIGHT = (258, 70)
            self.B_PAWN = (320, 70)

            # a figurák mérete a képen
            self.SIZE = (62, 62)

            # kép betöltése
            self.image = pygame.image.load('pieces.png')

    def main():
        # objektum létrehozása
        pieces = Pieces()

        # pygame inicializálás
        pygame.init()

        # ablak megnyitás
        window = pygame.display.set_mode((320, 200))
        pygame.display.set_caption('pygame példaprogram')

        # rajz készítése
        window.fill(pygame.Color('#90E090'))
        window.blit(pieces.image, (82, 74), pygame.Rect(pieces.W_KING, pieces.SIZE))
        window.blit(pieces.image, (144, 74), pygame.Rect(pieces.B_PAWN, pieces.SIZE))
        window.blit(pieces.image, (206, 74), pygame.Rect(pieces.W_KNIGHT, pieces.SIZE))

        # ki a képernyőre
        pygame.display.update()

        # szokásos várakozás a kilépésre
        quit = False
        while not quit:
            event = pygame.event.wait()
            if event.type == pygame.QUIT:
                quit = True

        pygame.quit()

    main()

pieces.png letöltése

## 5. Szövegek megjelenítése

Szövegeket a `pygame.font` modul segítségével lehet a képernyőre írni. Először a `pygame.font.Font()` vagy a `pygame.font.SysFont()` meghívásával be kell tölteni egy betűtípust. A két módszer közötti különbség, hogy a `Font()`-nak egy betűtípus filet kell megadni, a `SysFont()`-nak pedig egy az operációs rendszerbe telepített betűtípus nevét. Mindkét függvény második paramétere a méret és visszatérési értékük a betöltött betűtípus. Például:

    font = pygame.font.SysFont('Arial', 32)

A betöltött betűtípussal ezután a `font.render()` függvénnyel tudunk írni. Ennek az első paramétere a szöveg, amit ki akarunk írni, a második paramétere, hogy szeretnénk-e antialiast, a harmadik pedig, hogy milyen színnel írjon. A negyedik opcionális paraméter a háttér színét határozza meg, ha ezt nem adjuk meg átlátszó háttérre írunk. Például az "Pygame" szöveg kiírása átlátszó háttérre, fehérrel:

    white = pygame.Color('#FFFFFF')
    text = font.render('Pygame', True, white)

A `render()` nem közvetlenül a képernyőre írja a szöveget, hanem egy felületre, amit nekünk kell a képernyőre másolni. Erről az előző fejezetben volt szó, ezek alapján a szöveg másolása a `window` felület bal felső sarkába így néz ki:

    window.blit(text, (0, 0))

Betűtípusokat a Windows `C:\Windows\Fonts` mappájában, vagy a Linux `/usr/share/fonts/truetype` mappájában lehet találni. Meg a neten egy csomó helyen, csak sajnos az ingyenes betűtípusokból hiányozni szokott a hosszú `ő` és az `ű` betű. A lenti rajz a Liberation Serif nevű betűtípust használja. A linkre kattintva letölthető fájlt a projekt mappájába kell tenni.

LiberationSerif-Regular.ttf letöltése

    import random

    import pygame
    import pygame.gfxdraw

    def randomcolor():
        return pygame.Color(random.randrange(256), random.randrange(256), random.randrange(256), 64)

    def main():
        # pygame inicializálás
        pygame.init()

        # ablak megnyitás
        window = pygame.display.set_mode((480, 200))
        pygame.display.set_caption('pygame példaprogram')

        white = pygame.Color('#FFFFFF')
        red = pygame.Color('#FF0000')

        # háttér véletlenszerű elhelyezkedésű és színű körökkel
        for i in range(500):
            pygame.gfxdraw.filled_circle(window,
                                         random.randrange(0, 480),
                                         random.randrange(0, 200),
                                         random.randrange(10, 15),
                                         randomcolor())

        # betűtípus betöltése, 32 pont magasságal
        font = pygame.font.SysFont('Arial', 32)

        # különféle kiírások
        text = font.render('No AntiAlias', False, white)
        window.blit(text, ((480 - text.get_width()) / 2, 20))

        text = font.render('With Background', False, white, red)
        window.blit(text, ((480 - text.get_width()) / 2, 60))

        text = font.render('Yes AntiAlias', True, white)
        window.blit(text, ((480 - text.get_width()) / 2, 100))

        text = font.render('Még ékezettel is működik', True, white, red)
        window.blit(text, ((480 - text.get_width()) / 2, 140))

        # ki a képernyőre
        pygame.display.update()

        # szokásos várakozás a kilépésre
        quit = False
        while not quit:
            event = pygame.event.wait()
            if event.type == pygame.QUIT:
                quit = True

        pygame.quit()

    main()

## 6. A billentyűzet kezelése

A billentyűzet kezelése pygame-ben nem nagy ördöngősség: `pygame.KEYDOWN` eseményt kapunk egy billentyű megnyomásánál, `pygame.KEYUP` eseményt az elengedésénél. Az esemény adatait tároló strktúrában az alábbi adattagok érhetőek el:

- `event.key`: a lenyomott billentyű azonosítój.
- `event.mod`: módosító billentyűk (shift, ctrl stb.) Mivel egyszerre több módosító is le lehet nyomva, egy bitenkénti ÉS & művelettel kell megvizsgálni azt, amelyik érdekes. A módosítók lenyomásakor külön esemény is érkezik.

Játékokban, ahol arra vagyunk kíváncsiak, hogy nyomva van-e tartva egy billentyű, nekünk kell külön megjegyezni azt. Ez egyszerűen megoldható egy logikai típusú változóval, amelynek értékét `pygame.KEYDOWN` esemény esetén igazra, `pygame.KEYUP` esemény esetén pedig hamisra állítjuk. Az alábbi példaprogramban pontosan ez történik. A balra `←` és jobbra `→` nyilakat nyomva tartva lehet változtatni a háromszögek színét. Az `Esc` gomb pedig az ablak bezárásához hasonlóan kilép a programból.

    import pygame
    import pygame.gfxdraw

    def main():
        # pygame inicializálás
        pygame.init()

        # ablak megnyitás
        window = pygame.display.set_mode((350, 200))
        pygame.display.set_caption('pygame példaprogram')

        quit = False
        left = False
        right = False
        draw = True

        while not quit:
            if draw:
                color = pygame.Color("#00C000") if left else pygame.Color("#FF0000")
                pygame.gfxdraw.filled_trigon(window, 50, 100, 150, 50, 150, 150, color)
                color = pygame.Color("#00C000") if right else pygame.Color("#FF0000")
                pygame.gfxdraw.filled_trigon(window, 300, 100, 200, 50, 200, 150, color)
                pygame.display.update()
                draw = False

            event = pygame.event.wait()
            if event.type == pygame.KEYUP:
                if event.key == pygame.K_LEFT:
                    left = False
                    draw = True
                if event.key == pygame.K_RIGHT:
                    right = False
                    draw = True
                if event.key == pygame.K_ESCAPE:
                    quit = True

            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_LEFT:
                    left = True
                    draw = True
                if event.key == pygame.K_RIGHT:
                    right = True
                    draw = True

            if event.type == pygame.QUIT:
                quit = True

        pygame.quit()

    main()

## 7. Szöveg bevitele

Az alábbi példaprogram egy szöveg beolvasását végző függvényt tartalmaz. Kell neki a LiberationSerif-Regular.ttf nevű fájl, amelyet az előző program is használt.

    import random

    import pygame
    import pygame.gfxdraw

    def input_text(x, y, width, height, bg_color, fg_color, font, surface):
        clip = surface.get_clip()
        destination = pygame.Rect(x, y, width, height)
        surface.set_clip(destination)

        user_input = ''
        enter = False
        quit = False
        while (not quit) and (not enter):
            # szöveg kirajzolása
            pygame.gfxdraw.box(surface, destination, bg_color)
            pygame.gfxdraw.rectangle(surface, destination, fg_color)
            text = font.render(user_input + '|', True, fg_color)
            surface.blit(text, destination)
            pygame.display.update()

            event = pygame.event.wait()
            if event.type == pygame.KEYDOWN:
                # enter: bevitel vége
                if event.key == pygame.K_RETURN:
                    enter = True
                # backspace: utolsó karakter törlése
                elif event.key == pygame.K_BACKSPACE:
                    user_input = user_input[:-1]
                # egyébként meg hozzáadjuk a beírt szöveghez
                else:
                    user_input += event.unicode

            if event.type == pygame.QUIT:
                # visszatesszük a sorba, mert sok mindent nem tudunk vele kezdeni
                pygame.event.post(event)
                quit = True

        surface.set_clip(clip);
        return user_input

    def randomcolor():
        return pygame.Color(random.randrange(256), random.randrange(256), random.randrange(256))

    def main():
        white = pygame.Color('#FFFFFF')
        black = pygame.Color('#000000')

        pygame.init()

        window = pygame.display.set_mode((480, 200))
        pygame.display.set_caption('pygame szöveg bevitele')

        font = pygame.font.SysFont('Arial', 32)

        # szöveg beolvasása
        for i in range(200):
            pygame.gfxdraw.filled_circle(window,
                                         random.randrange(480),
                                         random.randrange(200),
                                         random.randrange(20, 25),
                                         randomcolor())
        pygame.display.update()
        user_input = input_text(40, 80, 400, 40, black, white, font, window)

        # szöveg kirajzolása
        pygame.gfxdraw.box(window, pygame.Rect(0, 0, 480, 200), black)
        for i in range(200):
            pygame.gfxdraw.filled_circle(window,
                                         random.randrange(480),
                                         random.randrange(200),
                                         random.randrange(20, 25),
                                         randomcolor())
        text = font.render(user_input, True, white)
        window.blit(text, ((480 - text.get_width()) / 2, (200 - text.get_height()) / 2))
        pygame.display.update()

        quit = False
        while not quit:
            event = pygame.event.wait()
            if event.type == pygame.QUIT:
                quit = True

        pygame.quit()

    main()