$$ \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.

Час 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 и не заборави да је ископираш ако покрећеш овај пример у локалу).

../_images/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.

../_images/CekicGore.png ../_images/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).

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