Час 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_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
.
Као и у свим анимацијама кретања објеката, део стања програма мора бити положај објекта на екрану. У овом случају положај авиона можемо регистровати променљивама
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
).