Ügyességi játékok programozása
Pythonnal és Pygame-melChapter 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:
- A számítógép hogyan kezeli az x, y koordinátákat? Ez nem ugyanaz, mint amit matekból tanultunk.
- Hogyan adjunk/határozzunk meg színeket? Milliónyi szín közül választhatunk, és ez sokszor nem csak abból áll, hogy azt mondjuk a gépnek, hogy vörös.
- Hogyan lehet üres ablakot nyitni a rajzoláshoz? Minden művésznek szüksége van vászonra.
- Hogyan rajzoljunk vonalakat, háromszögeket, elipsziseket, és íveket.
5.1 A számítógép koordináta rendszere
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:
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.
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.
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.
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.
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
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:
- grafikai alakzatok rajzolására
- Bit-térképes képek megjelenítésére
- Animációhoz
- Egér, gamepad, billentyűzet interakciójára
- Zene lejátszására
- Észrevenni mikor egy objektum összeomlik
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.
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/
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
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:
- Amíg nem teljesül hogy (while):
- Addig (for) minden esemény (billentyűlenyomás, egérgomb, stb.):
- Használj egy sor if feltételes parancsot, hogy a kódod minden eseményt kezeljen.
- Futtass számításokat, hogy meghatározd azt, hogy merre mozognak a tárgyak, vagy mi történik velük, stb.
- Takarítsd le a képernyőt!
- Írass ki mindent !
- Addig (for) minden esemény (billentyűlenyomás, egérgomb, stb.):
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)
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)
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 )
5.13 Téglalap rajzolása
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).
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
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.
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
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.
# 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
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
""" 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.
English version by Paul Vincent Craven
Spanish version by Antonio Rodríguez Verdugo
Russian version by Vladimir Slav
Turkish version by Güray Yildirim
Portuguese version by Armando Marques Sobrinho and Tati Carvalho
Dutch version by Frank Waegeman
Hungarian version by Nagy Attila
Finnish version by Jouko Järvenpää
French version by Franco Rossi
Korean version by Kim Zeung-Il
Chinese version by Kai Lin