Prijavi problem


Obeleži sve katergorije koje odgovaraju problemu

Jos 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.

Programiranje grafike pomoću Pygame, priručnik za sedmi razred

Догађаји и реаговање на њих

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

Нагласимо још и то да се догађаји региструју тек када се иницијализује библиотека PyGame (помоћу pg.init) и када се иницијализује екран (помоћу pg.display.set_mode) - док се то не уради, догађаји се неће исправно регистровати.

Постоји неколико сценарија детекције и обраде догађаја у PyGame програмима. Најбољи приступ се заснива на коришћењу функције pg.event.wait() којом се извршавање програма практично зауставља све док не наступи неки догађај.

Ову функцију смо већ користили у свим програмима које смо до сада писали. У њима смо занемаривали све догађаје осим догађаја pg.QUIT који наступа када корисник искључи прозор.

Сваки догађај чува податак о типу догађаја коме можемо приступити помоћу поља type. У претходном коду се током израчунавања услова петље while позове функција pg.event.wait() која враћа први догађај из реда или чека да се неки догађај догоди ако је ред празан. Када у реду постоји неки необрађени догађај, функција pg.event.wait() га враћа. Након тога се одмах испитује његов тип и пореди са pg.QUIT. Ако догађај није тог типа (корисник није искључио прозор), тада је услов петље испуњен, извршава се тело петље у коме се налази наредба pass која нема никаквог ефекта и поново се враћа на проверу услова у којој се обрађује наредни догађај (ако је потребно, поново се чека на њега).

У ситуацији када су нам релевантни и други догађаји, структура петље је мало другачија. Посматрајмо наредни PyGame програм у коме се само исписују информације о догађајима.

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

Структура претходне петље је таква да се у њој прихвата наредни догађај помоћу pg.event.wait. А онда се гранањем анализира тип догађаја који смо прихватили. Ако нам је релевантан само догађај искључивања прозора, тада се у гранању проверава само тип догађаја pg.QUIT. Када се тај догађај детектује, треба да прекинемо петљу (а тиме практично и програм). Један начин за то је коришћење логичке променљиве kraj, као у претходном програму.

Уместо логичке променљиве, поново смо могли употребити наредбу break.

Обе претходне варијанте остварују исти ефекат као и она коју смо користили у свим досадашњим програмима, међутим, иако су дуже и компликованије, имају предност да се лако уопштавају. Наиме, гранањем на основу типа можемо анализирати и друге типове догађаја и за сваки од типова можемо направити одговарајућу реакцију. Сваком типу догађаја тада можемо придружити једну грану у гранању који се реализује помоћу наредбе if-elif-else. Главна петља програма у којој се догађаји обрађују се тада може имплементирати на следећи начин (уместо ??? потребно је навести конкретне типове догађаја, попут KEYDOWN који се генерише притиском на неки тастер или MOUSEMOTION који се генерише када се помери миш, о којима ће више речи бити у наставку).

Реакција на догађај обично подразумева да се на екрану нешто промени, тј. да се сцена на екрану поново исцрта. Стога се код за цртање често смешта у тело главне петље (пре или после обраде догађаја), слично као што је случај и код анимација које не морају да реагују на догађаје, али такође веома често мењају слику на екрану.

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

На почетку променљива treba_crtati добија вредност True како би се у првом проласку кроз тело петље слика нацртала. Одмах након првог цртања та променљива добија вредност False. У наредним проласцима кроз петљу цртање се не врши, све док се не региструје неки догађај који проузрокује промену сцене, након чега је потребно поново је исцртати. У склопу обраде таквог догађаја променљива treba_crtati добија вредност True, и на почетку наредног проласка кроз петљу сцена се поново црта, након чега се променљива treba_crtati поново поставља на False и наредно цртање се одлаже док се поново не деси одговарајући догађај.