Arvutiteaduse instituut
  1. Esileht
  2. Python koolis
EN
Logi sisse

Python koolis

  • Sissejuhatus
  • Teemad
  • PyGame

1. Aken
2. Värvid ja koordinaadid
3. Joonistamine
4. Pildid
5. Tekst
6. Animeerimine
7. Juhtimine klaviatuuriga
8. Juhtimine hiirega
9. Heli
10. Õpetusi

  • ÜLESANDED

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

  • Spraidid: http://www.pygame.org/docs/ref/sprite.html

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/

  • Arvutiteaduse instituut
  • Loodus- ja täppisteaduste valdkond
  • Tartu Ülikool
Tehniliste probleemide või küsimuste korral kirjuta:

Kursuse sisu ja korralduslike küsimustega pöörduge kursuse korraldajate poole.
Õppematerjalide varalised autoriõigused kuuluvad Tartu Ülikoolile. Õppematerjalide kasutamine on lubatud autoriõiguse seaduses ettenähtud teose vaba kasutamise eesmärkidel ja tingimustel. Õppematerjalide kasutamisel on kasutaja kohustatud viitama õppematerjalide autorile.
Õppematerjalide kasutamine muudel eesmärkidel on lubatud ainult Tartu Ülikooli eelneval kirjalikul nõusolekul.
Courses’i keskkonna kasutustingimused