$$ \newcommand{\floor}[1]{\left\lfloor{#1}\right\rfloor} \newcommand{\ceil}[1]{\left\lceil{#1}\right\rceil} \renewcommand{\mod}{\,\mathrm{mod}\,} \renewcommand{\div}{\,\mathrm{div}\,} \newcommand{\metar}{\,\mathrm{m}} \newcommand{\cm}{\,\mathrm{cm}} \newcommand{\dm}{\,\mathrm{dm}} \newcommand{\litar}{\,\mathrm{l}} \newcommand{\km}{\,\mathrm{km}} \newcommand{\s}{\,\mathrm{s}} \newcommand{\h}{\,\mathrm{h}} \newcommand{\minut}{\,\mathrm{min}} \newcommand{\kmh}{\,\mathrm{\frac{km}{h}}} \newcommand{\ms}{\,\mathrm{\frac{m}{s}}} \newcommand{\mss}{\,\mathrm{\frac{m}{s^2}}} \newcommand{\mmin}{\,\mathrm{\frac{m}{min}}} \newcommand{\smin}{\,\mathrm{\frac{s}{min}}} $$

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.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Корњача и зец

Напиши програм који приказује корњачу и зеца који полазе са два краја прозора, крећу се једно према другом (зец се креће два пута брже од корњаче) док се не сусретну, након чега се на екрану исписује порука Здраво. Можеш употребити слике 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). Пошто зец треба да се креће брже од корњаче умањење треба да буде веће него увећање (на пример, у сваком фрејму зеца можемо померити два пиксела налево, а корњачу један пиксел надесно).

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

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

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

Напиши програм који приказује стражара који патролира лево десно по екрану. Претпостави да на располагању имаш слике 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 одређује и смер кретања, на основу њега одређујемо слику коју ћемо приказивати (када је вредност позитивна приказујемо слику стражара окренутог надесно, а када је негативна приказујемо слику стражара окренутог налево).

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

Авион

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

../_images/avion.png ../_images/sunce.png
  • Као и у свим анимацијама кретања објеката, део стања програма мора бити положај објекта на екрану. У овом случају положај авиона можемо регистровати променљивама avion_x и avion_y које представљају координате горњег левог угла слике авиона. Пошто се током кретања авиона мења његов смер кретања, потребно је да део стања буду и информације о правцу, смеру и брзини кретања авиона. Све ове информације могу бити представљене помоћу променљивих avion_dx и avion_dy. Број avion_dx ће представљати хоризонтални померај авиона и одређиваће за колико ће се пиксела мењати \(x\) координата авиона приликом преласка на сваки наредни фрејм. Можемо слободно рећи и да тај број изражава хоризонталну брзину авиона. Пошто се авион стално помера на десно и то увек истом брзином, ова променљива ће имати позитивну вредност и неће мењати своју вредност током рада програма. Број avion_dy ће представљати вертикалани померај авиона и одређиваће за колико ће се пиксела мењати \(zec_y\) координата авиона приликом преласка на сваки наредни фрејм. Можемо слободно рећи и да тај број изражава хоризонталну брзину авиона. Ако је вредност 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.

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

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

  • У сваком тренутку је потребно да знамо положај лоптице на екрану. То је најједноставније остварити тако што ћемо у променљивама 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).