Час 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.
Стање сцене је одређено положајем аутомобила. Положај аутомобила биће одређен познавањем координата његовог горњег левог угла (њих можемо чувати коришћењем променљивих
auto_xиauto_y). Поред тога, чуваћемо и саму слику аутомобила, као и променљиве којима су представљене њене димензије.Цртање вршимо веома једноставно, приказивањем слике аутомобила на позицији одређеној тренутним координатама
auto_xиauto_y.Померање аутомобила вршићемо само по оси x. При преласку на сваки нови фрејм (у функцији
novi_frejm) петље координатуauto_xћемо увећавати за одговарајући померај. За разлику од задатака у којима смо брзину кретања задавали бројем пиксела по фрејму, овај пут желимо да брзину задамо у броју пиксела у једној секунди. Да бисмо од брзине задате у пикселима по секунди добили број пиксела које аутомобил треба да се помери по сваком фрејму, потребно је да да израчунамо времеdtкоје протекне између приказивања два узастопна фрејма. Њега лако израчунавамо на основу броја фрејмова у секунди (у питању је реципрочна вредност). Померај (пређени пут) онда израчунавамо као производ временаdtи брзине аутомобила изражене у броју пиксела у једној секунди.Пошто желимо да се аутомобил стално помера по екрану, приликом преласка на сваки наредни фрејм, након померања аутомобила потребно је проверити да ли је аутомобил излетео иза десне ивице екрана и ако јесте, она га пребацити на крајњи леви део екрана (иза леве ивице прозора). Сматраћемо да је ауто испао ван слике када му леви крај (одређен координатом
auto_x) пређе ширину екрана (одређену променљивомsirina). Тада га враћамо тако да му десни крај буде на левој ивици екрана (леви крај му се тада налази у минусу и то тачно за ширину слике аутомобила).
На основу претходне дискусије можемо да напишемо наредни програм.
Корњача и зец¶
Напиши програм који приказује корњачу и зеца који полазе са два
краја прозора, крећу се једно према другом (зец се креће два пута
брже од корњаче) док се не сусретну, након чега се на екрану
исписује порука Здраво. Можеш употребити слике kornjaca.png
и 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 на којој је приказан исти стражар окренут на
десно.
Решење задатка је прилично слично оном у коме се ауто кретао ширином екрана. Поново стање програма садржи текућу позицију стражара. Она може, на пример, бити одређена променљивом
xкоја региструје x координату горњег левог угла слике којој је стражар представљен, која се иницијализује на нулу и која се током анимације мења и променљивомyкоја се иницијално поставља тако да се стражар налази на поду, тј. тако да јој вредност буде једнака разлици висине прозора и висине слике стражара и која не мења своју вредност током извршавања анимације. Основна разлика у односу на раије примере је у томе што се стражару када дође до краја прозора не мења позиција, већ му се мења смер кретања. Зато ће стање програма бити одређено не само позицијом стражара, већ и смером његовим смером кретања. Смер може бити представљен знаком променљиве која представља брзину кретања. Претпоставићемо да брзину кретања одређује променљиваdx(померај, тј. промена координате x), која може бити и позитивна и негативна.При преласку на сваки нови фрејм у функцији
novi_frejmx координату горњег левог угла стражараxувећавамо заdx. Ако јеdxпозитиван број, тада ће се \(x\) координата увећавати и стражар ће се кретати на десно. Ако јеdxнегативан број, тада ће се \(x\) координата умањивати и стражар ће се кретати на десно. Када стражар испадне ван екрана (када му је координата \(x\) десног краја већа од ширине екрана или му је координата \(x\) левог краја мања од нуле, тј. када јеx < 0или јеx + strazar_sirina > sirina), тада му се смер кретања мења тако што се промени знак брзинеdx.У функцији
crtajприказујемо слику стражара тако да јој је горње лево теме буде у тачки(x, y). Пошто знак бројаdxодређује и смер кретања, на основу њега одређујемо слику коју ћемо приказивати (када је вредност позитивна приказујемо слику стражара окренутог надесно, а када је негативна приказујемо слику стражара окренутог налево).
На основу претходне дискусије допуни наредни програм.
Авион¶
Напиши програм који приказује авион који полеће (из доњег левог
угла прозора), пење крећући се надесно док не додирне врх прозора,
затим се спушта и даље крећући се надесно док не додирне земљу и
онда наставља да се креће по земљи док изађе ван прозора на његовом
десном делу. Можеш употребити слику avion.png, а на небо можеш
поставити слику 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).