Час 14 - Догађаји миша и тастатуре¶
Као што је то обично случај у програмима са графичким корисничким интерфејсом и PyGame програми врше интеракцију са корисником коришћењем догађаја. Наиме, сваки пут када корисник помери миша, притисне неко дугме миша или тастер на тастатури систем то бележи у облику догађаја који се региструје у нашем програму и на шта можемо одреаговати извршавањем неког програмског кода.
Обрада догађаја у свим програмима које ћемо писати ће се заснивати на
постојању функције obradi_dogadjaj
чији ће задатак бити да
анализира сваки догађај који се десио и да на основу тога промени
стање програма (представљено најчешће преко глобалних
променљивих). Информације о сваком догађају упаковане су у објекат
dogadjaj
који ће се аутоматски прослеђивати као аргумент ове
функције.
Поред функције obradi_dogadjaj
дефинисаћемо и функцију crtaj
чији ће задатак бити да исцрта прозор на основу текућег стања
програма. Пошто ћемо многе догађаје игнорисати (на пример, у неком
програму ћемо реаговати само на померање миша, а не и на тастере
тастатуре), неће бити потребе да се сцена поново исцртава након сваког
догађаја. Зато ћемо усвојити конвенцију да функција
obradi_dogadjaj
враћа логичку вредност којом се назначава да ли је
потребно поново исцртати сцену.
Постоји неколико начина да се у програму реализује реаговање на
догађаје и о њима више можеш прочитати овде. Ми ћемо користити библиотеку
PyGameBg у којој ће се догађаји обрађивати у главној петљи која се
покреће функцијом pygamebg.event_loop
чији су параметри функција
за цртање crtaj
и функција обраде догађаја obradi_dogadjaj
.
Типови догађаја¶
Функција obradi_dogadjaj
као аргумент прима догађај који се десио
и потребно је прво да утврди његов тип (да ли је то био притисак неког
тастера на тастатури, клик неког дугмета миша, померање миша и
слично). Сваки догађај чува податак о типу догађаја коме можемо
приступити помоћу поља type
и стога ће се у функцији
obradi_dogadjaj
најчешће вршити гранање на основу вредности овог
поља. У програмима заснованим на коришћењу библиотеке PyGameBg, обрада
догађаја ће најчешће функционисати на следећи начин.
Догађаји тастатуре¶
Сваки пут када корисник притисне и када отпусти неки тастер на
тастатури региструје се догађај. За сваки клик тастером догоде се два
посебна догађаја: pg.KEYDOWN
и pg.KEYUP
.
У склопу обраде догађаја притиска тастера, често нас занима да сазнамо
који је тастер притиснут. Догађај типа pg.KEYDOWN
податак о томе
чува у пољу key
, па ако је догађај сачуван у променљивој
dogadjaj
, анализом вредности dogadjaj.key
можемо одредити који
је тастер притиснут и реаговати на одговарајући начин. Ако је
притиснута нека од стрелица, dogadjaj.key
ће имати вредности
pg.K_LEFT
(стрелица на лево), pg.K_RIGHT
(стрелица на десно),
pg.K_UP
(стрелица на горе) или pg.K_DOWN
(стрелица на доле).
Сличне константе постоје и за друге тастере (на пример, за слова
можемо користити pg.K_a
, pg.K_b
, …, pg.K_z
).
Бојење круга тастатуром¶
Напиши програм који ће цртати круг на центру екрана који ће бити обојен док је неки тастер притиснут.
Контролу да ли круг треба или не треба да буде обојен вршићемо помоћу глобалне логичке променљиве
obojen
.У функцији
crtaj
ћемо цртати круг, чија ће дебљина зависити од вредности глобалне променљивеobojen
. Подсетимо се, дебљина 0 означава да круг треба да буде испуњен.Приликом сваког догађаја типа
pg.KEYDOWN
променљивојobojen
ћемо додељивати вредностTrue
, а приликом сваког догађаја типаpg.KEYUP
вредностFalse
.
Покушај да модификујеш претходни програм тако што ћеш док је тастер притиснут уместо црвеног круга цртати плави квадрат. Покушај да га модификујеш тако да реагује само на притисак и отпуштање тастера за размак.
Шетање лоптице тастатуром¶
Напиши програм у којем корисник шета лоптицу по екрану тастатуром.
Стање програма је одређено положајем лоптице. Помоћу две глобалне променљиве
x
иy
памтићемо тренутни положај центра лоптице на екрану (иницијализоваћемо их тако да се лоптица налази у центру екрана). Променљиваr
садржаће полупречник лоптице, али се она неће мењати током рада програма.У функцији
crtaj
бојићемо позадину прозора у бело (да би се обрисао његов претходни садржај) и исцртаваћемо плаву лоптицу на положају одређеном текућим стањем програма (вредностима променљивихx
иy
).Догађаје ћемо обрађивати у посебној функцији
obradi_dogadjaj
. Приликом сваког притиска на тастер стрелице, координатаx
или координатаy
центра лоптице треба за мало да се промени (увећа или умањи, у зависности од тога која је стрелица притиснута). То колико ће се мало лоптица померити одређено је променљивамаdx
иdy
(поставићемо их обе на 10 пиксела). Када притиснемо стрелицу на десно, тада увећавамо променљивуx
за вредностdx
. Слично, када притиснемо стрелицу на лево, тада умањујемо променљивуx
заdx
, када притиснемо стрелицу на горе тада умањујемо променљивуy
заdy
, а када притиснемо стрелицу на доле, тада увећавамо променљивуy
заdy
.
Решење са речником¶
Уместо гранања којим испитујемо која стрелица је притиснута, можемо направити речник који сваком тастеру придружује уређен пар који представља померај обе координате који се додаје на текуће координате центра лоптице када се тај тастер притисне.
Tада се реакција на притисак тастера може реализовати веома једноставно.
Шетање свемирског брода¶
Додатно, уместо цртања лоптице можемо да шетамо неку сличицу по екрану
и тиме добијемо основу неке једноставне игрице. То, на пример, може
бити следећи свемирски брод (слика се зове spaceship.png
и не
заборави да је ископираш ако покрећеш овај пример у локалу).
Сударање са ивицама¶
Модификуј програм у којем се шетала лоптица тако да сваки пут када лоптица удари у ивицу екрана, она мења боју на насумичан начин.
Стање програма проширујемо глобалном променљивом
boja
која ће садржати боју лоптице (она ће бити постављена насумично, помоћу функцијеnasumicna_boja
која је већ имплементирана у „сивом коду”).Функцију
crtaj
ћемо модификовати тако да у обзир узме и вредност променљивеboja
.Након сваке промене положаја центра лоптице (што се дешава у склопу обраде догађаја), треба проверити да ли је она испала ван граница екрана и ако јесте, вратити је и променити јој боју. Притиском стрелица на десно лоптица која је била на екрану је могла испасти једино преко десне ивице екрана. Зато је приликом реакције на догађај притиска тог тастера довољно само проверити да ли је десни крај лоптице десно од десне ивице екрана тј. да ли је вредност
x + r
већа од ширине екрана тј. вредности променљивеsirina
. Ако јесте, тадаx
можемо поставити наsirina - r
(што је најдешњи положај лоптице у коме се она још налази на екрану) и променити јој насумично боју. Веома слично, приликом реаговања на догађај притиска стрелице на лево умањиваћемоx
заdx
, проверавати да ли јеx - r
постало негативно и ако јесте постављатиx
наr
и лоптици мењати боју. Аналогно ћемо поступати и у случају друге две стрелице (једино што ћемо тада мењатиy
заdy
).
Догађаји миша¶
Као и тастатура и миш има дугмад и за њих постоје догађаји притиска и
догађаји отпуштања дугмета: pg.MOUSEBUTTONDOWN
и
pg.MOUSEBUTTONUP
. Реаговање на њих је веома слично као што је
реаговање на догађаје тастатуре pg.KEYDOWN
и pg.KEYUP
. Миш
често има три дугмета (лево, средње и десно) и клик на било које од
њих генерише поменута два догађаја. Ови догађаји садрже следећа
поља.
Поље
dogadjaj.button
може да садржи број од 1 до 5 и означава које дугме миша је притиснуто (1 - лево, 2 - средње, 3 - десно, 4 - скрол на горе, 5 - скрол на доле).Поље
dogadjaj.pos
садржи уређени пар координата тачке на којој је дугме притиснуто.
Поред догађаја притиска на дугме, приликом померања миша генерише се
догађај pg.MOUSEMOTION
. Заправо, током померања миша генерише се
више оваквих догађаја (сваки од њих описује неко мало померање миша у
неком веома кратком временском интервалу, тако да сваки такав догађај
обично описује померање тек за неколико пиксела). Ови догађаји садрже
следећа поља.
Позицију миша након померања можемо одредити помоћу
dogadjaj.pos
, које садржи уређени пар координата на којима се миш нашао након померања.Поље
dogadjaj.rel
садржи уређени пар који описује колико се током тог једног померања миша позиција променила (тај пар представља разлику између крајње и почетне координате \(x\) и крајње и почетне \(y\) координате).Поље
dogadjaj.buttons
садржи трочлану листу логичких вредности које за свако од три дугмета миша одређују да ли је било притиснуто током померања миша.
Дан и ноћ¶
Напиши програм који приказује небо и то ако је дан, плаво са жутим сунцем у горњем левом углу, а ако је ноћ, онда црно са 100 белих звездица насумично распоређених по њему. Када се клинке мишем било где на прозор, дан се мења у ноћ, а ноћ у дан.
Стање програма биће одређено логичком променљивом
dan
која ће имати вредностTrue
ако и само ако је тренутно дан.У функцији за цртање вршићемо гранање на основу вредности те променљиве и цртамо плаво небо са сунцем тј. црно небо са звездицама (њих цртамо у петљи и положај им одређујемо насумично).
У функцији обраде догађаја проверавамо да ли је у питању догађај притиска дугмета миша
pg.MOUSEBUTTONDOWN
и ако јесте, мењамо вредност логичке променљивеdan
(гранањем, или још лакше помоћу оператора негацијеnot
).
Боја позадине мишем¶
Напиши програм који мења боју позадине екрана у зависности од положаја миша. Што се миш налази ближе десној ивици прозора, то је више црвене боје, а што је ближе доњој ивици прозора, то је више плаве боје. Зелена компонента је стално на нули.
Глобално стање програма биће одређено променљивама
crvena
иplava
које имају вредности између 0 и 255 и одређују количину црвене тј. плаве светлости у тренутној боји позадине.Функција
crtaj
ће бити веома једноставна - бојиће позадину прозора на основу вредности променљивихcrvena
иplava
.У овом задатку не реагујемо на клик миша, него на свако померање миша (догађај
pg.MOUSEMOTION
). Из позиције на којој се миш налази тј. пољаdogadjaj.pos
издвајамо координатеx
иy
и на основу њих одређујемо боју тј. ажурирамо вредности глобалних променљивихcrvena
иplava
. Нијансу цврене боје одређујемо коришћењем линеарне функције која ће бити таква да \(x\) координату нула пресликава у интензитет боје нула, а \(x\) координату једнаку ширини екрана пресликава у 255. Ту функцију је лако конструисати - координатуx
делимо са ширином екрана и множимо са 255 (наравно, заокружимо резултат на цео број). Потпуно аналогно, на основу y координате одређујемо нијансу плаве боје.
На основу претходне дискусије допуни наредни програм.
Чекић¶
Направи програм у коме мишем помераш чекић по екрану. Чекић је у
подигнутом положају, а када притисне дугме миша чекић се
спусти. Можеш употребити слике CekicGore.png
и
CekicDole.png
.
Стање програма биће одређено положајем центра чекића који ће бити одређен вредностима променљивих
mis_x
иmis_y
. Слике ћемо учитати у уређени парmis_slika
(прво чекић горе, затим чекић доле), а слику коју тренутно треба приказати ћемо одређивати на основу вредности променљивеi_slika
(њена вредност 0 ће указивати на то да треба нацртати чекић горе, а 1 да треба нацртати чекић доле).У функцији
crtaj
бојићемо позадину екрана у светло-плаво (да би се обрисала претходна слика) и приказиваћемо одговарајућу слику (елемент параmis_slika
на позицијиi_mis
) тако да јој се центар налази на позицији(mis_x, mis_y)
(подсетимо се, треба одредити положај горњег-левог угла слике и то се ради тако што се од центра слике одузме пола њене ширине тј. висине).У функцији за обраду догађаја ћемо реаговати на притисак тастера миша (догађај
pg.MOUSEBUTTONDOWN
) и тада ћемо променљивојi_mis
додељивати вредност 1, како би се приказивао спуштен чекић, на отпуштање тастера миша (догађајpg.MOUSEBUTTONUP
) и тада ћемо променљивојi_mis
додељивати вредност 0, како би се приказивао подигнут чекић и на померање миша (догађајpg.MOUSEMOTION
) и тада ћемо променљивеmis_x
иmis_y
ажурирати на основу очитаног положаја миша (вредностиdogadjaj.pos
).
Покушај да на основу претходне дискусије самостално напишеш програм, а ако видиш да ти је помоћ потребна, затражи је.