Ügyességi játékok programozása
Pythonnal és Pygame-mel

Chapter 5: Bevezetés a grafikába

Már tudunk ciklusokat készíteni, így itt az ideje megtanulni grafikai felületet kezelni. Ez a fejezet az alábbiakról fog szólni:

5.1 A számítógép koordináta rendszere

Videó A számítógépes grafikában használt koordináta rendszer

A hagyományos (Descartes-féle) koordináta rendszert láthatjuk itt. Figure 5.1(Wikimedia Commons), Ez az a rendszer, amit a legtöbb ember használ arra, hogy grafikát alkalmazzon. Ezt a rendzsert tanultuk az iskolában. A számítógépé hasonlóan működik, de egy kicsit más. Ahhoz, hogy megértsük, miért tér el, egy kicsit vissza kell tekintenünk a számítógépek történetébe:

fig.Cartesian_coordinates_2D
Figure 5.1: Hagyományos koordináta rendszer

A korai 80-as években a legtöbb rendszer szöveg-alapú volt, és nem támogatta a grafikát. Figure 5.2(Wikimedia Commons) , ez az ábra egy egyoldalas programot mutat, ami egy Apple gépen futott, és eléggé népszerű volt a 80-s években. Amikor a képernyőn a szöveget elhelyezték, a programozók a felső sort kezdték el "első sornak" hívni. A képernyő még 24 soron át folytatódott, és 40 karakter volt mindben.

fig.apple3screen
Figure 5.2: korai Apple szöveges képernyő

Még, ha sima szöveget is használtunk, akkor is volt lehetőség arra, hogy kezdetleges grafikákat alkossunk pusztán a billentyűzet karaktereinek segítségével. Itt van például a kiscica, az ábrán 5.3érdemes tüzetesen megvizsgálni azt, ahogyan megrajzolták. Amikor készítették, a karaktereket felül, az első sorba pozícionálták.

fig.simpleASCII
Figure 5.3: Szöveges képernyő

Később a karakter-készlet kibővült és már dobozok, és más primitív alakzatok kerültek bele. A karaktereket meg lehetett jeleníteni mindenféle színnel. Ezt láthatjuk az ábrán 5.4, a grafika itt már fejlettebb. Ha rákeresünk a neten az "ASCII art" kifejezésre, sokkal több példát is találhatunk.

fig.spacewar
Figure 5.4: Spacewar nevű játék szöveges képernyője

Miután a számítógépek képessé váltak színes képpontokat egyenként is kezelni, a szöveg-alapú koordináta rendszer megrekedt ott, ahol volt.

fig.Computer_coordinates_2D
Figure 5.5: Számítógépes koordináta rendszer

Az $x$ koordináták ugyanott vannak, mint a Descartes-féle koordináta rendszerben. Egyedül az $y$ koordináta van megfordítva. Vagyis, ahelyett, hogy az $y$ koordináta az alul kezdődne, mint rendesen, a felső sarokból kezdjük el számolni a számítógépen. Ahogy növekszik az $y$ értéke, úgy megy a pozíciónk is lefelé a képernyőn. Lásd a következő ábrát:5.5.

Vagyis, jegyezd meg, hogy a képernyő legtávolabbi pontja a jobb alsó sarok, ellenben a Descartes-féle koordináta rendszerrel, ahol ez a jobb felső sarokban van. Lehetőség van negatív koordinátákkal is kirajzolni dolgokat, de ezek a képernyőn kívülre fognak kerülni. Ez hasznos lehet olyankor, amikor egy alakzat egy része a képernyőn kívülre kerül. A számítógép nyilvántartja azt, hogy mi van a képernyőn kívül, és a programozónak nem kell emiatt is aggódnia.

5.2 A Pygame könyvtár

Videó: Megnyitni egy ablakot

Ezért, hogy könnyebb legyen a grafikával dolgozni, a Pygame-t fogjuk használni. A Pygame egy kódkönyvtár, amit mások írtak és egyszerű használni:

Egy Pygame-ben megírt program első kódja először betölti és előkészíti a Pygame könyvtárat. Minden program, ami Pygame-t használ, ezekkel a sorokkal kell, hogy kezdődjön:

# Importálunk egy függvény-könyvtárat, amit 'pygame'-nak hívnak
import pygame
# A játék motorjának inícializálása
pygame.init()

Ha még nem telepítetted volna a Pygame-t, akkor a segítség ehhez elérhető a mielőtt belekezdenél részben Ha még nincs a Pygame telepítve a számítógépedre, akkor egy hibaüzenet lesz az eredménye annak a parancsnak, hogy import pygame.

Ne nevezz el egyetlen fájlt sem “pygame.py”-nak!

Fontos: Az import pygame megpróbál keresni egy könyvtár-fájlt, amit pygame-nek hívnak. Ha a programozó egy ilyen nevű fájlt hoz létre, akkor a számítógép azt a fájlt fogja megnyitni a pygame.py helyett. Ez meg fog gátolni minden más pygame programot abban, hogy fusson, amíg törölve nem lesz.

5.3 Színek

Ezután, olyan változókat kell létrehoznunk, melyek meghatározzák a színeket a programunkban. A színek, három szín alapján vannak meghatározva: vörös, zöld, és kék. Hallottál már RGB monitorról? Ez az eredete az elnevezésnek. Red-Green-Blue (vörös-zöld-kék) Régibb monitoroknál, ha elég közel ülsz a képernyőhöz, akkor láthatod is egyenként az RGB színeket. Vagy legalábbis addig, amíg az anyukád nem szól, hogy ne ülj olyan közel. Ez már nem igaz viszont a mostani nagyfelbontású monitorokra.

Minden eleme az RGB triádnak egy számot jelöl, 0 és 255 közt. A zérus azt jelenti, hogy semmilyen színt ne jelenítsen meg, a 255 pedig, hogy olyannyira erősen, amennyire csak bírja. A színek additív módon keverednek, szóval, ha mindhárom szín specifikált, akkor a monitoron a fehér szín fog megjelenni. (Ez eltér attól, ahogyan a tinta, és a festék működik.)

A Pythonban a listákat szögletes zárójel, vagy zárójel választhatja el. (A Hetedik fejezet fogja elmondani a részleteket, és hogy mi a különbség a kettő közt.) Az egyedi számokat vesszővel választjuk el. Alább van egy példa arra, hogyan hozzunk létre változóket és adjuk meg őket egy lista három számának. Ezt a listát később a színek meghatározánál használni fogjuk.

# Define some colors
BLACK    = (   0,   0,   0)
WHITE    = ( 255, 255, 255)
GREEN    = (   0, 255,   0)
RED      = ( 255,   0,   0)

Miért vannak ezek a változók nagybetűvel írva? Emlékezz vissza az első fejezetre, az olyan változót, ami nem változik, konstansnak nevezzük. Nem várjuk el, hogy a fekete színe megváltozzon; ez konstans, vagyis állandó. Ezeket a konstans változókat úgy különböztetjük meg, hogy nyomtatott nagybetűvel írjuk ki őket. Ha egy színt meg szeretnénk változtatni, ha például, vagy egy égbolt_színe ami megváltozik napnyugtakor, akkor ezt a változót kisbetűvel írjuk ki.

Az interaktív IDLE shellt használva, próbáld meg ezeket a változókat definiálni, és kiíratni. Ha az öt szín, ami fentebb van, nem azok, amiket te szeretnél, akkor határozd meg őket magad. Ahhoz, hogy megadj egy színt, keress egy online "szín-felvevő"(color-picker) eszközt, ahogy azt az alábbi ábrán is láthatod: 5.6. Egy ilyen szín-pipetta pl.
http://www.colorpicker.com/

fig.colorpicker
Figure 5.6: Color picker

Extra: Néhány color picker tizenhatos számrendszerben adja meg a színkódot. Megadhatod hexadecimálisan , ha akarod, kezdve a számokat 0x-szel. Például:

WHITE = (0xFF, 0xFF, 0xFF)

Továbbá a programnak szüksége lesz a $\pi$ értékére, amikor szöget akar rajzolni, szóval ez egy alkalmas idő arra, hogy definiáljuk azt, amit a $\pi$ értéke tartalmaz. (Szintén lehetséges, hogy a matematika könyvtárból importáljuk:math.pi.).

PI = 3.141592653

5.4 Ablak nyitása

Eddig a programok, amiket alkottunk, csak a képernyőre írtak ki valamit. Azok a programok nem nyitottak meg semmilyen ablakot, mint a legtöbb modern program. A kód, amivel ablakot nyithatunk meg, egyáltalán nem bonyolult. Alább megtekinthető, jelen esetben egy 700 pixel széles és 500 pixel magas ablakot eredményez.

size = (700, 500)
screen = pygame.display.set_mode(size)

Miért a set_mode? Miért nem az open_window? A magyarázat az, hogy ez a parancs sokkal több mindent csinál. Képes játékokat futtatni ablakban. Ezzel lehet leszedni a start menüt, címfeliratokat, és irányítani mindent a képernyő felületén. Mivel ezt a módot sokkal nehezebb használni, és mivel a legtöbb ember kedveli a képernyőben futtatott játékokat, ezért átugorjuk a teljes képernyőben megírt játékok részleteit. De, ha szeretnél ezekről is többet megtudni, akkor kérlek lesd meg a dokumentációt a pygame-n belül, egy paranccsal: display.

Továbbá miért size = (700, 500), és nemsize = 700, 500? Ugyanazon okból amiért a színdefiníciónál is használtuk a zárójelet. A python nem képes alapesetben tárolni két változót (szélesség és magasság) egy változóban. Az egyetlen módja ennek, ha listaként tároljuk. A listáknál szükséges zárójelet, vagy négyszögletes zárójelet használni. (Technikailag, a zárójelbe írt számokat rekordnak vagy állandó listának hívjuk. A szögletes zárójelbe írt számokkal megírt lista, pedig a lista. A hetedik fejezetben bővebben szólunk ezekről. )

Az ablak címének megadásához (ami a címsorban van) az alábbi kódot használjuk:

pygame.display.set_caption("Professor Craven's Cool Game")

5.5 Párbeszéd a felhasználóval

Idáig csak egy olyan programot írtunk, ahol megjelenik egy ablak, majd ennyi. A felhasználó nem tud semmit sem cselekedni, még bezárni sem. Mindezt le kell programozni. Írnunk kell egy ciklust, ami addig vár, amíg a felhasználó az 'kilépés'-re nem klikkel.

Ez a legösszetetteb része a programnak, de nem szükséges minden részletét még tökéletesen érteni. Azonban, szükséges az, hogy legyen egy elképzelésünk arról, hogy mi is ez. Szóval, kérlek szentelj egy kis időt ennek.

#Hajtsd végre addig, amíg a felhasználó nem klikkel a bezár gombra.
done = False

# Itt állítjuk be, hogy a képernyő milyen rendszerességgel frissül.
clock = pygame.time.Clock()

# -------- A főprogram ciklusa -----------
while not done:
    # Minden eseményvezérlés ez alatt fog történni
    for event in pygame.event.get(): # felhasználó valamit tesz
        if event.type == pygame.QUIT: # ha a felhasználü a bezár gombra klikkel
            done = True # megjegyezzük, hogy készen vagyunk és kilépünk a programból
    # Minden eseményvezérlés ez alatt fog történni


    # A játék logikája a komment alatt folytatódik

    #  A játék logikája a komment alatt folytatódik


    #  A játék logikája a komment alatt folytatódik

    #  A játék logikája a komment alatt folytatódik

    # 20 frame per másodpercre meghatározva
    clock.tick(20)

Végső fokon, olyan kódot írtunk, ami a billentyűzetet és az egeret ellenőrzi. Ez a kód mindig lefut majd az esemény végrehajtások közt. Olyan kódok lesznek majd a "játék logikája" közt, amelyek megmondják, hogy lett-e kilőve golyó, vagy hogyan mozog egy tárgy. Ezekről majd később ejtünk szót. A megjelenítés az adott kódokon belül lesz.

5.5.1 Az esemény-vezérelt ciklusa

Pay Attention!

Figyelem! Az egyik legidegesítőbb probléma, amit egy programozó elkövethet, az az, belezavarodik az esemény-vezérelt ciklusába. Ez az 'esemény vezérlés' kód kezeli a billentyű lenyomásokat, egérgombbal való klikkelést, és más hasonló eseményeket. Például a te ciklusod kinézhet valahogy így:

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            print("A felhasználó ki szeretne lépni.")
        elif event.type == pygame.KEYDOWN:
            print("A felhasználó lenyomott egy billentyűt.")
        elif event.type == pygame.KEYUP:
            print("Felhasználó elengedett egy billentyűt.")
        elif event.type == pygame.MOUSEBUTTONDOWN:
            print("Felhasználó lenyomta az egér gombot.")
Az események (mint amilyen egy billentyű lenyomása) mindannyian egy listába kerülnek. A program egy for ciklust használ az esemény ismétlésére. Egy ismétlődő if parancssort alkalmazva, a program meghatározza, hogy mi is történt, és aszerint kezeli az eseményt, ahogyan az adott if meghatározza.

Az összes if parancs együtt kerül vizsgálat alá, egy for cikluson belül. Elég gyakori hiba, hogy amikor másolunk, és beillesztünk egy kódot, akkor néha kétszer illesztjük be magát a ciklust is, és így két esemény ciklusunk lesz.

    # Itt van egy esemény-vezérelt ciklus
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            print("A felhasználó ki szeretne lépni.")
        elif event.type == pygame.KEYDOWN:
            print("A felhasználó lenyomott egy billentyűt.")
        elif event.type == pygame.KEYUP:
            print("Felhasználó elengedett egy billentyűt.")

    # Ide a programozó bemásolt egy esemény-vezérlő ciklust
    # a programba. Ez ROSSZ. Az események már vezérelve vannak
    #
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            print("A felhasználó ki szeretne lépni.")
        elif event.type == pygame.MOUSEBUTTONDOWN:
            print("Felhasználó lenyomta az egér gombot.")

A for ciklus a második sorban minden felhasználói cselekvésre reagál. A for ciklus a tizenhármas sorban nem fog semmilyen eseményt vezérelni, mivel azok már végrehajtódtak előtte.

Másik tipikus hiba, amikor rajzolni kezdünk, és aztán megpróbáljuk befejezni az esemény-vezérelt ciklusunkat:

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            print("Felhasználó lenyomta az egér gombot.")
        elif event.type == pygame.KEYDOWN:
            print("Felhasználó lenyomott egy billentyűt.")


    pygame.rect.draw(screen, GREEN, [50,50,100,100])

    # Ez a kód ami vezérli az eseményeket. De ez nem a "for" cikluson belül  van.
    # Nem fog megbízhatóan működni.
    if event.type == pygame.KEYUP:
        print("Felhasználó felengedett egy billentyűt.")
    elif event.type == pygame.MOUSEBUTTONDOWN:
        print("Felhasználó lenyomott egy egér gombot.")

Ez azt fogja eredményezni, hogy a program figyelmen kívül hagy majd pár billentyű és egér parancsot. Miért? A for ciklus nyomon követ minden eseményt egy listából. Szóval, ha két gombot nyomunk le, akkor a for ciklus mindkettőre reagál majd. A fenti példában, az if parancs nincs a for cikluson belül. Ha több esemény történik, akkor az if parancs csak a legutolsó esetén fut le, nem az összesen.

5.5.2 Az összes keret vezérlése

A játék összes keretének alapvető logikája és sorrendje:

A programunkat egyszerűbb lesz olvasni és megérteni, ha ezeket a lépéseket nem keverjük össze. Ne kezdj el számolni, aztán rajzolni, aztán még számolni és még rajzolni. Hanem, nézd meg, hogy milyen egyszerűen működött ez a számológép programunk esetén az első fejezetben. A felhasználó megadta az adatokat, számítás futott, és kiírtuk a választ. Ugyanez a minta fog lenni itt is.

A kód, amivel a képet megrajzoljuk a képernyőre, az a cikluson belülre kerül. Ha az óra ketyegését (clock tick) 10-re állítjuk, akkor a tartalma az ablaknak 10-szer fog kirajzolódni minden másodpercben. Ha mindez túl gyors lenne, akkor a számítógép be fog lassulni, mivel időbe kerül neki is, hogy mindig frissítse a képernyőt. Ha mindez nem a cikluson belül van, akkor a képernyőre nem lesz megjelenítve újra meg újra tökéletesen az, amit akarunk. Ha a rajz a cikluson kívül van, akkor a képernyőn csak részlegesen látjuk majd a grafikát, de a grafika nem fog újra meg- jelenni, ha a képernyőt kisebbre vettük, vagy ha egy másik képernyőt tettünk elé.

5.6 Program lezárása

Most, ha az ablakban a "bezárás" gombra kattintunk, miközben ez a pygame program az IDLE-n belül van, akkor is az eredmény a program összeomlása lesz. Ekkor jó sokszor kell a bezárásra klikkelnünk.

A baj csak az, hogy habár a program végre lett hajtva, de a program nem szólt erről a számítógépnek. Szóval, a lenti parancsot gépeljük be, ha bármilyen megnyitott ablakot szeretnénk bezárni.

pygame.quit()

5.7 A képernyő letakarítása

A következő kód letörli bármi is legyen az ablakban, és egy fehér hátteret kapunk. Emlékezz rá, hogy a white nevű változót korábban definiáld listaként, 3 RGB értékkel.

# A képernyő letörlése és a képernyő háttér beállítása
screen.fill(WHITE)
Videó: Vonalak rajzolása

Ennek azelőtt kell megtörténnie, hogy bármilyen más parancs végrehajtódna. Ha azután törlöd a képernyőt, hogy a program kirajzolt minden grafikát akkor a felhasználó csak egy üres képernyővel játszhat.

Amikor megcsinálunk egy ablakot, az alapértelmezett esetben fekete hátterű. Ez fontos, hogy letöröljük a képernyőt, mivel számtalan dolog van, ami képes megjelenni egy frissen kreált képernyőn is. A programunknak ugyanis mindegy, hogy üres oldalra rajzol, vagy egy már megkezdettre.

5.8 Képernyő frissítése

Nagyon fontos! Frissíteni kell a kijelzőt, miután rajzoltunk rá. A számítógép nem fogja megjeleníteni a grafikát úgy, ahogy te rajzolod, mivel akkor vibrálna a képernyő. Megvárja, amíg a program végzett a rajzolással, és azután megjeleníti azt. A lenti parancs frissíti a teljes képernyőn a grafikát.

Hiba szokott lenni, hogy ez a parancs csak egy tiszta lapot készít. Valójában bármilyen kód, ami rajzolna ezután nem jelenik meg.

# Gyerünk, és frissítsük a képernyőt azzal, amit rajzoltunk.
pygame.display.flip()

5.9 Üres ablak megnyitása

Rakjunk akkor most már mindent egybe egy programba, amiről eddig beszéltünk. Ez a program lehet egy minta is a további Pygame programjaink számára. Ez meg fog nyitni egy üres ablakot, és megvárja, hogy a felhasználó megnyomja a bezárás gombot.

"""
 Pygame base template for opening a window

 Sample Python/Pygame Programs
 Simpson College Computer Science
 http://programarcadegames.com/
 http://simpson.edu/computer-science/

 Explanation video: http://youtu.be/vRB_983kUMc
"""

import pygame

# Define some colors
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
GREEN = (0, 255, 0)
RED = (255, 0, 0)

pygame.init()

# Set the width and height of the screen [width, height]
size = (700, 500)
screen = pygame.display.set_mode(size)

pygame.display.set_caption("My Game")

# Loop until the user clicks the close button.
done = False

# Used to manage how fast the screen updates
clock = pygame.time.Clock()

# -------- Main Program Loop -----------
while not done:
    # --- Main event loop
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            done = True

    # --- Game logic should go here

    # --- Screen-clearing code goes here

    # Here, we clear the screen to white. Don't put other drawing commands
    # above this, or they will be erased with this command.

    # If you want a background image, replace this clear with blit'ing the
    # background image.
    screen.fill(WHITE)

    # --- Drawing code should go here

    # --- Go ahead and update the screen with what we've drawn.
    pygame.display.flip()

    # --- Limit to 60 frames per second
    clock.tick(60)

# Close the window and quit.
pygame.quit()

5.10 Bevezetés a rajzoláshoz

Itt egy lista azokról, amiket kirajzolhatsz:
http://www.pygame.org/docs/ref/draw.html
A program kirajzolhat olyan dolgokat, mint sokszögek, téglalapok, körök, ellipszisek, ívek, és vonalak. El fogjuk majd mondani azt is, hogyan. A Bit-térképes grafika (képek) a tizenkettedik fejezetben lesznek megtalálhatóak. Ha úgy döntesz, hogy a pygame referenciáját tekinted meg, akkor olyan függvényeket fogsz itt találni, mint például:

pygame.draw.rect(Surface, color, Rect, width=0): return Rect

A vonal rajzolásnál megadott width=0 sokszor összezavarja az embereket. Amit ez jelent, az az, hogy nem lesz szélessége a vonalnak, mivel itt 0-t adtunk meg neki. Ezt a függvényt is meghívhatjuk:

pygame.draw.rect(screen, RED, [55,500,10,5])

Ugyanaz lesz, mint az alábbi:

pygame.draw.rect(screen, RED, [55,500,10,5], 0)

A : return Rect mondja meg, hogy a függvény egy téglalapot fog visszaadni, hasonlót, mint az előbb. El is felejtheted ezt a részt egyelőre.

Ami nem fog működni, az az, ha kimásolod a vonal attribútumai közül a width=0, és idézőjelbe teszed.

# Ez hibás és a számítógép hibaüzenetet küld neked, hogy
# ezt tényleg nehezen érti.
pygame.draw.rect(screen, RED, [55,500,10,5], width=0)

5.11 Vonalak rajzolása

A lenti kód megmutatja, hogyan rajzolj egy vonalat a képernyőre. Ez egy 5 pixel széles zöld vonalat fog rajzolni (0,0)-tól (100,100)-ig. Emlékezz rá, hogy a green egy változó, amit korábban már definilnod kellett RGB értékeket tartalmazó változóként.

# Egy zöld vonal kirajzolása a képernyőre (0,0)-tól (100,100)-
# ami 5 pixel széles.
pygame.draw.line(screen, GREEN, [0,0], [100,100], 5)

Használd az alap programot, és írass ki több vonalat. Olvasd el a megjegyzéseket is, hogy megértsd, hogyan működik a kód. Próbálj meg kirajzolni olyan vonalakat, amelyek eltérnek vastagságban, színben, és helyben. Rajzolj ki több vonalat!

5.12 Ciklussal kirajzolt, és eltolt vonalak

A programok képesek a dolgokat ismételni újra és újra. A következő kód egy példa arra, hogyan rajzoljunk ki vonalakat újra és újra. A programok ugyanezt a technikát használják arra, hogy többszörös vonalakat rajzoljanak, vagy hogy egy egész autót megjelenítsenek.

Egy vonal kirajzolásának a parancsát, ha egy ciklusba tesszük, akkor több vonalat fogunk kirajzolni a képernyőre. De itt a csavar. Ha minden vonalnak ugyanaz a kezdő és a végpontja, akkor egymás hegyén-hátán lesznek. Egyik eltakarja majd a másikat. És úgy tűnik majd, hogy csak egy vonalat rajzoltunk ki.

Ahhoz, hogy ezt elkerüljük, fontos, hogy eltoljuk a koordinátákat minden egyes vonal esetén a ciklusunkban. Szóval, először az y_offset változónk nulla lesz. A lenti kódban a vonal először (0,10)-től (100,110)-ig rajzolódik majd. A ciklus következő lefutáskor az y_offset változó értéke nőnni fog 10-zel, így a következő vonalunk (0,20)-tól (100,120)-ig rajzolódik majd ki. Ez fog ismétlődni, vagyis minden vonal 10 pixellel lejjebb kerül.

# A képernyőre több vonal kirajzolása (0,10)-től (100,110)-ig
# 5 pixel szélesen, ciklus alkalmazásával
y_offset = 0
while y_offset < 100:
    pygame.draw.line(screen, RED, [0,10+y_offset], [100,110+y_offset], 5)
    y_offset = y_offset + 10

Ez a fenti kód sokkal egyszerűbben is megírható, mondjuk egy for ciklussal:

# Több vonal kirajzolása a képernyőre (0,10)-től (100,110)-ig
# 5 pixel szélesen, ciklus alkalmazásával
for y_offset in range(0,100,10):
    pygame.draw.line(screen, RED, [0,10+y_offset], [100,110+y_offset], 5)

Futtasd le ezt a kódot, és próbálj ki különböző változtatásokat az eltoláshoz! Próbálj meg egy más értékekkel működő eltolást létrehozni! Gyakorolj különböző értékekkel amíg már nem lesz egyértelmá számodra, ahogyan ez a program működik!

Például, itt van egy ciklus ami a szinuszt és a koszinuszt használja ahhoz, hogy egy bonyolultabb eltolást hozzon létre, és megjelenítse az ábrán látható alakzatot. Ábra:5.7.

for i in range(200):

	radians_x = i / 20
	radians_y = i / 6

	x = int( 75 * math.sin(radians_x)) + 200
	y = int( 75 * math.cos(radians_y)) + 200

	pygame.draw.line(screen, BLACK, [x,y], [x+5,y], 5)
fig.complex_offsets
Figure 5.7: Összetett eltolás

Több elemet is rajzolhatunk egy for ciklussal, mint az alábbi példa is mutatja. Ábra 5.8.

    for x_offset in range(30,300,30):
        pygame.draw.line(screen,BLACK,[x_offset,100],[x_offset-10,90], 2 )
        pygame.draw.line(screen,BLACK,[x_offset,90],[x_offset-10,100], 2 )
fig.multiple_x
Figure 5.8: Többszörös X-k

5.13 Téglalap rajzolása

Videó: Hogyan rajzoljunk téglalapokat és ellipsziseket

Amikor téglalapot rajzolunk, olyankor a számítógépnek szüksége van a bal-felső koordinátára, és a magasságra, és a szélességre.

Az ábra 5.9 egy téglalapot szemléltet (és egy ellipszist, amit majd később elmagyarázunk), aminek az origója (20,20) -nál van, a szélessége 250, és a magassága 100. Amikor meghatározzuk a téglalapot, akkor a számítógépnek ezt a négy számot kell, megadjuk, az alábbi sorrendben: (x,y,széles,magas).

fig.ellipse
Figure 5.9: Ellipszis rajzolása

A következő kód példa arra, hogyan rajzoljunk téglalapot. Az első két szám a listában megadják a bal felső sarkát (20,20). A következő két szám pedig megadja, hogy 250 pixel széles és 100 pixel magas.

A 2 a végén pedig azt mondja meg, hogy a vonalak szélessége legyen 2 pixel. Minél nagyobb a szám, annál vastagabb a vonal. Ha a szám 0, akkor nincs határvonal az alakzatunk körül. Ehelyett azzal a színnel lesz kitöltve, amit megadtunk neki.

# Téglalap rajzolása
pygame.draw.rect(screen,BLACK,[20,20,250,100],2)

5.14 Ellipszis rajzolása

Az ellipszist hasonlóan rajzoljuk, mint a téglalapot. Megadjuk a határait, és a határain belül a számítógép kirajzolja.

A leggyakoribb hiba azt hinni, hogy a kiindulási pont az ellipszisünk középpontját adja meg. Valójában, semmi sem rajzolódik ki a kiindulási pontnál. Ugyanis ez a pont a bal felső pontja a téglalapnak, ami az ellipszisünket magába foglalja.

Vessünk egy pollantást ide: Ábra 5.9. Bárki láthatja, hogy az ellipszis 250 pixel széles, és 100 pixel magas. A bal felső sarka a (20,20)-nál van, ami a 250x100 nagyságú téglalapnak a bal felső sarka egyben. Jegyezd meg, hogy a (20,20)-nál valójában semmi sem rajzolódott ki. Ha egymásra rajzoljuk őket, akkor sokkar egyszerűbb lesz megérteni, hogy hogyan határozzuk meg egy ellipszis helyzetét.

# Kirajzolunk egy ellipszist, ehhez egy téglalap külső határait vesszük figyelembe
pygame.draw.ellipse(screen,BLACK,[20,20,250,100],2)

5.15 Ív megrajzolása

Videó: Hogyan rajzoljunk meg egy ívet?

Mi van akkor, ha egy programnál csak annyira van szükségünk, hogy az ellipszisünk egy részletét rajzoljuk ki? Ezt megtehetjük a az arc paranccsal. Ez a parancs eléggé hasonlít az ellipse parancshoz. Itt azonban szükségünk lesz az ív kezdő és végpontjára, amiket radiánsban adunk majd meg.

fig.arc
Figure 5.10: Ívek

Az alábbi kód példa arra, hogyan rajzoljunk meg négy különböző ívet, a kör négy különböző részéből. Minden negyedet más színnel jelölünk, így jobban látható. Az alábbi kód eredményét az alábbi ábrán láthatjuk: 5.10.

# Kirajzolunk egy ívet, ami egy ellipszis része. Radiánst használunk arra, hogy meghatározzuk
# milyen szögben rajzolunk.
pygame.draw.arc(screen,GREEN,[100,100,250,200],  pi/2,     pi, 2)
pygame.draw.arc(screen,BLACK,[100,100,250,200],     0,   pi/2, 2)
pygame.draw.arc(screen,RED,  [100,100,250,200],3*pi/2,   2*pi, 2)
pygame.draw.arc(screen,BLUE, [100,100,250,200],    pi, 3*pi/2, 2)

5.16 Sokszög kirajzolása

Videó: Hogyan rajzoljunk sokszögeket?

A következő sor ki fog rajzolni egy sokszöget. A háromszög alakot három ponttal definiáltuk: (100,100) (0,200) és (200,200) a csúcs. Lehetőségünk van annyi pontot megadni, amennyit csak szeretnénk. Jegyezd meg, ahogyan a pontokat listázzuk. Minden pont kettő szám listája, és a pontok maguk is bele vannak ágyazva egy másik listába, ami az összes pontot tartalmazza. Ez a kód kirajzolja azt, amit ezen az ábrán látsz: 5.11.

fig.triangle
Figure 5.11: Sokszögek
# Ez ki fog rajzolni egy sokszöget, a polygon parancs hatására
pygame.draw.polygon(screen,BLACK,[[100,100],[0,200],[200,200]],5)

5.17 Szöveg kirajzolása

Videó: Hogyan rajzoljunk ki szöveget

A szöveg sokkal bonyolultabb történet. Ehhez három dolog szükséges. Először is, a program készít egy változót, ami információt tárol arról, hogy milyen fontot fogunk hasznnálni, milyen típusú lesz a kiírás és milyen nagy.

Másodsorban a program képet készít a szövegből. Mondjuk úgy kell elképzelni, hogy a programunk kivési a betűket egy pecsétbe, amit utána tintába kell mártani és papíron kell használni.

A harmadik dolog amit meg kell tennünk, hogy meg kell mondnanunk, hogy ezzel a pecsételővel, hova pecsételjen a program a képernyőn.

Íme egy példa:

# Válaszd ki a font nagyságát. Az alapértelmezett 25 pt nagyságú betűfont.
font = pygame.font.Font(None, 25)

# Rendereld a szöveget. A "True" azt jelenti, hogy ez nem egy álneves szöveg.
# A fekete a szí. A BLACK változó definiálva lett
# a fenti listában [0,0,0]-ként
# Megjegyzés: a betűkből képet készít ez a sor,
# de nem íratja ki még őket a képernyőre.
text = font.render("My text",True,BLACK)

# A képernyőre való kiíratás, így fog történni, amennyiben a képernyő 250x250
screen.blit(text, [250,250])

Ki akarod íratni a pontszámot a képernyőre? Az még egy kicsit nehezebb. Ez nem fog működni:

text = font.render("Score: ", score, True, BLACK)

Miért? Mert a program nem képes extra dolgokat adni a font.render paranccsal úgy, mint ahogyan a print paranccsal tettük. Csak egy szöveg küldhető a parancshoz, továbbá az aktuális pontszám értéket szövegként kellene elmenteni, de még így sem működik:

text = font.render("Score: " + score, True, BLACK)

Ha a pontszám egy egész változó, akkor a számítógép nem tudja, hogyan adja azt hozzá egy szöveghez. Te, te a programozó, neked kell átváltanod a pontszámot szöveggé. És azután összeadhatod őket, valahogy így:

text = font.render("Score: " + str(score), True, BLACK)

Most már tudod, hogyan írasd ki a pontszámot. Ha ki akarnál íratni egy órát/számlálót, akkor ahhoz a kiíráatás formáját kell használnod, amiről majd később lesz szó. Nézd meg a példa kódot az online timer.py példatárban:
ProgramArcadeGames.com/python_examples/f.php?file=timer.py

5.18 Az összes program listája

Itt van az összes program listája, amiről korábban beszéltünk ebben a fejezetben. Ez a program, más programokkal együtt letölthető innen:
http://ProgramArcadeGames.com/index.php?chapter=example_code

fig.program_result
Figure 5.12: Példa program eredménye
"""
 Simple graphics demo

 Sample Python/Pygame Programs
 Simpson College Computer Science
 http://programarcadegames.com/
 http://simpson.edu/computer-science/

"""

# Import a library of functions called 'pygame'
import pygame

# Initialize the game engine
pygame.init()

# Define some colors
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
BLUE = (0, 0, 255)
GREEN = (0, 255, 0)
RED = (255, 0, 0)

PI = 3.141592653

# Set the height and width of the screen
size = (400, 500)
screen = pygame.display.set_mode(size)

pygame.display.set_caption("Professor Craven's Cool Game")

# Loop until the user clicks the close button.
done = False
clock = pygame.time.Clock()

# Loop as long as done == False
while not done:

    for event in pygame.event.get():  # User did something
        if event.type == pygame.QUIT:  # If user clicked close
            done = True  # Flag that we are done so we exit this loop

    # All drawing code happens after the for loop and but
    # inside the main while not done loop.

    # Clear the screen and set the screen background
    screen.fill(WHITE)

    # Draw on the screen a line from (0,0) to (100,100)
    # 5 pixels wide.
    pygame.draw.line(screen, GREEN, [0, 0], [100, 100], 5)

    # Draw on the screen several lines from (0,10) to (100,110)
    # 5 pixels wide using a loop
    for y_offset in range(0, 100, 10):
        pygame.draw.line(screen, RED, [0, 10 + y_offset], [100, 110 + y_offset], 5)


    # Draw a rectangle
    pygame.draw.rect(screen, BLACK, [20, 20, 250, 100], 2)

    # Draw an ellipse, using a rectangle as the outside boundaries
    pygame.draw.ellipse(screen, BLACK, [20, 20, 250, 100], 2)

    # Draw an arc as part of an ellipse.
    # Use radians to determine what angle to draw.
    pygame.draw.arc(screen, BLACK, [20, 220, 250, 200], 0, PI / 2, 2)
    pygame.draw.arc(screen, GREEN, [20, 220, 250, 200], PI / 2, PI, 2)
    pygame.draw.arc(screen, BLUE, [20, 220, 250, 200], PI, 3 * PI / 2, 2)
    pygame.draw.arc(screen, RED, [20, 220, 250, 200], 3 * PI / 2, 2 * PI, 2)

    # This draws a triangle using the polygon command
    pygame.draw.polygon(screen, BLACK, [[100, 100], [0, 200], [200, 200]], 5)

    # Select the font to use, size, bold, italics
    font = pygame.font.SysFont('Calibri', 25, True, False)

    # Render the text. "True" means anti-aliased text.
    # Black is the color. This creates an image of the
    # letters, but does not put it on the screen
    text = font.render("My text", True, BLACK)

    # Put the image of the text on the screen at 250x250
    screen.blit(text, [250, 250])

    # Go ahead and update the screen with what we've drawn.
    # This MUST happen after all the other drawing commands.
    pygame.display.flip()

    # This limits the while loop to a max of 60 times per second.
    # Leave this out and we will use all CPU we can.
    clock.tick(60)

# Be IDLE friendly
pygame.quit()

5.19 Review Questions

Click here for a multiple-choice review quiz.

Miután válaszoltál az ellenőrző kérdésekre alább, próbálj megírni egy számítógépes programot, ami egy általad elképzelt képet rajzol ki. Részletekért, látogass el ide: Create-a-Picture.

5.20 Gyakorlat

Teljesítsd a Gyakorlat-3-t “Készíts képet” készíts el egy képet, és mutasd meg, hogy megértetted a ciklusok és a grafika működését.

5.21 Áttekintés

5.21.1 Több választásos teszt

Click here for a multiple-choice quiz.

5.21.2 Rövid válaszos feladatlap

Click here for the chapter worksheet.

5.21.3 gyakorlat

Click here for the chapter lab.


You are not logged in. Log in here and track your progress.