6. PyGame: animeerimine
Animeerimine tähendab objektide liigutamist teise kohta e. asukoha muutmist. Tehnilises mõttes toimub animeerimine pildi või kujundi uude kohta joonistamise ja vanast kohast nö. kustutamise kaudu. Kustutamise eesmärgil täidame kogu akna uuesti taustavärviga ja joonistame kõik kujundid uuesti. Et liikumine oleks mõistliku kiirusega, peaks lisama ka viivituse.
# Täidame kogu ekraani valge värviga ekraan.fill([255, 255, 255]) pilt = pygame.image.load("pildifail.png") ekraan.blit(pilt, (300, 100)) pygame.display.flip() # 1000 millisekundi pikkuse viivituse lisamine pygame.time.delay(1000) # Täidame kogu ekraani valge värviga, et katta ära varasem pilt ekraan.fill([255, 255, 255]) # Pildi liigutamine uude kohta ekraan.blit(pilt, (350, 100)) pygame.display.flip()
Liikumise sujuvuse huvides tuleks pilti liigutada sammhaaval, seda peab kindlasti tegema tsükliga. Teeme näiteks tsükli, mis kordub 50 korda ning mille igal sammul joonistatakse valge taust, lisatakse pilt, muudetakse x-koordinaadi väärtust 5 punkti võrra ja oodatakse 50 millisekundit:
pilt = pygame.image.load("pildifail.png") x = 300 y = 100 for i in range (50): ekraan.fill([255, 255, 255]) ekraan.blit(pilt, (x, y)) pygame.display.flip() x = x + 5 pygame.time.delay(20)
Kogu programm näeks välja selline:
import pygame, sys pygame.init() ekraan = pygame.display.set_mode([800, 600]) pygame.display.set_caption("Animeerimine") pilt = pygame.image.load("pildifail.png") x = 300 y = 100 for i in range (50): ekraan.fill([255, 255, 255]) ekraan.blit(pilt, (x, y)) pygame.display.flip() x = x + 5 pygame.time.delay(20) running = True while running: for i in pygame.event.get(): if i.type == pygame.QUIT: running = False pygame.quit()
Animeerime paremini!
Eeltoodud kood töötab, kuid sellel on üks suur probleem: while-tsükli juurde (kus on kirjas käsud programmi kinnipanekuks) jõutakse alles pärast animatsiooni lõppemist, seega seni, kuni animatsioon käib, programmi sulgeda ei saa. Momendil on meie animatsioon piiratud: for-tsükkel kordub 50 korda ning me võime selle aja ära oodata. Samas me võime soovida teha ka piiramatult kestvat animatsiooni (lumesadu, palli põrkamine jne) ning siis poleks programmi normaalne sulgemine üldse võimalik. Teiseks: me vaatame järgmistes peatükkides klaviatuuri ja hiire abil juhtimist ning kõik juhtimiskäsud (analoogselt sulgemiskäsuga) peame me lisama samuti samasse while-tsüklisse, seega animatsiooni ajal ei saaks programmi tööd üldse juhtida. Seega peame animatsiooni viima alla while-tsüklisse ning igal while-tsükli sammul liigutama objekte ning samal ajal jätkuvalt kontrollima, kas programmi ei soovita sulgeda.
import pygame, sys pygame.init() ekraan = pygame.display.set_mode([800, 600]) pygame.display.set_caption("Animeerimine") pilt = pygame.image.load("pildifail.png") x = 300 y = 100 running = True while running: ekraan.fill([255, 255, 255]) ekraan.blit(pilt, (x, y)) pygame.display.flip() if x < 500: x = x + 5 pygame.time.delay(20) for i in pygame.event.get(): if i.type == pygame.QUIT: running = False pygame.quit()
Nagu näete, kopeerisime kogu varasema for-tsükli sisu while-tsüklisse, kuid kuna meil enam "liikumispiirangut" polnud (varem sai x muutuda vaid 20 korda ehk pilt liikuda 20 korda 5 punkti kaupa paremale), siis nüüd lisame ka ühe tingimuse: x muutub vaid siis, kui x väärtus on vähem kui 500.
Animatsioonikiirusest: praegu tehakse while-tsüklis ära kõik sammud (nii kiiresti, kui arvuti seda suudab) ning seejärel oodatakse 20 ms (käsk "pygame.time.delay(20)"). Momendil on meil käske vähe ning arvuti kiirus ei mängi nende täitmisel erilist rolli, kuid tulevikus (kus tingimuslauseid kontrollimiseks on palju ning ekraanipilt on palju mitmekesisem, sisaldab tausta ning erinevaid teisi elemente) on see tähtis. Näiteks kiirusel põhinevad mängud on sel juhul kiirel arvutil raskemad mängida kui aeglasel. Seepärast võime juba praegu kontrollida programmi kiirust hoopis teistmoodi, nimelt lisame enen tsüklit rea "clock = pygame.time.Clock()" (võtame kasutusele muutuja "clock") ja kirjutame while-tsükli sisse teise rea: "clock.tick(60)". Esimene neist võtab kasutusele Pygame'i sisseehitatud "kella", teine ütleb, et tsüklit (täpsemalt seda rida koodis) läbitakse võimaluse korral 60 korda sekundis (nö. "kaadrisagedus"). Arvu 60 võime vahetada mõne muu vastu. Mida suurem see on, seda kiiremini programm töötab (kuni takistuseks saab arvuti kiirus), mida väiksem, seda aeglasemalt. Varasem delay() käsk lihtsalt ootas pärast viimast tegevust ega teadnud, kaua eelmised read ise aega võtsid, uus käsk aga mõõdab aega viimasest läbimisest. Seega võime ära kustutada rea delay() käsuga. Tulemus:
import pygame, sys pygame.init() ekraan = pygame.display.set_mode([800, 600]) pygame.display.set_caption("Animeerimine") pilt = pygame.image.load("pildifail.png") x = 300 y = 100 running = True clock = pygame.time.Clock() while running: ekraan.fill([255, 255, 255]) ekraan.blit(pilt, (x, y)) pygame.display.flip() if x < 500: x = x + 5 clock.tick(60) for i in pygame.event.get(): if i.type == pygame.QUIT: running = False pygame.quit() (:codestart python gutter='false':) !Spraidid Suure hulga piltide puhul ja vajadusega nende kattumist (''collide'') tuvastada on mõistlik PyGame'is kasutada spraite (''sprite''). Iga sprait sisaldab pilti ja oma asukoha koordinaate. Spraidid võivad moodustada gruppe (''group''). (:codestart python gutter='false':) pildid = pygame.sprite.Group() # Teeb uue spraitide grupi for i in range(5): ajutinelill= pygame.sprite.Sprite() # Ajutine muutuja ühe lille spraidi jaoks ajutinelill.image= pygame.image.load("lill.png") # Spraidi pildi määramine ajutinelill.rect = ajutinelill.image.get_rect() # Spraidi ümber oleva ristküliku andmed ajutinelill.rect.topleft = (i*150, 100) # Spraidi koordinaadid pildid.add(ajutinelill) mesilane = pygame.sprite.Sprite() # Ajutine muutuja mesilase spraidi jaoks mesilane.image= pygame.image.load("mesilane.png") # Spraidi pildi määramine mesilane.rect = mesilane.image.get_rect() # Spraidi ümber oleva ristküliku andmed mesilane.rect.topleft = (0, 0) # Spraidi koordinaadid pildid.add(mesilane)
Lisamaterjalid
Creative Commons litsentsiga Autorile viitamine + Mitteäriline eesmärk 3.0 Eesti (CC BY-NC 3.0 EE) - https://creativecommons.org/licenses/by-nc/3.0/ee/