Loading [MathJax]/jax/output/CommonHTML/jax.js

Prijavi problem


Obeleži sve kategorije koje odgovaraju problemu

Još detalja - opišite nam problem


Uspešno ste prijavili problem!
Status problema i sve dodatne informacije možete pratiti klikom na link.
Nažalost nismo trenutno u mogućnosti da obradimo vaš zahtev.
Molimo vas da pokušate kasnije.

Час 12 - Анимације кретања

Кретање објеката по екрану

Варијације на тему лоптице која се креће

У уводном поглављу смо приказали како можемо направити анимацију лоптице која се креће са леве ка десној страни екрана. Подсетимо се.

  • Пошто се лоптица увек вертикално налази на средини екрана, довољно је да памтимо само њену координату x (то може, на пример, бити координата њеног центра, а могла би бити и, на пример, координата горњег левог темена квадрата описаног око ње). Пошто лоптица своје кретање започиње на левом крају екрана, променљиву x ћемо иницијализовати на нулу.

  • У функцији crtaj бојимо позадину екрана у бело и затим исцртавамо лоптицу коришћењем вредности њеног положаја x.

  • При преласку на сваки нови фрејм потребно је да лоптицу померимо мало (на пример, за 1 пиксел) удесно. Дакле, у функцији novi_frejm потребно је само да увећамо вредност променљиве x за 1. Пошто се мења вредност променљиве x која је глобална, у функцији novi_frejm морамо променљиву x означимо помоћу кључне речи global.

Сада ћемо тај програм модификовати тако да се лоптица која изађе на десном крају екрана појављује поново на левом крају екрана.

 
1
import pygame as pg
2
import pygamebg
3
4
(sirina, visina) = (300, 100)  # otvaramo prozor
5
prozor = pygamebg.open_window(sirina, visina, "Лоптица")
6
7
8
x = 0  # pozicija loptice
9
10
def crtaj():
11
    # crtamo lopticu
12
    prozor.fill(pg.Color("white"))
13
    pg.draw.circle(prozor, pg.Color("red"), (x, visina // 2), 30)
14
15
def novi_frejm():
16
    global x
17
    x += 1    # pomeramo lopticu za jedan piksel nadesno
18
    if x > 300:
19
        x = 0
20
    crtaj()
21
22
23
# funkcija novi_frejm se poziva 100 puta u sekundi
24
pygamebg.frame_loop(100, novi_frejm)
25

(loptica_jednostavna_1)

Мана претходног програма је то што лоптица не испадне цела са екрана пре него што се пребаци на леву страну. Такође, када се појави на левој страни, она се већ до пола види. Покушај да то поправиш.

23
 
1
import pygame as pg
2
import pygamebg
3
4
(sirina, visina) = (300, 100)  # otvaramo prozor
5
prozor = pygamebg.open_window(sirina, visina, "Лоптица")
6
7
x = 0  # pozicija loptice
8
9
def crtaj():
10
    # crtamo lopticu
11
    prozor.fill(pg.Color("white"))
12
    pg.draw.circle(prozor, pg.Color("red"), (x, visina // 2), 30)
13
14
def novi_frejm():
15
    global x
16
    x += 1    # pomeramo lopticu za jedan piksel nadesno
17
    if x > ???:
18
        x = -???
19
    crtaj()
20
21
# funkcija novi_frejm se poziva 100 puta u sekundi
22
pygamebg.frame_loop(100, novi_frejm)
23

(loptica_jednostavna_2)

Преправимо сада програм тако да лоптица промени полупречник сваки пут када се поново појави на левом крају екрана.

  • Стање програма треба проширити глобалном променљивом r.

  • У функцији crtaj потребно је цртати лоптицу полупречника r, уместо досадашњег фиксног полупречника 30.

  • У функцији novi_frejm проверу да ли је лоптица испала са екрана треба прилагодити тако да ради исправно за сваку вредност полупречника. Када лоптица испадне, нови полупречник треба одабрати насумично, из интервала [5,30] (подсети се, насумичан цео број добијамо функцијом random.randint). Пошто се у овој функцији може променити вредност глобалних променљивих x и r, потребно је навести их уз кључну реч global.

Покушај да овај и наредне програме напишеш потпуно самостално (увек проширујући и прилагођавајући претходну верзију). Ако се негде заглавиш, потражи помоћ, па онда допуни започети програмски кôд.

12
 
1
import random
2
import pygame as pg
3
import pygamebg
4
5
(sirina, visina) = (400, 100)   # otvaramo prozor
6
prozor = pygamebg.open_window(sirina, visina, "Лоптица")
7
8
9
10
# funkcija novi_frejm se poziva 100 puta u sekundi
11
pygamebg.frame_loop(100, novi_frejm)
12

(loptica_jednostavna_3)

Допуни сада програм тако да се свака нова лоптица креће различитом брзином.

  • Стање програма је потребно доупнити брзином v која представља брзину изражену у пикселима по фрејму (она мери колико се пиксела лоптица помери надесно у сваком фрејму).

  • Функцију crtaj нема потребе мењати.

  • У функцији novi_frejm, када лоптица изађе са екрана, поред промене хоризонталне позиције и насумичног одређивања полупречника, насумично јој је потребно одредити и брзину (на пример, цео број између 1 и 10). Пошто ова функција мења сада и глобалну променљиву v, и та променљива треба да буде означена кључном речју global.

12
 
1
import random
2
import pygame as pg
3
import pygamebg
4
5
(sirina, visina) = (400, 100)   # otvaramo prozor
6
prozor = pygamebg.open_window(sirina, visina, "Лоптица")
7
8
9
10
# funkcija novi_frejm se poziva 100 puta u sekundi
11
pygamebg.frame_loop(100, novi_frejm)
12

(loptica_jednostavna_4)

Допуни сада програм тако да се свака нова лоптица креће на различитој висини. Висину бирај насумично, али тако да лоптица цела буде унутар прозора.

12
 
1
import random
2
import pygame as pg
3
import pygamebg
4
5
(sirina, visina) = (400, 100)   # otvaramo prozor
6
prozor = pygamebg.open_window(sirina, visina, "Лоптица")
7
8
9
10
# funkcija novi_frejm se poziva 100 puta u sekundi
11
pygamebg.frame_loop(100, novi_frejm)
12

(loptica_jednostavna_5)

Једини параметар лоптице који се за сада никада не мења је боја. На крају, допуни програм тако да се и боја сваке нове лоптице бира насумично.

12
 
1
import random
2
import pygame as pg
3
import pygamebg
4
5
(sirina, visina) = (400, 100)   # otvaramo prozor
6
prozor = pygamebg.open_window(sirina, visina, "Лоптица")
7
8
9
10
# funkcija novi_frejm se poziva 100 puta u sekundi
11
pygamebg.frame_loop(100, novi_frejm)
12

(loptica_jednostavna_6)

Вежбе ради, измени претходни програм тако да се лоптице крећу с десна налево.

12
 
1
import random
2
import pygame as pg
3
import pygamebg
4
5
(sirina, visina) = (400, 100)   # otvaramo prozor
6
prozor = pygamebg.open_window(sirina, visina, "Лоптица")
7
8
9
10
# funkcija novi_frejm se poziva 100 puta u sekundi
11
pygamebg.frame_loop(100, novi_frejm)
12

(loptica_jednostavna_7)

Аутомобил који се креће

Напиши програм који приказује аутомобил који се креће ширином екрана. Када испадне на десном крају екрана, поново се појављује на левом крају.

Анимацију аутомобила можемо реализовати тако што ћемо га сваких неколико милисекунди померати и цртати у новом положају (на исти начин као што смо померали лоптицу).

Прикажимо прво варијанту програма у којој се приказује слика аутомобила auto.png.

../_images/auto.png
  • Стање сцене је одређено положајем аутомобила. Положај аутомобила биће одређен познавањем координата његовог горњег левог угла (њих можемо чувати коришћењем променљивих auto_x и auto_y). Поред тога, чуваћемо и саму слику аутомобила, као и променљиве којима су представљене њене димензије.

  • Цртање вршимо веома једноставно, приказивањем слике аутомобила на позицији одређеној тренутним координатама auto_x и auto_y.

  • Померање аутомобила вршићемо само по оси x. При преласку на сваки нови фрејм (у функцији novi_frejm) петље координату auto_x ћемо увећавати за одговарајући померај. За разлику од задатака у којима смо брзину кретања задавали бројем пиксела по фрејму, овај пут желимо да брзину задамо у броју пиксела у једној секунди. Да бисмо од брзине задате у пикселима по секунди добили број пиксела које аутомобил треба да се помери по сваком фрејму, потребно је да да израчунамо време dt које протекне између приказивања два узастопна фрејма. Њега лако израчунавамо на основу броја фрејмова у секунди (у питању је реципрочна вредност). Померај (пређени пут) онда израчунавамо као производ времена dt и брзине аутомобила изражене у броју пиксела у једној секунди.

    Пошто желимо да се аутомобил стално помера по екрану, приликом преласка на сваки наредни фрејм, након померања аутомобила потребно је проверити да ли је аутомобил излетео иза десне ивице екрана и ако јесте, она га пребацити на крајњи леви део екрана (иза леве ивице прозора). Сматраћемо да је ауто испао ван слике када му леви крај (одређен координатом auto_x) пређе ширину екрана (одређену променљивом sirina). Тада га враћамо тако да му десни крај буде на левој ивици екрана (леви крај му се тада налази у минусу и то тачно за ширину слике аутомобила).

На основу претходне дискусије можемо да напишемо наредни програм.

28
 
1
import pygame as pg
2
import pygamebg
3
4
(sirina, visina) = (400, 400)  # otvaramo prozor
5
prozor = pygamebg.open_window(sirina, visina, "Аутомобил")
6
7
auto_slika = pg.image.load("auto.png")   # slika automobila
8
(sirina_auta, visina_auta) = (auto_slika.get_width(), auto_slika.get_height()) # dimenzije slike automobila
9
10
auto_v = 100                   # brzina automobila (broj piksela u sekundi)
11
auto_x = 0                     # početni polozaj - x koordinata
12
auto_y = visina - visina_auta  # početni polozaj - y koordinata
13
frejmova_u_sekundi = 25        # broj frejmova u jednoj sekundi
14
dt = 1 / frejmova_u_sekundi    # vreme koje protekne između dva frejma
15
16
def crtaj():
17
    prozor.fill(pg.Color("skyblue"))            # bojimo pozadinu u nebo-plavu
18
    prozor.blit(auto_slika, (auto_x, auto_y))   # prikazujemo sliku auta
19
20
def novi_frejm():
21
    global auto_x               # menjaćemo horizontalni položaj auta
22
    auto_x += auto_v * dt       # pomeramo auto nadesno
23
    if auto_x > sirina:         # ako je ispao van prozora
24
        auto_x = - sirina_auta  #     vraćamo ga na početak
25
    crtaj()
26
27
pygamebg.frame_loop(frejmova_u_sekundi, novi_frejm)
28

(automobil_slika)

Корњача и зец

Напиши програм који приказује корњачу и зеца који полазе са два краја прозора, крећу се једно према другом (зец се креће два пута брже од корњаче) док се не сусретну, након чега се на екрану исписује порука Здраво. Можеш употребити слике kornjaca.png и zec.png.

../_images/kornjaca.png ../_images/zec.png

За разлику од претходних примера, у овом примеру вршимо анимацију два различита објекта.

  • Стање програма је одређено положајем корњаче и положајем зеца. Променљивама kornjaca_x и kornjaca_y регистроваћемо горњи леви угао слике корњаче, а променљивама zec_x и zec_y регистроваћемо горњи леви угао слике зеца. Слике зеца и корњаче учитавамо на почетку програма и региструјемо помоћу две променљиве (zec_slika и kornjaca_slika), међутим, те променљиве се не мењају током извршавања програма.

  • И цртање и померање ће зависити од тога да ли су се корњача и зец срели. Пошто корњача креће са левог, а зец са десног дела прозора, то можемо да одредимо тако што проверимо да ли је десни крај слике корњаче (који се лако може израчунати додавањем ширине слике корњаче на x координату њеног горњег левог темена) достигао леви крај слике зеца. Пошто ћемо проверу судара вршити на неколико места у програму, можемо је издвојити у засебну функцију.

  • У функцији crtaj цртамо прво небо (плави правоугаоник), земљу (зелени правоугаоник) и сунце (жути круг), чиме суштински бришемо претходни цртеж. Након тога приказујемо слике корњаче и зеца на положајима одређеним текућим стањем програма. На крају проверавамо да ли су се корњача и зец срели и ако јесу, тада на средини екрана приказујемо поздравну поруку (технику центрирања текста на екрану смо разматрали и раније).

  • У функцији novi_frejm прво проверавамо да ли су се зец и корњача срели. Ако јесу, анимација је завршена и не вршимо никакве промене. У супротном померамо корњачу на десно (увећавајући x координату њеног левог краја kornjaca_x) и зеца на лево (умањујући x координату његовог левог краја zec_x). Пошто зец треба да се креће брже од корњаче умањење треба да буде веће него увећање (на пример, у сваком фрејму зеца можемо померити два пиксела налево, а корњачу један пиксел надесно).

Допуни наредни програм на основу претходне дискусије.

44
 
1
import random
2
import pygame as pg
3
import pygamebg
4
5
(sirina, visina) = (800, 400)  # otvaramo prozor
6
prozor = pygamebg.open_window(sirina, visina, "Корњача и зец")
7
8
kornjaca_slika = pg.image.load("kornjaca.png")   # slika kornjače
9
(kornjaca_x, kornjaca_y) = (???, ???)            # pozicija njenog gornjeg levog ugla
10
zec_slika = pg.image.load("zec.png")             # slika zeca
11
(zec_x, zec_y) = (???, ???)                      # pozicija njenog gornjeg levog ugla
12
13
# funkcija koja ispisuje tekst tako da mu je centar na datoj poziciji
14
def centriraj_tekst(tekst, x, y):
15
    font = pg.font.SysFont("Arial", 40)                   # font kojim se ispisuje tekst
16
    tekst = font.render(tekst, True, pg.Color("white"))   # sličica koja sadrži ispisan tekst
17
    (sirina_teksta, visina_teksta) = (???, ???)           # dimenzije te sličice
18
    (x, y) = (x - ???, y - ???)                           # koordinate gornjeg levog ugla
19
    ???                                                   # prikazujemo tekst
20
21
# funkcija koja proverava da li su se sreli
22
def sreli_su_se():
23
    desni_kraj_kornjace = ???                     # desni kraj slike kornjače
24
    levi_kraj_zeca = ???                          # levi kraj slike zeca
25
    return desni_kraj_kornjace >= levi_kraj_zeca  # proveravamo da li su se mimiošli
26
27
def crtaj():
28
    pg.draw.rect(prozor, pg.Color("skyblue"), (0, 0, sirina, visina / 2))            # crtamo nebo
29
    pg.draw.rect(prozor, pg.Color("forestgreen"), (0, visina / 2, sirina, visina))   # crtamo zemlju
30
    pg.draw.circle(prozor, pg.Color("yellow"), (80, 80), 60)                         # crtamo sunce
31
    prozor.blit(kornjaca_slika, (kornjaca_x, kornjaca_y))                            # prikazujemo sliku kornjače
32
    ???                                                                              # prikazujemo sliku zeca
33
    if sreli_su_se():                                                                # ako su se sreli
34
        centriraj_tekst(???, ???, visina / 3)                                        #   prikazujemo tekst
35
36
def novi_frejm():
37
    global ???
38
    if not sreli_su_se():     # ako se nisu sreli
39
        kornjaca_x += 1       #    pomeramo kornjaču jedan piksel nadesno
40
        zec_x -= 2            #    pomeramo zeca dva piksela nalevo
41
    crtaj()
42
43
pygamebg.frame_loop(30, novi_frejm)
44

(kornjaca_i_zec)

Одбијање приликом судара

Стражар који патролира

Напиши програм који приказује стражара који патролира лево десно по екрану. Претпостави да на располагању имаш слике strazar_levo.png на којој је приказан стражар окренут на лево и strazar_desno.png на којој је приказан исти стражар окренут на десно.

../_images/strazar_levo.png ../_images/strazar_desno.png
  • Решење задатка је прилично слично оном у коме се ауто кретао ширином екрана. Поново стање програма садржи текућу позицију стражара. Она може, на пример, бити одређена променљивом x која региструје x координату горњег левог угла слике којој је стражар представљен, која се иницијализује на нулу и која се током анимације мења и променљивом y која се иницијално поставља тако да се стражар налази на поду, тј. тако да јој вредност буде једнака разлици висине прозора и висине слике стражара и која не мења своју вредност током извршавања анимације. Основна разлика у односу на раије примере је у томе што се стражару када дође до краја прозора не мења позиција, већ му се мења смер кретања. Зато ће стање програма бити одређено не само позицијом стражара, већ и смером његовим смером кретања. Смер може бити представљен знаком променљиве која представља брзину кретања. Претпоставићемо да брзину кретања одређује променљива dx (померај, тј. промена координате x), која може бити и позитивна и негативна.

  • При преласку на сваки нови фрејм у функцији novi_frejm x координату горњег левог угла стражара x увећавамо за dx. Ако је dx позитиван број, тада ће се x координата увећавати и стражар ће се кретати на десно. Ако је dx негативан број, тада ће се x координата умањивати и стражар ће се кретати на десно. Када стражар испадне ван екрана (када му је координата x десног краја већа од ширине екрана или му је координата x левог краја мања од нуле, тј. када је x < 0 или је x + strazar_sirina > sirina), тада му се смер кретања мења тако што се промени знак брзине dx.

  • У функцији crtaj приказујемо слику стражара тако да јој је горње лево теме буде у тачки (x, y). Пошто знак броја dx одређује и смер кретања, на основу њега одређујемо слику коју ћемо приказивати (када је вредност позитивна приказујемо слику стражара окренутог надесно, а када је негативна приказујемо слику стражара окренутог налево).

На основу претходне дискусије допуни наредни програм.

10
 
1
import pygame as pg
2
import pygamebg
3
4
(sirina, visina) = (400, 300)    # otvaramo prozor
5
prozor = pygamebg.open_window(sirina, visina, "Стражар који патролира")
6
7
8
9
pygamebg.frame_loop(50, novi_frejm)
10

(strazar_patrolira)

Авион

Напиши програм који приказује авион који полеће (из доњег левог угла прозора), пење крећући се надесно док не додирне врх прозора, затим се спушта и даље крећући се надесно док не додирне земљу и онда наставља да се креће по земљи док изађе ван прозора на његовом десном делу. Можеш употребити слику avion.png, а на небо можеш поставити слику sunce.png.

../_images/avion.png ../_images/sunce.png
  • Као и у свим анимацијама кретања објеката, део стања програма мора бити положај објекта на екрану. У овом случају положај авиона можемо регистровати променљивама avion_x и avion_y које представљају координате горњег левог угла слике авиона. Пошто се током кретања авиона мења његов смер кретања, потребно је да део стања буду и информације о правцу, смеру и брзини кретања авиона. Све ове информације могу бити представљене помоћу променљивих avion_dx и avion_dy. Број avion_dx ће представљати хоризонтални померај авиона и одређиваће за колико ће се пиксела мењати x координата авиона приликом преласка на сваки наредни фрејм. Можемо слободно рећи и да тај број изражава хоризонталну брзину авиона. Пошто се авион стално помера на десно и то увек истом брзином, ова променљива ће имати позитивну вредност и неће мењати своју вредност током рада програма. Број avion_dy ће представљати вертикалани померај авиона и одређиваће за колико ће се пиксела мењати zecy координата авиона приликом преласка на сваки наредни фрејм. Можемо слободно рећи и да тај број изражава хоризонталну брзину авиона. Ако је вредност avion_dy негативна, y координата ће се умањивати и авион ће се подизати (мање y координате су ближе врху прозора). Ако је вредност avion_dy једнака 0, то значи да авион неће мењати своју висину. Ако је вредност avion_dy позитивна, тада ће се y координата повећавати и авион ће се спуштати.

  • Функција crtaj се може имплементирати веома једноставно. Прозор се обоји у небо-плаву боју (чиме се пребрише претходни фрејм), прикаже се слика сунца (на својој фиксираној позицији) и слика авиона (на позицији одређеној променљивама avion_x и avion_y).

  • Функција novi_frejm ажурира x и y координату авиона avion_x и avion_y тако што их увећа за вредности помераја avion_dx и avion_dy. Још једна важна ствар која се у тој функцији мора решити је промена смера кретања. Приметимо да се авион хоризонтално увек креће надесно, тако да је потребно мењати само вертикални смер тј. вертикалну брзину кретања. Иницијално авион треба да се подиже тако да ће иницијална вертиална брзина avion_dy бити постављена на негативну вредност (нпр. на -1). Када врх авиона достигне врх екрана, тада авион треба да крене да се спушта, тако да ћемо му вертикалну брзину avion_dy поставити на позитивну вредност (нпр. на 1). На крају, када дно слике авиона (које можемо израчунати тако што положај врха слике авиона увећамо за висину те слике) достигне дно прозора, тада авион треба да се креће по земљи, што значи да вертикални померај avion_dy треба да постане 0.

10
 
1
import pygame as pg
2
import pygamebg
3
4
(sirina, visina) = (800, 400)    # otvaramo prozor
5
prozor = pygamebg.open_window(sirina, visina, "Авион")
6
7
8
9
pygamebg.frame_loop(50, novi_frejm)
10

(avion)

Домаћи задатак - одбијање лоптице

Напиши програм који приказује лоптицу која се креће и одбија о ивице екрана.

  • У сваком тренутку је потребно да знамо положај лоптице на екрану. То је најједноставније остварити тако што ћемо у променљивама x и y памтити координате центра лоптице (на почетку их можемо иницијализовати на половину ширине и висине, тако да се лотпица налази у центру екрана). Полупречник лоптице ћемо представити променљивом r.

Кретање лоптице се остварује тако што јој се у правилним временским интервалима мењају x и y координата. Пошто претпостављамо да је брзина константна у сваком тренутку ће промена сваке од координата бити идентична: координату x ћемо увећавати или умањивати за по 5 пиксела и координату y ћемо увећавати или умањивати за по 5 пиксела. Пошто су промене по обе координате идентичне, лоптица ће се увек кретати под углом од 45 степени у односу на ивице прозора. Промену координате x ћемо представити променљивом dx која ће имати вредност или 5 или -5, у зависности од тога да ли се лоптица креће надесно или налево. Слично ћемо употребљавати и променљиву dy. Уређени пар (dx, dy) заправо представља вектор брзине кретања лоптице. У правилним временским интервалима (на пример, на сваких 25 милисекунди) помераћемо лоптицу тако што x увећамо за dx, а y за dy.

Након сваког померања провераваћемо да ли је лоптица излетела ван граница екрана. Хоризонталну проверу можемо извршити тако што ћемо проверити да ли је леви крај лоптице лево од леве ивице екрана, или је десни крај лоптице десно од десне ивице екрана. Леви крај лоптице има x координату једнаку x-r, а десни крај има x координату једнаку x+r, па се провера своди на то да се провери да ли x-r < 0 или је x+r > sirina. Ако је то случај, тада се мења смер хоризонталног кретања тако што се промени знак вредности dx. Потпуно аналогно се врши и вертикална провера (само се уместо x користи y, уместо dx користи dy и уместо sirina користи visina).

10
 
1
import pygame as pg
2
import pygamebg
3
4
(sirina, visina) = (400, 450)    # otvaramo prozor
5
prozor = pygamebg.open_window(sirina, visina, "Лоптица")
6
7
8
9
pygamebg.frame_loop(100, novi_frejm)
10

(loptica)