68
UNIVERZA V LJUBLJANI PEDAGOŠKA FAKULTETA DIPLOMSKO DELO Dejan Dobnikar

diplomsko delo dejan dobnikar v5a - uni-lj.si

  • Upload
    others

  • View
    1

  • Download
    0

Embed Size (px)

Citation preview

UNIVERZA V LJUBLJANI

PEDAGOŠKA FAKULTETA

DIPLOMSKO DELO

Dejan Dobnikar

UNIVERZA V LJUBLJANI

PEDAGOŠKA FAKULTETA

Študijski program: Matematika in računalništvo

GEOMETRIJSKA PREDSTAVA TRIDIMENZIONALNEGA

PROSTORA S POMOČJO PRENOSNIH NAPRAV

DIPLOMSKO DELO

Mentor: prof. dr. Jože Rugelj

Kandidat: Dejan Dobnikar

Ljubljana, november 2012

I

Zahvala

Posebej se zahvaljujem svojemu mentorju, prof. dr. Jožetu Ruglju, za strokovno pomoč in usmerjanje pri izdelavi diplomske naloge.

Zahvaljujem se vsem prijateljem, ki so bili pripravljeni posoditi svoje tablične računalnike, da sem lahko preizkusil delovanje igre na različnih napravah. Prav tako se zahvaljujem vsem, ki so igro preizkušali in podali svoje mnenje o možnih izboljšavah.

Zahvaljujem se prof. Alenki Jurančič, prof. Francki Planinc, prof. Jožici Mlakar Broder in prof. Goranu Vujoviću, da so si vzeli čas, preizkusili igro in podali mnenje.

Zahvala gre tudi dr. Zlatanu Magajni za pomoč pri vsebini igre.

Za konec bi se zahvalil tudi vsem, ki so me spodbujali pri pisanju diplomske naloge.

II

Povzetek

V diplomskem delu se posvetim vprašanju, ali lahko računalniške igre, ki so sicer zelo popularne, povežemo z učenjem. Poizkušam odgovoriti na vprašanja, kot so: Ali pri igrah poteka učenje? Kako pri igrah poteka učenje? Ali bi lahko izdelali igro, ki bi se navezovala na katero izmed poglavij, obravnavanih v šoli, in bila še vedno zanimiva za igranje? Nato je na podlagi tega opisana zasnova, načrt in izdelava igre, ki deluje na napravah z operacijskim sistemom Android.

V uvodu so predstavljeni cilji, v drugem poglavju pa govorim o igrah in povezavi z učenjem. Posebej opišem principe učenja, ki so sicer značilni za učne ure v šoli, najdemo jih pa tudi v računalniških igrah. Tretje poglavje govori o zasnovi igre. Tu predstavim idejo igre ter vse funkcije, ki jih igra vsebuje. V tem poglavju tudi opišem orodja, ki jih potrebujemo za izdelavo Android aplikacij. V četrtem poglavju si pogledamo nekaj posebnosti, ki jih moramo vedeti, preden začnemo z izdelavo aplikacij. Predstavim programski jezik in način izdelave čisto osnovne aplikacije, nato pa se lotim izdelave igre. Za večino delov igre predstavim načrt in izdelavo, na koncu pa te dele še povežemo v celoto, ki je predstavljena v petem poglavju.

Obiskal sem tudi profesorje osnovnih in srednjih šol, da sem pridobil nekaj mnenj o igri. Mnenja so zbrana v šestem poglavju.

Ključne besede: izobraževanje, 3D, prostor, geometrijska, predstava, tridimenzionalni prostor, Android, izdelava, igre, programski jezik, Java, programiranje

ACM klasifikacija:

C. Computer Systems Organization C.3 SPECIAL-PURPOSE AND APPLICATION-BASED SYSTEMS

Real-time and embedded systems: Android naprave D. Software

D.1 PROGRAMMING TECHNIQUES D.1.5 Object-oriented Programming

D.3 PROGRAMMING LANGUAGES D.3.2 Language Classifications

Object-oriented languages: Java K. Computing Milieux

K.3 COMPUTERS AND EDUCATION Computer-managed instruction (CMI)

J. Computer Applications J.1 ADMINISTRATIVE DATA PROCESSING

Education

III

Abstract

The thesis is devoted to the question of whether we can look for parallels between computer games, which are otherwise very popular, and learning. It tries to answer questions such as: Is a learning process present during gaming? How does it happen? Is it possible to make a game that would be connected to certain courses discussed at school and still be interesting to play? Based on the findings, the thesis describes the design, outline and production of a game that works on Android devices.

The introduction presents objectives, while the second chapter speaks about games and their relation to learning. A special emphasis is given to the description of principles of learning that are otherwise characteristic of school lessons, but can also be found in computer games. The third chapter describes the design of the game. The idea of the game is thoroughly presented, as well as the included functions. This chapter also speaks about the tools needed to create Android applications. The fourth chapter contains some of the features we need to know before making an application. The programming language and the production of a basic application are presented, followed by the process of building the actual game. The thesis then presents the outline and making of various parts of the game, with the organization of these parts into a whole being described in the fifth chapter.

I have also visited elementary and secondary school professors to gather opinions on the game. These are collected in the sixth chapter.

Key words: education, 3D, space, geometric, presentation, three-dimensional space, Android, making of, games, programming language, Java, programming

ACM classification:

C. Computer Systems Organization C.3 SPECIAL-PURPOSE AND APPLICATION-BASED SYSTEMS

Real-time and embedded systems: Android devices D. Software

D.1 PROGRAMMING TECHNIQUES D.1.5 Object-oriented Programming

D.3 PROGRAMMING LANGUAGES D.3.2 Language Classifications

Object-oriented languages: Java K. Computing Milieux

K.3 COMPUTERS AND EDUCATION Computer-managed instruction (CMI)

J. Computer Applications J.1 ADMINISTRATIVE DATA PROCESSING

Education

IV

Kazalo vsebine

1 Uvod ................................................................................................................... 1

1 Računalniške igre ............................................................................................... 2

1.1 Igre in učenje ...................................................................................................... 3

1.2 Principi učenja v dobrih video igrah .................................................................... 4

2 Zasnova igre ...................................................................................................... 5

2.1 Liki ...................................................................................................................... 6

2.2 Načini igre .......................................................................................................... 9

2.3 Stopnje in zahtevnost ....................................................................................... 10

2.4 Tretja dimenzija ................................................................................................ 10

2.5 Dodatne zahteve .............................................................................................. 10

2.6 Okolje, kjer bo igra delovala ............................................................................. 11

2.7 Priprava delovnega okolja – SDK, IDE, ADT .................................................... 13

3 Izdelava igre ..................................................................................................... 15

3.1 Programski jezik ............................................................................................... 15

3.2 Predstavitev in posebnosti platforme Android .................................................. 16

3.2.1 Različne verzije sistema Android ............................................................. 16

3.2.2 Življenjski cikel programa ......................................................................... 17

3.2.3 Podpora za več jezikov ............................................................................ 19

3.2.4 Podpora različnim dimenzijam in gostotam zaslonov ............................... 20

3.3 Načrt in izdelava ............................................................................................... 21

3.3.1 Glavni meni .............................................................................................. 21

3.3.2 Priprava objektov - Lik .............................................................................. 22

3.3.3 Priprava objektov – Seznam likov ............................................................ 29

3.3.4 Priprava objektov – Sistem preverjanja mrež ........................................... 37

3.3.5 Sestavljanje objektov v celoto .................................................................. 40

4 Končni rezultat ................................................................................................. 50

5 Mnenja ............................................................................................................. 54

6 Zaključek .......................................................................................................... 58

7 Viri .................................................................................................................... 58

V

Kazalo slik

Slika 1: igra Tennis for Two iz leta 1958 na osciloskopu [1] ....................................... 2

Slika 2: prikaz števila igralcev pri ponudniku iger Steam [3] ....................................... 3

Slika 3: ideja igre ........................................................................................................ 5

Slika 4: liki v igri (posnetek) ........................................................................................ 6

Slika 5: Eclipse IDE .................................................................................................. 13

Slika 6: ADT vtičnik doda tudi pripomoček za uporabniške vmesnike ...................... 14

Slika 7: virtualna Android naprava ............................................................................ 15

Slika 8: dedovanje lastnosti razredov ....................................................................... 16

Slika 9: življenjski cikel programa ............................................................................. 18

Slika 10: testni program ............................................................................................ 19

Slika 11: struktura projekta ....................................................................................... 20

Slika 12: uporaba dveh različnih uporabniških vmesnikov v istem programu ........... 21

Slika 13: diagram glavnega menija ........................................................................... 21

Slika 14: jezik igre se razlikuje glede na jezik telefona ............................................. 22

Slika 15: definicija razreda Lik in njegovih podrazredov ........................................... 23

Slika 16: vektorski produkt ........................................................................................ 26

Slika 17: lepljenje likov.............................................................................................. 32

Slika 18: vrtenje likov ................................................................................................ 36

Slika 19: glavni del igre ............................................................................................. 40

Slika 20: meni igre .................................................................................................... 50

Slika 21: navodilo naloge .......................................................................................... 50

Slika 22: sestavljena mreža piramide ....................................................................... 50

Slika 23: zapiranje mreže v geometrijsko telo ........................................................... 51

Slika 24: sporočilo, da je naloga končana................................................................. 51

Slika 25: stopnja z dvema nalogama ........................................................................ 51

Slika 26: mreža tristrane prizme ............................................................................... 52

Slika 27: animacija zapiranja tristrane prizme ........................................................... 52

Slika 28: možnosti animacije .................................................................................... 53

Slika 29: neprosojne stranice .................................................................................... 53

Slika 30: okvir geometrijskega telesa ....................................................................... 54

Kazalo tabel

Tabela 1: delež operacijskih sistemov pametnih telefonov (podatki v milijonih) [9] .. 12

Tabela 2: prodani tablični računalniki (podatki v milijonih) [10] ................................. 12

Tabela 3: Verzije sistema Android in razširjenost po verzijah [18] ............................ 16

1

1 Uvod Prepričan sem, da je že vsakdo opazoval otroka pri igranju računalniških iger. Marsikdo je tudi opazil, da otroci porabijo za igranje veliko časa, bolj pozorni opazovalci pa so tudi opazili, da so te igre dolge in zahtevne, celo (ali pa še posebej) za odraslega, vendar je vsak otrok pripravljen vložiti svoj čas in se spopasti z izzivi, ki ga čakajo med igranjem. In kar je najpomembneje, pri tem zelo uživa!

Iz tega izhaja tudi moja ideja za diplomsko nalogo, ki sem jo dobil, ko sem opazoval nekega otroka, ki je starše prosil za njihov mobilni telefon, da bi igral igre. Namen diplomske naloge je narediti igro, ki bi posredno ali neposredno pomagala učencem pri katerem izmed obravnavanih poglavij v osnovni ali srednji šoli. Pri tem pa igra ne sme biti samo digitalna oblika učbenika ali delovnega zvezka.

Cilj igre je ozko usmerjen; igra bo poizkušala izboljšati predstavo tridimenzionalnega prostora. To je problem, ki sem ga opazil med prakso v osnovni šoli, predvsem pri individualni pomoči, ter pri inštrukcijah srednješolcev. Ta problem se med drugimi pokaže pri geometriji v prostoru ter kasneje v srednji šoli pri vektorjih v prostoru. Zaznava tridimenzionalnega prostora pa ni problem samo pri učencih, ampak, kot se je izkazalo pri začetnem testiranju ideje, tudi pri odraslih. Zato ciljna skupina niso samo učenci, ampak vse generacije.

Zasnova igre ter sam potek izdelave sta predstavljena kasneje, najprej pa bom poizkušal ovreči prepričanje (in dokazati nasprotno) mnogih, da so računalniške igre, ki jih igrajo otroci, namenjene samo zabavi, da so izguba časa, da pri igranju iger proces učenja ne poteka ter da igre povečujejo socialno odtujenost.

Ker obstaja tudi zelo široka izbira naprav in operacijskih sistemov, kjer bi igra lahko delovala, bom izbor opisal in tudi utemeljil svojo izbiro.

V diplomski nalogi želim doseči naslednje cilje:

• Izboljšati predstavo tridimenzionalnega prostora s pomočjo računalniške igre • Izbrati primerne tehnične pripomočke in okolje, kjer bo igra delovala

Raziskovalna vprašanja:

• Kako z uporabo IKT izboljšati predstavo tridimenzionalnega prostora

2

1 Računalniške igre Zgodovina komercialnih video iger sega v sedemdeseta in osemdeseta leta prejšnjega stoletja, prve igre pa so se pojavile v petdesetih letih. Leta 1952 je igro Križci in krožci naredil A. S. Douglas za svoje diplomsko delo, leta 1958 pa je William Higinbotham s pomočjo osciloskopa in analognega računalnika naredil igro za dva igralca Tennis for Two.

Slika 1: igra Tennis for Two iz leta 1958 na osciloskopu [1]

V sedemdesetih in osemdesetih letih so bile popularne video konzole za televizije. Takrat so se tudi izoblikovali številni žanri iger, kot so akcijske, pustolovske, dirkaške, strateške in simulacijske igre, vendar pa so se igre, kot jih poznamo danes, pojavile v devetdesetih letih, ko so postali procesorji in grafične kartice zmogljivejši in dostopnejši.

S tem se je hitro povečevalo tudi število igralcev, katerih števila ni mogoče natančno določiti, so pa zanimivi nekateri podatki:

• Trenutno ima igra World of Warcraft 9,1 milijona igralcev [2] • Samo v tem trenutku (17. 8. 2012, 14:10) pri ponudniku iger Steam igra

3.257.271 igralcev sočasno (več različnih iger) [3] • Povprečna starost igralca iger je 30 let in igra že 12 let [4] • 47% vseh igralcev je ženskega spola [4] • 62% vseh igralcev igra igre skupaj z drugimi, osebno ali preko spleta [4] • 33% jih igra igre na svojih telefonih [4] • 64% uporabnikov mobilnih telefonov igra igre vsak dan [5] • 52% igralcev iger na mobilnih telefonih igra več kot eno uro dnevno [5] • Najpopularnejša igra na mobilnih telefonih, Angry Birds, je od leta 2009

dosegla več kot 700 milijonov prenosov in prinese 6 milijonov dolarjev zaslužka mesečno [5]

3

Slika 2: prikaz števila igralcev pri ponudniku iger Steam [3]

Poudariti je treba, da poleg zgoraj omenjenih iger obstaja na trgu še ogromno drugih iger, ki se sicer ne približajo tem rekordom, a imajo še vedno zelo veliko število igralcev.

Ob zgornjih podatkih lahko zaključimo, da imajo igre nekatere elemente, ki jih naredi zanimive in zaradi katerih igre (vsaj nekatere) zelo počasi izgubljajo število igralcev.

1.1 Igre in učenje

Čeprav je veliko ljudi mnenja, da so računalniške igre nekoristne ali celo »zapravljanje časa«, igre pravzaprav vsebujejo veliko lastnosti, ki so pomembne tudi pri učenju. Prva lastnost iger, ki jo opazimo, je moč, s katero igra drži igralca pred računalnikom. Povprečen igralec iger lahko brez premora igra igro tudi po več ur. Druga pomembna lastnost iger je zahtevnost. Vsakdo, ki je kdaj igral igre, lahko potrdi, da so nekatere igre zelo zahtevne in zaradi tega mora igralec veliko časa tudi trenirati spretnosti, ki jih potrebuje za nadaljevanje. Igra mora imeti pravo ravnovesje zahtevnosti, saj prelahka igra ne nudi izziva, medtem ko pretežka igra prepriča igralca, da napredovanje ni mogoče. Tretja lastnost je nagrajevanje napredovanja. Ta lastnost je pomembna v povezavi z drugo lastnostjo, saj nagrade pogosto motivirajo igralce, da ne obupajo na stopnji, ki je na videz zahtevna. Poleg tega igre različno nagrajujejo igralce glede na vložen trud in dobljen rezultat, kar je le še dodatna motivacija za igralce. Četrta lastnost iger je takojšnja povratna informacija, zaradi katere igralec takoj ve, kaj je v igri pravilno in kaj ne. To je lastnost, ki je v učilnicah težko dosegljiva zaradi večjega števila učencev. Poleg tega igre prepričajo igralca, da vedno obstaja rešitev ter da je sposoben samostojno rešiti zahtevane naloge.

4

In če nadaljujemo v tej smeri, lahko opišemo nekaj principov učenja v dobrih video igrah.

1.2 Principi učenja v dobrih video igrah

Najpogostejši principi učenja, ki jih najdemo tudi v video igrah, so: [7]

Princip aktivnega učenja in učenja z refleksijo

Okolje mora biti pripravljeno tako, da spodbuja aktivno učenje ter učenje z refleksijo. Okolje v igri je lahko poljubno, ustvarimo lahko interaktiven 2D ali 3D svet, lahko je domišljijski, brez omejitev resničnega sveta. Tako ni nobenih omejitev za pripravo okolja, ki bi takšno učenje spodbujal.

Princip vaje

Igralec igre vadi v kontekstu, kjer vaja ni dolgočasna. V dobrih video igrah so tudi pogosto ponavljajoča se dejanja zabavna, in če mora igralec ponavljati določeno nalogo, da v igri napreduje, zakaj ne bi tej nalogi dodali izobraževalnega namena?

Princip dosežkov

Nagrajevanje, prilagojeno učenčevemu znanju in trudu, ki sporoča trenutne dosežke, je v učilnici težko izvedljivo. Video igre pa lahko ponujajo zelo dobro okolje, kjer je to mogoče doseči, saj je lahko igralna izkušnja vsakega igralca unikatna, igralec je v centru svojega napredovanja, igranje oz. reševanje problemov pa ni omejeno s časom. V povezavi s prejšnjim principom pa lahko ponavljajočo se vajo časovno vedno bolj omejujemo.

Režim kompetenc

Učenec dobi veliko priložnosti za delovanje znotraj, a na meji svojih zmožnosti, da dobi občutek, da so stvari zahtevne, a ne neizvedljive.

Princip raziskovanja

Učenje je cikel raziskovanja, refleksije, na podlagi tega formiranje hipoteze, ponovnega raziskovanja in testiranje hipoteze in nato sprejetje ali spreminjanje hipoteze. Ta cikel uporabljamo tudi v dobrih igrah, kjer je treba reševati probleme za napredovanje.

Princip več poti

Vedno obstaja več poti za napredovanje. To omogoča učencem, da se sami odločajo in zanašajo na svoje lastno znanje ter stil učenja in reševanja problemov, lahko pa tudi raziskujejo alternativne stile učenja.

Pri zasnovi igre, ki bi uporabljala ta naigralec ne more rešiti določobtiči na isti točki igre. Da pa bi spodbudili igralca, da bi se vraga poskusil rešiti, bi omogoč

Princip stopnjevanja

Učenje mora biti stopnjevano tako, da zauporabne za kasnejše primere. znanje ali spretnost, vendar tak na

Princip večmodalnosti

Pomen in znanje sta zgrajena skozi razliinterakcije, zvok, itd.

Iz zgoraj opisanih principov lahko vidimo, da tako oddaljene od video igre, ki bi lahko predstavljala odlipoglavja, ki jih danes učenci obravnavajo v šoli.

2 Zasnova igre Namen igre je, kot je bilo omenjeno v uvodu, pomotridimenzionalnega prostora. iz osnovnih likov. Uporabnik bo moral izbrati potrebne like, jmogoče tudi zavrteti, da bodo liki skupaj predstavljali mrežo telesa. Mreže nekaterih likov je mogoče sestaviti na vepredstava prostora, saj je treba

5

Pri zasnovi igre, ki bi uporabljala ta način, bi lahko dodali možnost, da igralec ne more rešiti določenega problema, lahko rešuje drug problem in tako ne

ki igre. Da pa bi spodbudili igralca, da bi se vračal k temu problemu in kusil rešiti, bi omogočili določene nagrade le v primeru, da reši vse stopnje.

enje mora biti stopnjevano tako, da začetni primeri vodijo do posplošitev, ki so uporabne za kasnejše primere. Podobno velja za igre, kjer je prav tako znanje ali spretnost, vendar tak način najdemo le v začetnih fazah igre.

Pomen in znanje sta zgrajena skozi različne modalnosti – slike, besedila, simbole,

zgoraj opisanih principov lahko vidimo, da video igre, ki jih ljudje igrajo, sploh niso tako oddaljene od video igre, ki bi lahko predstavljala odlično učno okolje za nekatera

čenci obravnavajo v šoli.

Namen igre je, kot je bilo omenjeno v uvodu, pomoč pri tridimenzionalnega prostora. Glavna ideja igre temelji na sestavljanju mrež poliedrov

Uporabnik bo moral izbrati potrebne like, jih pravilno razporediti in da bodo liki skupaj predstavljali mrežo telesa. Mreže nekaterih

e sestaviti na več načinov. Za reševanje teh nalog je potrebna treba dvodimenzionalni sliki dodati tretjo dimenzijo

Slika 3: ideja igre

in, bi lahko dodali možnost, da v primeru, ko lahko rešuje drug problem in tako ne

al k temu problemu in ene nagrade le v primeru, da reši vse stopnje.

do posplošitev, ki so Podobno velja za igre, kjer je prav tako treba osvojiti

etnih fazah igre.

slike, besedila, simbole,

video igre, ki jih ljudje igrajo, sploh niso no okolje za nekatera

č pri prepoznavi Glavna ideja igre temelji na sestavljanju mrež poliedrov

ih pravilno razporediti in da bodo liki skupaj predstavljali mrežo telesa. Mreže nekaterih

inov. Za reševanje teh nalog je potrebna tjo dimenzijo.

6

Igra bi morala vsebovati čim več različnih likov, kar bi tudi omogočalo sestavo veliko različnih mrež teles, vendar se bom omejil na šest različnih likov: enakostranična trikotnika dveh velikosti, kvadrata dveh velikosti, enakokraki trikotnik in pravokotnik. Stranice likov so dolge eno enoto ali enoto in pol.

Slika 4: liki v igri (posnetek)

2.1 Liki

S temi šestimi liki lahko sestavimo naslednje kombinacije teles in mrež:

Prizme

Trije mali kvadrati, dva mala enakostranična trikotnika:

Trije pravokotniki, dva mala enakostranična trikotnika:

7

Dva enakokraka trikotnika, dva pravokotnika, en mali kvadrat:

Dva enakokraka trikotnika, dva velika kvadrata, en pravokotnik:

Trije pravokotniki, dva mala enakostranična trikotnika:

Dva velika enakostranična trikotnika, trije pravokotniki:

8

Dva velika enakostranična trikotnika, trije veliki kvadrati:

Piramide

En mali kvadrat, štirje mali enakostranični trikotniki:

En mali kvadrat, štirje enakokraki trikotniki:

Štirje (mali ali veliki) enakostranični trikotniki:

9

En mali enakostranični trikotnik, trije enakokraki trikotniki:

En pravokotnik, dva velika enakostranična trikotnika, dva enakokraka trikotnika

2.2 Načini igre

Predvidenih je več načinov igre. Prvi način je podoben igri s kartami Remi. Igralci dobijo začetne karte, nato pa izmenično kupujejo karte, na katerih so liki. Ko igralec drži karte, iz katerih lahko sestavi mrežo telesa, te karte položi odprte na mizo. Karte, ki so na mizi, lahko igralec vzame tudi nazaj, če lahko iz njih in svojih kart sestavi več teles. Zmaga igralec, ki se prvi znebi kart. Nasprotnik je lahko program sam, ali pa igralec, ki se poveže k igri s pomočjo tehnologije Bluetooth.

Drugi predvideni način igre je časovno neomejeno napredovanje skozi vnaprej pripravljene stopnje. V primeru, da uporabnik ne bo znal rešiti naloge, bo dovoljeno napredovanje po stopnjah, vendar ne več kot dve ali tri stopnje. Tako se bo uporabnik moral vračati in rešiti tudi stopnjo, ki jo je izpustil.

Tretji predvideni način igre je igra na čas. V igri bo navodilo za sestavljanje mrež, uporabnik pa bo moral nalogo izpolniti v danem času.

Četrti način igre, ki sem ga predvidel, pa je večigralski način, ki bo temeljil na drugem in tretjem načinu igre. Igralci bodo tekmovali med seboj, dosežki pa se bodo točkovali glede na uspeh igralcev. Igralec, ki bo prvi zaključil nalogo, bo dobil vse predvidene točke. Od tega trenutka bodo imeli preostali igralci na voljo še nekaj časa, da zaključijo nalogo. Če jim to uspe, bodo nagrajeni z delom točk, ki bo odvisen od časa, ki ga bodo porabili. Uporabniku bo preostal čas viden, saj se bo v ozadju čas odšteval.

10

Režim kompetenc, opisan v prejšnjem poglavju, bi lahko dodali v igro tako, da bi se meril čas reševanja, nato pa bi se na podlagi tega izbirala naslednja stopnja. Primer: uporabniku, ki bi zelo hitro rešil neko stopnjo, bi igra izbrala težjo naslednjo stopnjo kot uporabniku, ki je porabil več časa.

Najprej bom implementiral tretji način igre, ki bo imel zaradi demonstracijskih namenov izklopljeno funkcijo odštevanja časa. Nato bom vključil še četrti način igre, saj je ta način najbolj zanimiv zaradi možnosti tekmovanja med različnimi uporabniki. Funkcija, ki bi upoštevala režim kompetenc, bi zahtevala zelo veliko število nalog, poleg tega bi pa moral še izmeriti povprečje reševanja nalog pri različnih uporabnikih ter določiti standarde za vsako nalogo posebej, poleg tega pa bi moral še upoštevati, da niso vsi uporabniki enako spretni pri uporabi elektronskih naprav.

2.3 Stopnje in zahtevnost

Zahtevnost igre je ključnega pomena. Igra, ki ne predstavlja izziva, ni zanimiva za uporabnike. Prav tako ni zanimiva igra, ki je preveč zahtevna. Zato bodo prve stopnje zelo lahke, nato pa se bo z vsako stopnjo zahtevnost povečala. Nekatere naloge bodo zahtevale samo točno določeno geometrijsko telo ali več teles, druge pa eno ali več točno določenih mrež telesa. Zato bo treba zgraditi sistem, v katerega bo mogoče na enostaven način dodajati in spreminjati stopnje, v ozadju pa bo moral delovati univerzalen sistem preverjanja pravilnosti reševanja stopenj.

2.4 Tretja dimenzija

Da bo igra omogočala predstavo tridimenzionalnega prostora, bo potrebna animacija, ki bo jasno prikazala, kako se liki, ki so narisani v dveh dimenzijah, zavrtijo, da nastane polieder. Za to bo potrebna transformacija iz dvodimenzionalnega prostora, v katerem se bodo sestavljale mreže teles, v tridimenzionalni prostor, v katerem bodo potekale animacije zapiranje teles.

2.5 Dodatne zahteve

V dvodimenzionalnem pogledu bo treba like zložiti skupaj, da bodo predstavljali mrežo telesa. Liki bodo morali biti natančno zloženi eden ob drugem. Da bo to mogoče, bodo morali biti liki »lepljivi«: Lik, ki se bo približal drugemu liku dovolj blizu, se bo moral sam poravnati. Da bo možno zlepiti med seboj kvadrat in trikotnik, bo potrebna tudi možnost rotacije likov.

Potreben bo tudi sistem preverjanja sestavljenih likov. Vsakič, ko bomo zlepili med seboj like, bo treba preveriti, ali sestavljeni liki že predstavljajo kako mrežo telesa.

11

Potrebno bo razpoznavanje vsake mreže posebej, da bomo iz nje sestavili podatke o animaciji, ki se bo izvajala v tridimenzionalnem načinu. Animacija bi se morala odvijati v obe smeri – lik bi se moral tako zapirati kot odpirati, z možnostjo začasne ustavitve animacije. Potrebne bodo tudi dodatne črte ali predmeti, ki bi pomagali pri zaznavi prostora.

V tridimenzionalnem načinu je predvidena tudi možnost povečave in obračanja pogleda, da bo postavitev likov oz. stranic telesa jasno prikazana. Interakcija, ki bo potekala s prsti na zaslonih, občutljivih na dotik, bo morala biti zelo intuitivna, da bo uporaba čim bolj preprosta. Možna bo uporaba več dotikov naenkrat, npr. pri povečavi.

Sama igra zasnova igre bi morala biti modularna, da bi bilo dodajanje novih likov in nalog možno s posodabljanjem igre in ne s ponovnim prenosom, saj je v prihodnosti predvideno dodajanje novih likov in novih nalog. Igra bo morala biti tudi večjezično zasnovana, da bo mogoča čim širša uporaba igre.

2.6 Okolje, kjer bo igra delovala

Možnost izbire okolja, v katerem bi igra delovala, je velika. Na področju namiznih in prenosnih računalnikov se najpogosteje uporabljajo operacijski sistemi Windows (Microsoft), Linux (odprtokodni operacijski sistem) in Mac OS (Apple). Na področju tabličnih računalnikov in pametnih telefonov pa so najbolj razširjeni operacijski sistemi Android (Google), iOS (Apple), Windows Phone (Microsoft), manj pa Symbian (Nokia), Bada (Samsung) in Blackberry OS (RIM).

Odločil sem se, da bo igra delovala na pametnih telefonih in tabličnih računalnikih. Razlogov za to je več: pametni telefoni in tablični računalniki si operacijski sistem delijo (Android, iOS), zato aplikacije delujejo na obeh tipih naprav. Te naprave omogočajo boljšo interakcijo, saj računalniško miško nadomestijo dotiki zaslona, ki lahko zaznavajo do deset dotikov naenkrat. Ker so vgrajeni senzorji, je možna uporaba naprave glede na naklon in nagib, tablični računalniki imajo v primerjavi s prenosnimi računalniki nekajkrat boljšo avtonomijo, so veliko lažji in manjši ter zato tudi lažje prenosljivi.

Poleg tega mora biti operacijski sistem tudi čim bolj razširjen, da ima čim več uporabnikov teh naprav možnost preizkusa igre.

12

Operacijski sistem

Q2 2012 Pošiljk na trg

Q2 2012 Tržni delež

Q2 2011 Pošiljk na trg

Q2 2011 Tržni delež

Sprememba

Android 104.8 68.1% 50.8 46.9% 106.5%

iOS 26.0 16.9% 20.4 18.8% 27.5%

BlackBerry OS 7.4 4.8% 12.5 11.5% -40.9%

Symbian 6.8 4.4% 18.3 16.9% -62.9%

Windows Phone 7 5.4 3.5% 2.5 2.3% 115.3%

Linux 3.5 2.3% 3.3 3.0% 6.3%

Ostali 0.1 0.1% 0.6 0.5% -80.0%

Skupaj 154.0 100.0% 108.3 100.0% 42.2%

Tabela 1: delež operacijskih sistemov pametnih telefonov (podatki v milijonih) [9]

Tabela 2: prodani tablični računalniki (podatki v milijonih) [10]

Iz teh tabel lahko razberemo, da je operacijski sistem Android v prednosti pri mobilnih telefonih, medtem ko je pri 68,7 milijona prodanih tabličnih računalnikov v letu 2011v prednosti podjetje Apple s sistemom iOS.

Če primerjamo še cene tabličnih računalnikov, so v prednosti naprave, na katerih deluje operacijski sistem Android. Ker so te naprave dostopnejše, so v splošnem tudi bolj primerne za širšo uporabo, npr. v šolah in podobnih ustanovah, kjer je treba zagotoviti vsakemu uporabniku svoj tablični računalnik. Pri tem pa je treba še preveriti, ali za tablične računalnike, ki jih nameravamo kupiti, obstaja programska oprema, ki je ključna za naše delo.

Zaradi razširjenosti in dostopnosti naprav sem se odločil, da bo igra delovala na pametnih telefonih in tabličnih računalnikih s sistemom Android.

13

2.7 Priprava delovnega okolja – SDK, IDE, ADT

Preden začnemo z delom, moramo pripraviti delovno okolje in namestiti vse potrebno za razvijanje programske opreme za platformo Android.

SDK

SDK je kratica za software development kit, ali po slovensko komplet programskih orodij za razvijanje programske opreme. Namestiti moramo dva, in sicer najprej Java JDK [12], nato pa še Android SDK [13]. Oba paketa dobimo brezplačno na spletnih straneh [12][13].

IDE

IDE je kratica za integrated development environment, ali po slovensko razvojno okolje. Je programska oprema, ki jo uporabljamo za razvijanje programov. Najbolj razširjeno razvojno okolje za programski jezik Java je Eclipse, ki ga moramo prenesti iz uradne spletne strani [14] in namestiti. Eclipse je odprtokodno razvojno okolje in zaradi tega brezplačno.

Za programski jezik Java so na voljo tudi druga razvojna okolja, vendar je za Eclipse na voljo vtičnik (plugin), ki nam olajša razvoj Android aplikacij.

Slika 5: Eclipse IDE

14

ADT

Android Development Tools [15] je vtičnik za Eclipse IDE. ADT razširi zmožnosti razvojnega okolja Eclipse in nam omogoča pripravo Android projektov, pomaga zgraditi uporabniški vmesnik aplikacije in omogoči razhroščevanje aplikacij (angleško debugging) [17]. Poleg tega vsebuje še virtualno Android napravo oz. Android emulator, s katero lahko testiramo svojo aplikacijo, če nimamo na voljo telefona ali tabličnega računalnika. Uporabimo ga lahko za simulacijo klicanja in pošiljanja SMS sporočil in za simulacijo prenosa podatkov. Virtualna naprava ima nekaj pomanjkljivosti, kot so počasno delovanje, nezmožnost zaznavanja več dotikov hkrati in pomanjkanje podpore tehnologiji Bluetooth, in zaradi tega v nekaterih primerih ni primerna za resno testiranje, vendar je v veliko pomoč možnost nastavljanja različnih dimenzij zaslonov. Tako lahko preverimo, kako bi bil program videti na drugih napravah. To je zelo pomembno pri razvijanju aplikacij, pri katerih moramo sami upoštevati število točk na zaslonu.

Celoten seznam funkcij, ki niso podprte v virtualni napravi, lahko najdete na spletni strani developer.android.com [16].

Slika 6: ADT vtičnik doda tudi pripomoček za uporabniške vmesnike

15

Slika 7: virtualna Android naprava

Ko imamo vse to nameščeno, smo pripravljeni za delo.

3 Izdelava igre

3.1 Programski jezik

Za programiranje Android aplikacij uporabljamo programski jezik Java, možna pa je tudi uporaba programskih jezikov C ali C++, ki se uporabljata (za celotno aplikacijo ali pa samo del nje), kadar želimo doseči veliko hitrost izvajanja programov. A glede na dokumentacijo [11] njuna uporaba ne prinese vedno opazne pohitritve, poveča pa kompleksnost aplikacije. Priporočljiva je uporaba za operacije, ki zelo obremenijo CPE (centralno procesno enoto), npr. za procesiranje signalov, simulacijo vpliva fizike in za stiskanje slik.

Java je programski jezik, ki podpira objektno orientiran pristop k programiranju. Tak pristop nam omogoča modularno strukturo programiranja in preprosto ponovno uporabo obstoječe kode. Pri objektno orientiranem programiranju uporabljamo objekte kot instance razredov, kjer so definirane spremenljivke in metode. Razredi lahko dedujejo lastnosti drugih razredov. Spremenljivke in metode, definirane v razredih, so lahko dveh vrst: statične in dinamične. Dinamične spremenljivke

16

pripadajo vsaki instanci razreda posebej, medtem ko so statične spremenljivke skupne vsem instancam razredov. Podobno je s statičnimi in dinamičnimi metodami.

Slika 8: dedovanje lastnosti razredov

Na zgornji sliki imamo štiri razrede. Razred Vozilo vsebuje podatka o barvi vozila in o imenu lastnika, vsebuje pa tudi metodo za zagon motorja. Razredi Avto, Tovornjak in Motorno kolo razširjajo razred Vozilo. To pomeni, da razred Avto deduje lastnosti razreda Vozilo in poleg podatkov o številu vrat in velikosti prtljažnika vsebuje še podatka o barvi in lastniku ter metodo za zagon motorja.

3.2 Predstavitev in posebnosti platforme Android

3.2.1 Različne verzije sistema Android

Pri izdelavi programske opreme za platformo Android je treba poznati nekaj posebnosti, ki se nanašajo na mobilne naprave. Najprej moramo paziti na veliko število verzij sistema Android, saj se ta zelo hitro razvija.

Trenutna verzija je Android 4.1, spodnja tabela pa prikazuje razširjenost po verzijah.

Verzija Kodno ime API Razširjenost (4. September 2012)

Razširjenost (1. maj 2012)

1.5 Cupcake 3 0,2% 0,3% 1.6 Donut 4 0,4% 0,7% 2.1 Eclair 7 3,7% 5,5% 2.2 Froyo 8 14% 20,9% 2.3 – 2.3.2 Gingerbread 9 0,3% 0,5% 2.3.3 – 2.3.7 10 57,2% 63,9% 3.1 Honeycomb 12 0,5% 1,1% 3.2 13 1,6% 2,2% 4.0 – 4.0.2 Ice Cream Sandwich 14 0,1% 0,5% 4.0.3 – 4.0.4 15 20,8% 4,4% 4.1 Jelly Bean 16 1,2% Izšel julija 2012

Tabela 3: Verzije sistema Android in razširjenost po verzijah [18]

17

Igra mora biti kompatibilna s čim večjim številom naprav, zato bomo pazili, da bo delovala vsaj na verziji 2.2 in kasnejših. S tem bo igra delovala na 95% vseh naprav. Igra bo lahko delovala tudi na verziji 2.1, vendar zaradi omejene podpore sledenju več dotikom na nekaterih napravah med razvijanjem igre ne bom osredotočen na to verzijo.

3.2.2 Življenjski cikel programa

Naslednja stvar, na katero moramo biti pozorni, je življenjski cikel programa.

Osnovni gradnik, tisto, kar vidimo na zaslonu, se v platformi Android imenuje Activity [19]. Vsak program, ki vsebuje tudi uporabniški vmesnik, vsebuje tudi vsaj en Activity, ki skrbi za življenjski cikel programa ter za kreiranje okna in postavitev uporabniškega vmesnika, ki ga določimo, v to okno.

Pot do prvega programa je preprosta, v razvojnem okolju Eclipse ustvarimo nov Android projekt, v katerega dodamo svoj razred, ki razširja razred Activity (rečemo lahko tudi, da je ta razred podrazred razreda Activity).

public class myActivity extends Activity {

@Override

public void onCreate(Bundle savedInstanceState) {// OBVEZNO

super.onCreate(savedInstanceState); // KLIC METODE onCreate V RAZREDU ACTIVITY

setContentView(R.layout.activity_my); // DOLOČIMO UPORABNIŠKI VMESNIK

}

// PRIMERNO ZA SHRANJEVANJE PODATKOV

@Override

public void onPause() {

super.onPause();

} // PRIMERNO ZA BRANJE SHRANJENIH PODATKOV

@Override

public void onResume() {

super.onResume();

}

@Override

public void onRestart() {

super.onRestart();

}

@Override

public void onStart() {

super.onStart();

}

@Override

public void onStop() {

super.onStop();

}

@Override

public void onDestroy() {

super.onDestroy();

}

}

V naš razred moramo vključob zagonu in kreiranju programa. V vmesnik, ki si ga bomo ogledali kasneje. PriporoonPause(); tu je potrebno shranjevati podatke, ki bi jih ob programa spet potrebovali. programa, so razložene v naslednjem diagramu.spremembi življenjskega cikla, moramo poklicati tudi istoimensko metodo v glavnrazredu.

18

V naš razred moramo vključiti vsaj metodo onCreate(), kjer določob zagonu in kreiranju programa. V tem primeru samo določvmesnik, ki si ga bomo ogledali kasneje. Priporočljivo je vključ

tu je potrebno shranjevati podatke, ki bi jih ob naslednjem zagonu programa spet potrebovali. Vse te metode, ki se izvajajo skozi življenjski cikel programa, so razložene v naslednjem diagramu. V vsaki metodi, ki spremembi življenjskega cikla, moramo poklicati tudi istoimensko metodo v glavn

Slika 9: življenjski cikel programa

kjer določimo kaj se zgodi samo določimo uporabniški

ljivo je vključiti tudi metodo naslednjem zagonu

skozi življenjski cikel V vsaki metodi, ki se izvede ob

spremembi življenjskega cikla, moramo poklicati tudi istoimensko metodo v glavnem

Uporabniški vmesniki so obiprimeru activity_my.xml:

<RelativeLayout xmlns:android xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" <TextView

android:layout_width android:layout_height android:layout_centerHorizontal android:layout_centerVertical android:padding="@dimen/padding_medium" android:text="@string/hello_world" tools:context=".myActivity" </RelativeLayout>

Če preizkusimo zgornji program, je na telefonu

3.2.3 Podpora za več

Podpora za več jezikov je pri sistemu Android zelo preprosta. shranjevati v datoteko strings.xmlnaslednji strani), gradniki uporabniškega vmbesedila v datoteki strings.xmlbesedila v privzetem jeziku, npr. v anglešslovenski jezik, ustvarimo mapo z imenom strings.xml, v kateri so slovenski prevodi. Podobno lahkoustvarimo mapo values in ji dodamo 3166-1. Program bo sam prepoznal jezik telefona in uporabljal ustrezne prevode,pa prevodi ne obstajajo, uporablja privzeta besedila, shranjena v mapi

Primer: Referenca do besedila v datoteki uporabniškega vmesnika):

19

običajno definirani v datotekah s končnico activity_my.xml:

xmlns:android="http://schemas.android.com/apk/res/android""http://schemas.android.com/tools"

"match_parent"

"match_parent" >

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_centerHorizontal="true"

android:layout_centerVertical="true"

"@dimen/padding_medium"

"@string/hello_world"

".myActivity" />

izkusimo zgornji program, je na telefonu videti tako:

Slika 10: testni program

Podpora za več jezikov

jezikov je pri sistemu Android zelo preprosta. Vsa besedila moramo strings.xml v mapi values (glej sliko struktu

), gradniki uporabniškega vmesnika pa morajo vsebovati referenco do strings.xml Priporočljivo je, da so v mapi values

besedila v privzetem jeziku, npr. v angleščini. Če pa želimo dodati prevode za slovenski jezik, ustvarimo mapo z imenom values-sl, v katero shranimo datoteko

, v kateri so slovenski prevodi. Podobno lahko za katerikoli jezikin ji dodamo dvočrkovno oznako države po standardu

. Program bo sam prepoznal jezik telefona in uporabljal ustrezne prevode,pa prevodi ne obstajajo, uporablja privzeta besedila, shranjena v mapi

Primer: Referenca do besedila v datoteki strings.xml

: android:text="@string/hello_world"

čnico .xml, v našem

"http://schemas.android.com/apk/res/android"

Vsa besedila moramo (glej sliko strukture projekta na

esnika pa morajo vsebovati referenco do values shranjena

e pa želimo dodati prevode za ero shranimo datoteko

za katerikoli jezik države po standardu ISO

. Program bo sam prepoznal jezik telefona in uporabljal ustrezne prevode, če pa prevodi ne obstajajo, uporablja privzeta besedila, shranjena v mapi values.

(Glej definicijo

20

Vsebina datoteke strings.xml v mapi values:

<resources>

<string name="app_name">Hello, Android</string>

<string name="hello_world">Hello world!</string>

<string name="menu_settings">Settings</string>

<string name="title_activity_my">myActivity</string>

</resources>

Vsebina datoteke strings.xml v mapi values-sl:

<resources>

<string name="app_name">Pozdrav, Android</string>

<string name="hello_world">Pozdrav!</string>

<string name="menu_settings">Nastavitve</string>

<string name="title_activity_my">myActivity</string>

</resources>

3.2.4 Podpora različnim dimenzijam in gostotam zaslonov

Zadnja stvar, na katero bomo morali biti pozorni, so različne dimenzije in gostote zaslonov. Da se pravilno lotimo tega problema, je potrebno upoštevati dokumentacijo na strani developer.android.com [20][21][22]. Uporabljati moramo enote, ki niso odvisne od velikosti in števila pik na zaslonu. Prva enota se imenuje density-independent pixel (dp), ali po slovensko točka, neodvisna od gostote zaslona. Na zaslonu z gostoto 160 dpi (Dots Per Inch ali 160 točk na 2,54 cm) se ena točka ujema z enoto 1dp, na zaslonu z gostoto 320 dpi pa 1dp predstavlja dve točki na zaslonu.

Druga enota se imenuje scale-independent pixel (sp). To enoto je priporočljivo uporabljati pri tekstu, saj se spreminja glede na velikost pisave, ki jo uporabnik izbere na telefonu ali tabličnem računalniku.

Poleg uporabe pravilnih enot pa si lahko pomagamo tudi z uporabo različnih uporabniških vmesnikov. V projektu moramo shraniti različne uporabniške vmesnike v različne mape, kot je prikazano na sliki levo. Program ob zagonu samodejno določi uporabniški vmesnik glede na velikost in orientacijo naše naprave. V mapi layout shranimo privzeti uporabniški vmesnik. V mapo layout-land pa shranimo uporabniški vmesnik, ki je

Slika 11: struktura projekta

21

namenjen za uporabo, če je naprava v ležečem položaju. Če želimo, da naš program uporabi drugačen uporabniški vmesnik za naprave, ki imajo večje zaslone (tablični računalniki), shranimo uporabniški vmesnik v mapo layout-large.

Slika 12: uporaba dveh različnih uporabniških vmesnikov v istem programu

Na zgornji sliki vidimo, kako lahko izkoristimo zaslon glede na položaj naprave.

3.3 Načrt in izdelava

Ker bo izdelava igre zahtevna, bom potreboval načrt. Igro bom razbil na posamezne dele in za vsak del najprej predstavil načrt, nato pa izvedbo.

3.3.1 Glavni meni

Najprej potrebujem grob načrt glavnega menija.

Slika 13: diagram glavnega menija

22

Po premisleku sem se odločil za postavitev glavnega menija tako, kot je prikazano v diagramu zgoraj. V meniju Nastavitve bodo različne možnosti, npr. nastavitev jezika, nastavitev velikosti pisav in ostale nastavitve, po katerih se bo pojavila potreba kasneje. Način za več igralcev bom dodal v meni takoj, vendar bo deloval le v primeru, če bo ostalo dovolj časa za izvedbo.

Izvedbe menija ne bom predstavil, ker ni pomemben za igranje igre.

Slika 14: jezik igre se razlikuje glede na jezik telefona

3.3.2 Priprava objektov - Lik

Zaslon, na katerem igramo igro, je glavni del igre in zato tudi najbolj kompleksen. Sestavljen mora biti iz dela, kjer se bodo prikazovali liki, ki so na voljo za sestavljanje, predvideni pa so tudi trije gumbi. Preostanek prostora pa bo namenjen za sestavljanje likov v mreže teles.

Prvi gumb bo odprl nov meni, kjer bodo gumbi za izhod v glavni meni, ponovno reševanje stopnje ter za nadaljevanje igre. V tem meniju si bo mogoče ponovno ogledati pomoč, kjer bo razložen potek igre. Drugi gumb bo namenjen ponovnemu prikazu navodila, tretji gumb bo pa imel funkcijo preverjanja pravilnosti sestavljene mreže. Če bo mreža pravilna, se bo zagnala animacija zapiranja likov v telo, sicer pa se bo prikazalo obvestilo o napačnem odgovoru.

Pri likih želimo čim bolje izkoristiti prednosti objektno orientiranega programskega jezika. Smiselno je definirati abstraktni razred Lik, v katerem bodo vse spremenljivke in metode, ki bodo vsem likom skupne. Nato pa bomo definirali

23

konkretne like, ki bodo razširjali razred Lik in jih bomo tudi uporabili kot objekte. Taka zasnova nam bo omogočala, da ob morebitnih spremembah spreminjamo samo razred Lik, ne pa tudi vse podrazrede.

Za spremenljivke in metode, ki jih bomo uporabili v razredu Lik in njegovih podrazredih, si poglejmo naslednjo sliko.

Slika 15: definicija razreda Lik in njegovih podrazredov

Poleg zgornjih spremenljivk in metod v razredu Lik je pomembna še ena konstanta: dolžina ene enote v točkah na zaslonu naprave. Ker se dimenzije zaslonov od naprave do naprave spreminjajo, bomo določili, da bo dolžina stranice enaka 80 dp, kar pomeni 80 točk na zaslonu s 160 točkami na 2,54 cm. Ob zagonu programa

24

bomo preračunali 80 dp v število točk na zaslonu in jih zapisali v razred Lik. To konstanto bomo potem uporabljali za računanje oglišč likov. Tako bomo dosegli, da bodo liki na vseh napravah enako veliki.

Sedaj si poglejmo odseke kode iz razreda Lik.

Rotacija točk

Pri rotaciji točke okoli točke si pomagamo z vektorji in matrikami:

��′�′� = �cos ∝ − sin ∝

sin ∝ cos ∝ � ����

Pri tem moramo paziti, da zgornji način zavrti točko (�, �) za kot ∝ okoli koordinatnega izhodišča. Če želimo točko A zavrteti okoli točke B, ki ni v koordinatnem izhodišču, moramo od točke A odšteti točko B, nato točko A zavrteti okoli koordinatnega izhodišča, nato pa točki A prišteti točko B.

/**

* Zavrti točko okoli točke za določen kot - v stopinjah

*

* @param pointToRotate

* @param pointToRotateAround

* @param angle

* @return

*/

public Coordinates rotatePointAroundPoint(Coordinates pointToRotate, Coordinates pointToRotateAround, float angle)

{

if (Float.isNaN(angle))

{ // če angle neveljavno število, vrnemo točko brez rotacije

return pointToRotate;

}

// stopinje pretvorimo v radiane float angleInRadians = (float) Math.toRadians(angle);

// začasni objekti

Coordinates tmp = new Coordinates();

Coordinates returnPoint = new Coordinates();

// prestavimo v središče koordinatnega sistema

tmp.x = pointToRotate.x - pointToRotateAround.x;

tmp.y = pointToRotate.y - pointToRotateAround.y;

returnPoint.x = (float) (tmp.x * Math.cos(angleInRadians) - tmp.y * Math.sin(angleInRadians) );

returnPoint.y = (float) (tmp.x * Math.sin(angleInRadians) + tmp.y * Math.cos(angleInRadians) );

// prestavimo iz središča nazaj

returnPoint.x += pointToRotateAround.x;

returnPoint.y += pointToRotateAround.y;

return returnPoint;

}

V zgornji metodi smo rešili problem vrtenja touporabimo za vrtenje lika okoli centra ali poljubne to

Vrtenje lika okoli centra:

/**

* Rotacija okoli centra, v stopinjah.* @param angle

*/

public void rotateAroundCenter({ // vertexArray je tabela, v kateri so zapisana oglišča for (int i = 0; i < {

vertexArray[i] = centerCoordinates, angle);

}

}

Vrtenje lika okoli poljubne toč

public void rotateAroundPoint({

for (int i = 0; i < {

vertexArray[i] = rotatePointAroundPoint( }

// poleg oglišč zavrtimo še središče lika centerCoordinates = rotatePointAroundPoint(}

Preverjanje, ali je točka znotraj lika

To preverjanje uporabimo za ali je točka znotraj lika, je za pravokotnike

Tu je treba samo preveriti, da je �2, ter da je � koordinata toč

Če pa kvadrat zavrtimo, to preverjanje ni vepreverjanja ni primeren za trikotnike ali pet

25

V zgornji metodi smo rešili problem vrtenja točke okoli točke. To lahko sedaj uporabimo za vrtenje lika okoli centra ali poljubne točke.

* Rotacija okoli centra, v stopinjah.

rotateAroundCenter(float angle)

vertexArray je tabela, v kateri so zapisana oglišča

i = 0; i < vertexArray.length; i++)

[i] = rotatePointAroundPoint(vertexArray[i], , angle);

koli poljubne točke:

rotateAroundPoint(float angle, Coordinates point)

i = 0; i < vertexArray.length; i++)

[i] = rotatePointAroundPoint(vertexArray[i], point, angle);

poleg oglišč zavrtimo še središče lika

= rotatePointAroundPoint(centerCoordinates

Preverjanje, ali je točka znotraj lika

za določanje, ali se s prstom dotaknemoka znotraj lika, je za pravokotnike preprosta:

da je � koordinata točke � med � koordinatama tokoordinata točke � med � koordinatama točk �0 in �3

e pa kvadrat zavrtimo, to preverjanje ni več tako preprosto. Pravtrikotnike ali petkotnike, če jih bomo kasneje dodali v igro.

čke. To lahko sedaj

[i],

[i], point, angle);

centerCoordinates, point, angle);

dotaknemo lika. Preverjanje,

koordinatama točk �3 in 3.

tako preprosto. Prav tako ta način e jih bomo kasneje dodali v igro.

Za rešitev tega problema Uporabili bomo lastnost vektorskega produkta:

Recimo, da imamo v ravnini

pa nas zanima, ali leži na isti strani dal

vektor � � �������� in � � ��������. vektorja � � in � � enako smimata vektorja � � in �

To lastnost nato uporabimo v metodi razreda Lik:

// metoda vrne TRUE, če sta točki P1 in P2 na isti strani daljice ABprotected boolean sameSide(Coordinates P1, Coordinates P2, Coordinates A, Coordinates B) {

MyVector v0 = new MyVector(B. MyVector v1 = new MyVector(P1. MyVector v2 = new MyVector(P2.

MyVector cp1 = crossProduct(v0, v1); MyVector cp2 = crossProduct(v0, v2);

if (dotProduct(cp1, cp2) >= 0) return true;

}

else {

return false;

}

}

26

lahko uporabimo znanje, pridobljeno pri urah algebre. lastnost vektorskega produkta:

v ravnini točke �, !, � in �. Točke �, ! in � poznamo, za to

pa nas zanima, ali leži na isti strani daljice �!"""" kot točka �. Imejmo vektor � Če sta točki � in � na isti strani daljice enako smer, če pa sta točki � in � na različ

� različno smer.

Slika 16: vektorski produkt

To lastnost nato uporabimo v metodi razreda Lik:

metoda vrne TRUE, če sta točki P1 in P2 na isti strani daljice ABsameSide(Coordinates P1, Coordinates P2, Coordinates A,

MyVector(B.x - A.x, B.y - A.y, 0);

MyVector(P1.x - A.x, P1.y - A.y, 0);

MyVector(P2.x - A.x, P2.y - A.y, 0);

MyVector cp1 = crossProduct(v0, v1);

MyVector cp2 = crossProduct(v0, v2);

(dotProduct(cp1, cp2) >= 0) {

lahko uporabimo znanje, pridobljeno pri urah algebre.

poznamo, za točko �

. Imejmo vektor � � �!������, na isti strani daljice �!"""", potem imata

na različnih straneh, pa

metoda vrne TRUE, če sta točki P1 in P2 na isti strani daljice AB sameSide(Coordinates P1, Coordinates P2, Coordinates A,

27

S pomočjo te metode v razredu Lik lahko v podrazredih ugotovimo, ali je dana točka znotraj lika.

Primer iz razreda EnakostranicniTrikotnik.java:

@Override public boolean isPointInside(Coordinates c) { if ( sameSide(c, vertexArray[0], vertexArray[1], vertexArray[2]) &&

sameSide(c, vertexArray[1], vertexArray[0], vertexArray[2]) && sameSide(c, vertexArray[2], vertexArray[0], vertexArray[1]) )

{ return true; } else { return false; } }

Zgornja metoda preveri, ali je za vsako stranico točka � na isti strani kot oglišče trikotnika, ki ne leži na stranici. Če so vsi pogoji izpolnjeni, točka leži znotraj lika.

Podrazredi razreda Lik

Podrazredi razreda lik morajo vsebovati abstraktne metode razreda Lik, poleg tega pa mora biti v vsakem podrazredu podan način, kako se izračunajo oglišča lika. To naredimo v konstruktorju objekta:

public EnakostranicniTrikotnik(int centerX, int centerY)

{

super(); // klic konstruktorja razreda Lik

centerCoordinates.x = centerX; // določitev centra lika

centerCoordinates.y = centerY;

vertexArray = new Coordinates[3]; // ustvarimo novo tabelo dolžine 3

vertexArray[0] = new Coordinates();

vertexArray[0].x = centerX; // izračun prve točke

vertexArray[0].y = (float) (centerY - ( (Lik.oneUnit * 1.73205) / 3));

vertexArray[1] = new Coordinates(); // drugo točko določimo z rotacijo prve

vertexArray[1] = rotatePointAroundPoint(vertexArray[0], centerCoordinates, 120);

vertexArray[2] = new Coordinates();// tretjo točko določimo z rotacijo prve

vertexArray[2] = rotatePointAroundPoint(vertexArray[0], centerCoordinates, 240);

}

Vedno, ko bomo ustvarili nov objekt razreda EnakostranicniTrikotnik, se bo izvedla zgornja koda.

Ostala nam je še metoda za izris samega lika. Ta mora za risanje prejeti parameter tipa Canvas [23], ki določa risalno površino, na katero rišemo.

28

public void draw(Canvas canvas) {

path.rewind(); // točke lika dodamo v objekt Path

path.moveTo(vertexArray[0].x, vertexArray[0].y);

path.lineTo(vertexArray[1].x, vertexArray[1].y);

path.lineTo(vertexArray[2].x, vertexArray[2].y);

path.close();

if (scaleWhenDrawing) // pomanjšan lik se uporablja ko lik ni na delovni površini

{

scaleMatrix.setScale(scale, scale, centerCoordinates.x, centerCoordinates.y);

scaledPath.reset();

scaledPath.set(path);

scaledPath.transform(scaleMatrix); // pomanjšamo

if (!Lik.drawFrameOnly) // če ne rišemo samo okvirja, narišemo najprej polnilo

{

canvas.drawPath(scaledPath, fillPaint);

}

canvas.drawPath(scaledPath, paint); // nato pa še rob

}

else

{ // rišemo lik v polni velikosti

if (!Lik.drawFrameOnly)

{

canvas.drawPath(path, fillPaint);

}

canvas.drawPath(path, paint);

}

// pomoč za razhroščevanje; za delo z rotacijami in za obnašanje likov med spajanjem if (debugModeEnabled)

{

canvas.drawLine(centerCoordinates.x, centerCoordinates.y, vertexArray[rotationReferenceVertex].x, vertexArray[rotationReferenceVertex].y, paint);

canvas.drawLine(centerCoordinates.x, centerCoordinates.y, LikHolder.refX, LikHolder.refY, paint);

if (showSidesLength)

{

canvas.drawText("1", centerCoordinates.x - (Lik.oneUnit/10),centerCoordinates.y + (Lik.oneUnit/10), textPaint);

}

if (isPressed)

{

canvas.drawText("P!", centerCoordinates.x,centerCoordinates.y, textPaint);

}

if (gluedToID != -1)

{

canvas.drawText("G:" + gluedToID, centerCoordinates.x, centerCoordinates.y, textPaint);

}

} }

Na podoben način ustvarimo še razrede za kvadrata dveh velikosti, pravokotnik in enakokraki trikotnik.

H kreiranju likov in klicanju metode draw(Canvas canvas) se bomo vrnili še kasneje, ko bomo like vključili v igro.

29

3.3.3 Priprava objektov – Seznam likov

Naslednja stvar, ki jo potrebujemo, je razred, v katerem bo seznam likov, ki bodo na glavni površini. V ta seznam bomo dodajali like, ki bodo na začetku igre ob robu zaslona. S pomočjo tega razreda bomo preverjali, ali sta dva lika tako blizu, da jih lahko zlepimo. Razred bo skrbel tudi za to, da če premikamo en lik po zaslonu, se premikajo tudi vsi liki, ki so k temu liku prilepljeni. Poleg tega bo izvajal rotacije likov, ki jih držimo s prsti.

Javne metode, ki jih bomo potrebovali v tem razredu, so naslednje:

• Metoda za dodajanje lika v seznam • Metoda, ki preveri, kateri liki so prilepljeni k danemu liku in jih označi za

premikanje • Metoda za preverjanje sestavljenih mrež • Metoda, ki odstrani referenčne točke za vrtenje • Metoda, ki odstrani oznake likov za premikanje • Metoda, ki doda referenčno točko za rotacije likov • Metoda, ki izbriše določen lik iz seznama in ga vrne • Metoda, ki izbriše ves seznam • Metoda, ki nariše like • Metoda, ki vrne lik z danim ID • Metoda, ki vrne število elementov v seznamu • Metoda, ki preveri, ali smo pritisnili lik in vrne ID • Metoda, ki premakne lik skupaj z liki, ki so zlepljeni • Metoda, ki odstrani likom oznako, da ga držimo • Metoda, ki posodobi referenčno točko za rotacijo in like zavrti

Poleg javnih metod bomo potrebovali tudi privatne metode. Do teh ni mogoče dostopati izven razreda, saj so namenjene za pomoč javnim metodam.

Privatne metode:

• Metoda, ki liku izračuna kot med vektorjem, ki poteka od središča lika proti oglišču in med vektorjem, ki poteka od središča lika proti referenčni točki za vrtenje. Na podlagi spremembe kota bomo vrteli lik

• Metoda, ki bo preverila, ali je treba dva lika zlepiti • Metoda, ki bo preverila, ali sta si dva oglišča dovolj blizu • Metoda, ki bo preverila, ali se oglišča dveh likov prekrivajo • Metoda, ki bo zlepila dva lika skupaj

Ker bo lahko v seznamu poljubno število likov, bo seznam narejen s pomočjo povezanih podatkovnih struktur [24] – to smo predvideli že pri načrtovanju razreda Lik, ki vsebuje kazalec na naslednji element.

30

Poglejmo si še izvedbo nekaterih zgoraj naštetih metod:

• Metoda, ki preveri, ali smo pritisnili lik in vrne ID

public int getPressedShapeID(int x, int y)

{

if (first != null) // Če seznam ni prazen, iščemo po likih

{

Lik runner = first;

while (runner != null)

{ // preverimo, ali je točka (x,y) znotraj lika

if (runner.isPointInside(x, y) )

{ // če je točka znotraj lika, označimo, da ga držimo

runner.isPressed = true;

if (hasRotationReference) // če je vrtenje likov v teku

{ // izračunamo podatke za vrtenje še za ta lik

addRotationReference(runner);

}

return runner.id; // vrnemo id lika

}

runner = runner.next; // pomik na naslednji objekt v seznamu

}

}

return -1; // če točka (x,y) ni znotraj nobenega lika, vrnemo -1

}

• Metoda za dodajanje lika v seznam

Ta metoda je preprosta, treba pa je razumeti delo s kazalci.

public int addLik(Lik lik) {

lik.id = nextId; // liku določimo ID

nextId++;

if (first == null) {

first = lik;

last = lik;

}

else {

last.next = lik;

last = last.next;

}

count++;

return lik.id; // vrnemo id lika

}

31

• Metoda, ki preveri, kateri liki so prilepljeni k danemu liku in jih označi za premikanje

/**

* Preveri, če je kateri lik prilepljen (imata 2 skupna oglišča) in ga označi za * premikanje. Rekurzivna metoda.

* @param shapeID - h kateremu liku ga prilepimo

* @param parentID - starš ki je sprožil preverjanje (kliknjen=

* @param excludeID - ID lika, ki ga želimo izključiti

*/

public void checkForGluedShapes(int shapeID, int parentID, int excludeID)

{

if (first != null)

{

Lik runner = first;

while (runner != null)

{ // lik, ki ga drži drug dotik izključimo

if (!runner.isPressed && (runner.id != excludeID) )

{ // če imata lika dva skupna oglišča, sta zlepljena

if (getCommonVertexNumber(findShapeById(shapeID), runner) == 2)

{ // sproti dodajamo like v tabelo, ki jo

// bomo uporabili za preverjanje sestavljenih mrež

if ( arrayItems < likArray.length )

{

likArray[arrayItems] = runner;

arrayItems++;

}

// označimo, da se premika in s katerim likom se // mora premikati

runner.willMove = true;

runner.gluedToID = parentID;

// ob ponovnem klicu metode trenutni lik //izključimo iz preverjanja, da ne pride do //neskončne zanke

checkForGluedShapes(runner.id, parentID, shapeID);

}

}

runner = runner.next;

}

}

}

Zgornja metoda je rekurzivna. Uporaba rekurzivne metode je najbolj primerna za problem iskanja sosedov. V tej metodi tudi pripravimo tabelo zlepljenih likov, katero bomo uporabili preverjanje, ali zlepljeni liki predstavljajo mrežo telesa.

• Metoda, ki premakne lik skupaj z liki, ki so zlepljeni

Ta metoda premika lik z danim id, poleg tega pa premakne še vse like, ki so k liku z danim id prilepljeni. Metoda prejme tri parametre. Prvi parameter je id lika, ki ga želimo premakniti, druga dva parametra sta pa razdalja premika v x in y smeri. V tej metodi se preverja tudi, ali smo lik približali dovolj blizu drugemu liku, da se zlepita.

public void move(int id, float{

Lik tmp = null; // začasni objekt

if (first != null)

{

Lik runner = first while (runner != {

if ((runner. {

// premaknemo samo lik z danim id ali lik, ki je prilepljenrunner.moveTo(runner.ner.

if

{ } }

runner = runner. }

// ko vse premaknemo, preverimo še, ali je v bližini lik checkIfGlueingNeeded(tmp); }}

• Metoda, ki bo zlepila dva lika skupaj

Ta metoda je zelo obsežna. Poglejmo

Najprej določimo neko obmodveh likov znotraj tega obmorotacij bomo najprej poravnalizračunali kot, za katerega boizračunamo kot, ugotovimopomočjo testne točke, ki jo zavrtimo v neko smer, nato pa primerjamociljnega oglišča. Če je razdaKo pravilno poravnamo lik, si še metodo:

32

float dx, float dy)

// začasni objekt

first;

(runner != null)

((runner.id == id) || (runner.gluedToID == id) )

// premaknemo samo lik z danim id ali lik, ki je prilepljenrunner.moveTo(runner.centerCoordinates.xner.centerCoordinates.y + dy);

if (runner.id == id)

{

tmp = runner; // zapomnemo si lik, ki ima dan id}

runner = runner.next;

// ko vse premaknemo, preverimo še, ali je v bližini likcheckIfGlueingNeeded(tmp);

Metoda, ki bo zlepila dva lika skupaj

Ta metoda je zelo obsežna. Poglejmo si najprej idejo:

Slika 17: lepljenje likov

območje lepljenja. Če je razdalja med dvema paromatega območja, se bo prvi lik prilepil k drugemu. Zaradi možnih

najprej poravnali oglišči, ki sta si bližje, nato pa s pokot, za katerega bomo zavrteli lik okoli poravnanega

mo še smer, v katero moramo vrteti lik. V metodi jo zavrtimo v neko smer, nato pa primerjamo

razdalja večja kot pred vrtenjem, smo vrteli lik, poravnamo še like, ki so k temu liku prilepljeni. Poglejmo

== id) )

// premaknemo samo lik z danim id ali lik, ki je prilepljen

x + dx, run-

si lik, ki ima dan id

// ko vse premaknemo, preverimo še, ali je v bližini lik

dvema paroma oglišč , se bo prvi lik prilepil k drugemu. Zaradi možnih

i, ki sta si bližje, nato pa s pomočjo vektorjev lik okoli poravnanega oglišča. Ko

v katero moramo vrteti lik. V metodi to rešimo s jo zavrtimo v neko smer, nato pa primerjamo razdaljo od

v napačno smer. še like, ki so k temu liku prilepljeni. Poglejmo

33

/**

* Spoj dveh likov.

* @param runner

* @param lik

*/

private void glueTogether(Lik runner, Lik lik)

{

if (runner.isPressed && lik.isPressed)

{

return; //če oba lika držimo, ne poravnamo

}

int firstVertex = -1; // kateri dve oglišči je potrebno poravnati

int secondVertex = -1;

float firstDX; // za razdalje

float firstDY;

float secondDX;

float secondDY;

int i = 0;

// Določimo katera oglišča v seznamu so označena za spoj

for (i = 0; i < lik.vertexArray.length; i++)

{

if (lik.vertexArray[i].glueTo != null)

{

if (firstVertex == -1)

{

firstVertex = i; // prvo oglišče za spoj

}

else {

secondVertex = i; // drugo oglišče za spoj

}

}

}

// kalkulacija koliko sta oglišči oddaljeni od koordinat za spoj

firstDX = lik.vertexArray[firstVertex].glueTo.x - lik.vertexArray[firstVertex].x;

firstDY = lik.vertexArray[firstVertex].glueTo.y - lik.vertexArray[firstVertex].y;

secondDX = lik.vertexArray[secondVertex].glueTo.x - lik.vertexArray[secondVertex].x;

secondDY = lik.vertexArray[secondVertex].glueTo.y - lik.vertexArray[secondVertex].y;

float angle;

if ( (Math.pow(firstDX,2) + Math.pow(firstDY,2)) < (Math.pow(secondDX,2) + Math.pow(secondDY,2)) )

{

// prvo oglišče bližje ciljni točki; to oglišče poravnamo na mesto

lik.moveTo(lik.centerCoordinates.x + firstDX, lik.centerCoordinates.y +firstDY);

34

// če je eno od teles zavrteno, drugo vozlišče še ni na svojem //mestu.

MyVector2D v1 = new MyVector2D();

MyVector2D v2 = new MyVector2D();

// prvi vektor: iz poravnanega oglišča do neporavnanega oglišča

v1.x = lik.vertexArray[secondVertex].x - lik.vertexArray[firstVertex].x;

v1.y = lik.vertexArray[secondVertex].y - lik.vertexArray[firstVertex].y;

// drugi vektor: iz poravnanega oglišča do mesta, kamor mora priti neporavnano oglišče

v2.x = lik.vertexArray[secondVertex].glueTo.x - lik.vertexArray[firstVertex].x;

v2.y = lik.vertexArray[secondVertex].glueTo.y - lik.vertexArray[firstVertex].y;

// izračun kota med vektorji

double tmp = MyVector2D.dotProduct(v1, v2)/(v1.vectorLength() * v2.vectorLength() );

if (tmp > 1.0f)

{ // problem z zaokroževanjem

// realna števila se lahko zaokrožijo na 1.0000000001 // kar povzroči napako pri funkciji acos (dobimo NaN)

tmp = 1.0f;

}

// izračunamo kot za koliko moramo še lik zavrteti

angle = (float) Math.toDegrees( Math.acos( tmp ) );

// test v katero stran je potrebno vrteti

float newDX;

float newDY;

Coordinates testPoint = new Coordinates();

testPoint.x = lik.vertexArray[secondVertex].x;

testPoint.y = lik.vertexArray[secondVertex].y;

// na novo izračunam dx in dy po premiku

secondDX = lik.vertexArray[secondVertex].glueTo.x - lik.vertexArray[secondVertex].x;

secondDY = lik.vertexArray[secondVertex].glueTo.y - lik.vertexArray[secondVertex].y;

// zavrtim testno točko

testPoint = lik.rotatePointAroundPoint(testPoint, lik.vertexArray[firstVertex], angle);

// ali je testna točka bolj oddaljena od cilja? => vrtenje v //napačno smer

newDX = testPoint.x - lik.vertexArray[secondVertex].glueTo.x;

newDY = testPoint.y - lik.vertexArray[secondVertex].glueTo.y;

if ( (Math.pow(newDX,2) + Math.pow(newDY,2) ) > (Math.pow(secondDX,2) + Math.pow(secondDY,2)) )

{

angle = angle * -1; // spremenimo smer vrtenja

}

35

// vrtim lik točke okoli [firstVertex]

// najprej oglišča

for (int k = 0; k < lik.vertexArray.length; k++)

{

if (k != firstVertex)

{

lik.vertexArray[k] = lik.rotatePointAroundPoint(lik.vertexArray[k], lik.vertexArray[firstVertex], angle );

}

}

// še center

lik.centerCoordinates = lik.rotatePointAroundPoint(lik.centerCoordinates, lik.vertexArray[firstVertex], angle );

//sedaj se lahko premaknejo tudi liki, ki so prilepljeni k liku, ki se je //poravnal

Lik tmpRunner = first;

while (tmpRunner != null)

{

if (tmpRunner.gluedToID == lik.id)

{

tmpRunner.moveTo(tmpRunner.centerCoordinates.x + firstDX, tmpRunner.centerCoordinates.y +firstDY);

tmpRunner.rotateAroundPoint(angle, lik.vertexArray[firstVertex]);

}

tmpRunner = tmpRunner.next;

}

}

else

{ //Če je drugo oglišče bližje, ravnamo podobno kot zgoraj

} // ko imamo še en lik prilepljen, ponovno preverimo zaradi oznak za //premik

checkForGluedShapes(lik.id, lik.id, -1);

}

36

• Metoda, ki doda referenčno točko za rotacije likov • Metoda, ki posodobi referenčno točko za rotacijo in like zavrti

Ti dve metodi sta prav tako zelo obsežni. Ker bi celotni metodi zasedli kar nekaj strani, si bomo pogledali samo idejo za izvedbo.

Dotik na zaslon povzroči preverjanje, ali smo se dotaknili lika. Če igra ugotovi, da smo se dotaknili praznega prostora, se bo točka tega dotika upoštevala za rotacijo. Tedaj bomo točko tega dotika dodali v seznam likov kot točko za rotacijo, likom, ki se jih z drugimi prsti že dotikamo, pa izračunamo potrebne podatke. Od tega trenutka naprej se bodo računali podatki tudi za vsak lik, ki se ga bomo dotaknili.

Ko se bo dotik na prazen prostor premikal po zaslonu, bomo s trenutno točko poklicali metodo, ki bo glede na prejšnjo točko izračunala potrebne rotacije likov. Ko bo ta dotik zapustil zaslon, se bo referenčna točka pobrisala, podatki za like pa se ne bodo več računali.

Slika 18: vrtenje likov

Pri računanju podatkov za vrtenje bomo za vsak lik najprej določili vektor iz središča lika do točke za rotacijo, nato bomo poiskali še vektor, ki bo potekal iz središča lika do oglišča lika tako, da bo kot med obema vektorjema najmanjši. Oglišče in kot bomo zapisali v spremenljivke lika. Nato bomo ob vsaki novi poziciji točke za rotacijo ponovno izračunali kot med vektorjema, ga primerjali z začetnim kotom ter lik zavrteli za razliko med prvotnim in novim kotom. Delovanje je prikazano na zgornji sliki. Črte iz središč likov predstavljajo vektorje. S premikom točke za rotacijo se vrtijo samo liki, ki se jih dotikamo.

37

Za zaključek razreda, ki vsebuje seznam likov, si poglejmo še metodo, ki bo skrbela za izris vseh likov v seznamu.

• Metoda, ki nariše like

/** * Izriše vse objekte, ki jih ima razred v seznamu * @param canvas */ public void draw(Canvas canvas) { if (first != null) { Lik runner = first; while (runner != null) { runner.draw(canvas); runner = runner.next; } } }

Tudi ta metoda mora prejeti parameter tipa Canvas. Ta metoda se sprehodi po seznamu in pokliče metodo draw(canvas) za vsak lik posebej. To nam omogoči, da iz glavnega programa ni treba klicati metode za izris za vsak lik posebej.

3.3.4 Priprava objektov – Sistem preverjanja mrež

Potrebujemo še en razred, ki bo pregledoval pravilnost sestavljenih mrež. Ta razred ne bo pregledoval pravilnosti mrež in teles glede na naloge v igri, temveč bo samo preveril, ali liki predstavljajo kakšno znano telo in mrežo. Za tak pristop sem se odločil zato, da lahko preverjanje mrež in teles ter preverjanje nalog razdelimo na dva manjša problema. Zato bo razred potreboval javne metode:

• Metoda, ki vrne id mreže • Metoda, ki vrne ime mreže • Metoda, ki vrne ime telesa • Metoda, ki vrne id telesa

Ker je mrež in teles veliko, potrebujemo neki način razlikovanja med njimi. Pomagamo si lahko s celoštevilskimi konstantami. Prva prednost je ta, da je primerjanje celih števil hitrejše od primerjanja besedil, poleg tega pa lahko tudi izven razreda dostopamo do teh konstant na način ImeRazreda.imeKonstante. To pomeni, da ni treba, da si id vsakega telesa in vsake mreže zapomnimo, ampak si moramo izbrati samo pravilno ime konstante. To je prednost tudi v primeru, če je potrebno identifikacijo likov in mrež spreminjati. Razredov, ki dostopajo do konstant na zgornji način, ni potrebno popravljati, medtem ko bi morali razrede, ki ne bi uporabljali konstant, popraviti.

38

Poglejmo si določitev konstant za geometrijska telesa:

// TELESA

public static final int TELO_NI_TELESA = 0;

public static final int TELO_KOCKA = 1;

public static final int TELO_KVADER = 2;

public static final int TELO_TETRAEDER = 3;

public static final int TELO_NEPRAVILNA_TRISTRANA_PIRAMIDA = 4;

public static final int TELO_STIRISTRANA_PIRAMIDA = 5;

public static final int TELO_TRISTRANA_PRIZMA = 6;

public static final int TELO_TRISTRANA_PIRAMIDA = 7;

public static final int TELO_NEPRAVILNA_TRISTRANA_PRIZMA = 8;

public static final int TELO_NEPRAVILNA_STIRISTRANA_PIRAMIDA = 9

Konstante za nekatere mreže:

// MREŽE

public static final int MREZA_NI_MREZE = 0;

public static final int MREZA_TETRAEDER_MALI_TRIKOTNIKI = 30;

public static final int MREZA_TETRAEDER_VELIKI_TRIKOTNIKI = 31;

// ŠTIRISTRANE PIRAMIDE

public static final int MREZA_STIRISTRANA_PIRAMIDA_OP_MALI_KVADRAT_ENAKOSTRANICNI_TRIKOTNIKI = 50;

public static final int MREZA_STIRISTRANA_PIRAMIDA_OP_MALI_KVADRAT_ENAKOKRAKI_TRIKOTNIKI = 51;

public static final int MREZA_STIRISTRANA_PIRAMIDA_OP_VELIK_KVADRAT_ENAKOSTRANICNI_TRIKOTNIKI = 52;

public static final int MREZA_STIRISTRANA_PIRAMIDA_OP_PRAVOKOTNIK_STRANICE_ENAKOKRAKA_IN_ENAKOSTRANICNA_TRIKOTNIKA = 53;

Poglejmo si še način preverjanja. Metoda, s katero bomo preverjali, mora prejeti kot parameter seznam likov, ki so zlepljeni skupaj. Nato bomo prešteli like v seznamu in na podlagi tega preverjali posamezne like. Če bodo v seznamu štirje liki, sta možni telesi tetraeder in tristrana piramida, zato bo metoda poklicala najprej metodo za preverjanje tetraedra, in nato še metodo za preverjanje tristrane piramide, če preverjanje tetraedra ne bo vrnilo rezultata.

Pri preverjanju mrež si bomo pomagali z naslednjimi metodami:

• Metoda, ki ugotovi, kateri lik v seznamu ima največ sosedov • Metoda, ki preveri, ali sta dva lika soseda • Metoda, ki preveri, ali ima lik točno določeno število sosedov določenega tipa • Metoda, ki preveri, ali obstaja nasprotni lik glede na podan lik in sosednji lik • Metoda, ki preveri, ali obstaja simetrično prilepljeni nasprotni lik glede na podan

lik in sosednji lik

39

Primer preverjanja, ali liki predstavljajo tetraeder:

private static int checkForTetrahedron(Lik[] liki)

{

// preverimo kateri lik ima največ sosedov

maxNeighboursIndex = getShapeIndexWithMostNeighbours(liki);

// Preverjanje pogojev – lik z največ sosedi mora biti enakostranični Trikotnik, ta pa mora imeti še tri sosede enakostranične trikotnike

if (liki[maxNeighboursIndex].name == Lik.ENAKOSTRANICNI_TRIKOTNIK &&

checkAndCountNeighbours(liki, maxNeighboursIndex, Lik.ENAKOSTRANICNI_TRIKOTNIK, 3))

{

// Če so pogoji izpolnjeni, vrne vrednost, ki predstavlja mrežo tetraedra

return MREZA_TETRAEDER_MALI_TRIKOTNIKI;

}

// Preverjanje za tetraeder z velikimi trikotniki

if (liki[maxNeighboursIndex].name == Lik.ENAKOSTRANICNI_TRIKOTNIK_15 &&

checkAndCountNeighbours(liki, maxNeighboursIndex, Lik.ENAKOSTRANICNI_TRIKOTNIK_15, 3))

{

return MREZA_TETRAEDER_VELIKI_TRIKOTNIKI;

}

// če liki ne predstavljajo tetraedra, to vrnemo

return MREZA_NI_MREZE;

}

Poglejmo si še način preverjanja ene od prizem:

else if (liki[maxNeighboursIndex].name == Lik.ENAKOSTRANICNI_TRIKOTNIK_15)

{ // v primeru, če ima velik enakostranični trikotnik največ sosedov

if (checkAndCountNeighbours(liki, maxNeighboursIndex, Lik.KVADRAT_15, 3))

{ // prva možnost: ima 3 sosede velike kvadrate

for (int i = 0; i < numberOfShapes; i++)

{ // preverimo še, ali ima kateri od kvadratov nasproti osnovne //ploskve še en enakostranični trikotnik

if ((liki[i].name == Lik.KVADRAT_15) &&

hasOppositeNeighbour(liki, maxNeighboursIndex, i, Lik.ENAKOSTRANICNI_TRIKOTNIK_15))

{

return MREZA_3_PRIZMA_OP_ENAKOSTRANICNI_TRIKOTNIK_STRANICE_KVADRATI;

}

}

}

if (checkAndCountNeighbours(liki, maxNeighboursIndex, Lik.PRAVOKOTNIK, 3))

{ // druga možnost: ima 3 sosede pravokotnike

for (int i = 0; i < numberOfShapes; i++)

{ // preverimo še, ali ima kateri od pravokotnikov nasproti osnovne //ploskve še en enakostranični trikotnik

if ((liki[i].name == Lik.PRAVOKOTNIK) &&

hasOppositeNeighbour(liki, maxNeighboursIndex, i, Lik.ENAKOSTRANICNI_TRIKOTNIK_15))

{

return MREZA_3_PRIZMA_OP_VELIKI_ENAKOSTRANICNI_TRIKOTNIK_STRANICE_PRAVOKOTNIKI; }

}

}

return MREZA_NI_MREZE;

}

40

V primeru, da liki predstavljajo določeno mrežo, v tem razredu izračunamo še podatke o vrtenju likov okoli stranic drugih likov, kar uporabljamo pri tridimenzionalni animaciji zapiranja likov. V Activity, kjer bo animacija zapiranja likov, preberemo podatke o osi in kotu vrtenja za vsak lik in ustrezno animacijo prikažemo na zaslonu. Za tridimenzionalno grafiko uporabljamo OpenGL [25]. Postopka ne bom opisoval zaradi obsežnosti, bo pa na koncu viden rezultat.

3.3.5 Sestavljanje objektov v celoto

Slika 19: glavni del igre

Na zgornji sliki je prikazano, kako je videti glavni del igre. Pripravljene imamo osnovne objekte – like in seznam likov, ki skrbi za vrtenje, spajanje in premikanje likov. Na zgornji sliki so ob robu zaslona pomanjšani liki, ki še niso v glavnem seznamu. Recimo, da so ti liki v skladišču. Tega skladišča ne bom posebej predstavljal.

Na začetku četrtega poglavja smo že omenili, da je osnovni gradnik programa ali dela programa Activity, kjer določimo uporabniški vmesnik. Uporabniški vmesnik bo sestavljen iz gumbov, ki so že pripravljeni za uporabo ter iz risalne površine, ki pa jo moramo zgraditi sami.

Risalna površina

Da naredimo svojo risalno površino, moramo uporabiti razred View [26], ki je osnovni gradnik za komponente uporabniškega vmesnika, ga razširiti in prilagoditi svojim zahtevam.

41

public class SinglePlayerView extends View {

// konstruktorji; zaradi kasnejše uporabe v definiciji uporabniškega vmesnika v //.xml datoteki so potrebni vsi možni konstruktorji.

public SinglePlayerView(Context context) {

this(context, null); // pokliče naslednji konstruktor

}

public SinglePlayerView(Context context, AttributeSet attrs) {

this(context, attrs, 0); // pokliče naslednji konstruktor

}

public SinglePlayerView(Context context, AttributeSet attrs, int defStyle) {

super(context, attrs, defStyle); // pokliče konstruktor razredu View // tu pripravimo razred na uporabo

}

@Override

protected void onDraw(Canvas canvas) {

// metoda, ki riše

} }

Najprej dodajmo pred konstruktorje spremenljivke, ki jih bomo potrebovali:

// Tabela, kamor bomo shranjevali podatke o dotikih

SparseArray<TouchInfo> pointerMap2 = new parseArray<SinglePlayerView.TouchInfo>();

//Oznaki, ali naj liki uporabljajo naključne barve in ali naj se izriše samo ok

public boolean useRandomColors;

public boolean drawFrameOnly;

LikHolder likHolder; // Seznam likov

LikProviderFrame likProvider; // Skladišče likov, ki so pripravljeni ob strani

MyApplicationData myData ; // uporaba za dostop do globalnih spremenljivk

private boolean firstRun; // Oznaka, ali prvič izrisujemo

private Context activityContext;

RelativeLayout instructionsLayout; // Za dostop do navodil

TextView instructionsView;

Nato v konstruktorju poskrbimo za inicializacijo.

public SinglePlayerView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); // Klic konstruktorja v razredu View activityContext = context; // Potrebujemo za zagon druge Activity likHolder = new LikHolder();// Ustvarimo nov seznam firstRun = true; // Označimo za prvi izris }

Metoda onDraw(Canvas canvas) skrbi za izris. Te metode ne kličemo sami, ampak jo pokliče sistem. Sistem moramo tudi obvestiti, da je potreben ponoven izris, kar storimo s klicem metode invalidate(). Ko to pokličemo, sistem takoj, ko je mogoče, pokliče metodo onDraw(Canvas canvas). Klic metode invalidate() uporabljamo na dva načina: lahko jo pokličemo ob vsakem dotiku zaslona, lahko pa ustvarimo novo nit programa, kjer kličemo metodo invalidate() vsakih nekaj

42

milisekund. Ker smo že na začetku predvideli tudi igro s tekmo na čas, prvi način ne bi bil primeren, saj bi se odštevalnik časa (če bi ga izpisovali znotraj tega razreda) posodabljal samo med dotiki in premiki po zaslonu. Zato bomo kasneje uporabili drugo metodo.

@Override protected void onDraw(Canvas canvas) {

// na tej točki zagotovo vemo dimenzijo zaslona. Zato pri prvem izrisu // izračunamo velikost in pozicijo skladišča likov ob robu zaslona // namesto tega načina se uporablja tudi // metodo onSizeChanged(int w, int h, int oldw, int oldh)

if (firstRun) { likProvider.calculatePosition(getWidth(), getHeight()); // Dimenzije shranimo za uporabo v drugih razredih DataHolder.height = getHeight(); DataHolder.width = getWidth(); firstRun = false; // ne potrebujemo več računanja } likHolder.draw(canvas); // izrišemo like v seznamu likProvider.draw(canvas); // izrišemo like ob strani v skladišču }

V tem razredu bomo poskrbeli za prejemanje podatkov o dotikih, ki jih smiselno povežemo z objekti, predstavljenimi zgoraj. Ker bomo igro upravljali z več prsti (sistem prepozna do deset različnih dotikov), moramo v neko tabelo shranjevati podatke v dotikih. Za podatke o dotikih uporabimo svoj razred, katerega objekti bodo vsebovali potrebne podatke. Vsak dotik na zaslon bo ustvaril nov objekt, v katerega se bo zapisala identifikacija dotika, katerega lika smo se dotaknili oziroma ali smo se dotaknili praznega prostora (rotacija). Poseben zapis bo obstajal tudi za dotik skladišča ob strani ter za zapis zadnje pozicije dotika. Tega razreda ne bom posebej predstavljal.

Podatke o dotikih lahko prestrežemo s spodnjo metodo:

@Override// Tu skrbimo za dotike

public boolean onTouchEvent(MotionEvent event) {

switch (event.getAction() & MotionEvent.ACTION_MASK) {

case MotionEvent.ACTION_DOWN: { // prvi dotik zaslona

break; }

case MotionEvent.ACTION_POINTER_DOWN: { // drugi ali kasnejši dotik zaslona

break; }

case MotionEvent.ACTION_MOVE: { // premikanje dotikov po zaslonu

break; }

case MotionEvent.ACTION_POINTER_UP: { // dotik (ne zadnji) zapusti zaslon

break; }

case MotionEvent.ACTION_UP: { // zadnji dotik zapusti ekran

break; }

case MotionEvent.ACTION_CANCEL: {break; }

}

return true; // obvestimo sistem, da tu prejemamo podatke

}

43

Za primer si poglejmo, kaj storimo s prvim dotikom zaslona in nato še kako upravljamo premike.

Spodaj je koda, ki se izvede ob prvem dotiku zaslona - (ACTION_DOWN)

pointerIndex = (event.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK)

>> MotionEvent.ACTION_POINTER_INDEX_SHIFT;

id = event.getPointerId(pointerIndex); // pridobimo id dotika za kasnejši dostop

x = event.getX(event.findPointerIndex(id)); // pridobimo koordinate dotika

y = event.getY(event.findPointerIndex(id));

shapeID = likHolder.getPressedShapeID((int)x, (int)y);

// če se dotikamo lika, pogledamo za prilepljene like

if (shapeID != -1)

{

likHolder.checkForGluedShapes(shapeID, shapeID, -1);

// Shranimo podatke o dotiku v mapo (id lika in točko zadnjega dotika

pointerMap2.put(id, new TouchInfo(shapeID, x, y));

}

else

{

// preverimo, ali se dotikamo skladišča likov

if (likProvider.isPointInsideShape( (int)x, (int)y) )

{

pointerMap2.put(id, new TouchInfo(-2, x, y, false, true);

}

else

{

// če dotikamo praznega prostora, ustvarimo točko za vrtenje

// v seznamu likov

likHolder.createRotationReference(x, y);

// shranimo podatke o dotiku, ki bo skrbel za vrtenje likov

pointerMap2.put(id, new TouchInfo(shapeID, x, y, true) );

}

}

44

Spodaj je koda, ki se izvede ob premikanju dotikov po zaslonu - (ACTION_MOVE)

// za vsak element - dotik shranjen v mapi for (int i = 0; i < pointerMap2.size(); i++) { int key = pointerMap2.keyAt(i); TouchInfo value = pointerMap2.valueAt(i); // Poiščemo indeks aktivnega kazalca in preberemo pozicijo

pointerIndex = event.findPointerIndex(key); x = event.getX(pointerIndex); y = event.getY(pointerIndex); // Pogledamo, za koliko se je dotik premaknil po zaslonu float dx = x - value.lastX; float dy = y - value.lastY; // Pogledamo podatke o dotiku if (value.pressedShapeID == -1) { // lika se ne dotikamo if (value.isRotationReference) //Ali je dotik uporabljen za rotacijo?

{ likHolder.updateRotationReferenceAndRotate(x, y);

} } else if (value.pressedShapeID == -2) { // Dotikamo se skladišča lika, lik v skladišču premaknemo likProvider.move(dx, dy); } else { // Dotikamo se lika v seznamu; lik premaknemo likHolder.move(value.pressedShapeID, dx, dy); } // Shranimo zadnjo pozicijo dotika value.lastX = x; value.lastY = y; }

Poleg zgoraj naštetih metod ta razred vsebuje še metodo, ki izbriše vse like v seznamu, metodo, ki pripravi zahtevane like v skladišču in metodo, ki predaja like iz skladišča v seznam. Teh metod ne bom posebej opisoval.

45

Definicija uporabniškega vmesnika

Uporabniški vmesnik sestavimo iz zgornjega razreda, ki upravlja like ter iz treh gumbov, ki bodo nad tem razredom. To določimo v .xml datoteki:

<?xml version="1.0" encoding="UTF-8"?>

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"

android:id="@+id/layout"

android:layout_width="fill_parent"

android:layout_height="fill_parent"

>

<com.dd.remi3.gameplay.SinglePlayerView <!--Dodamo naš razred -->

android:id="@+id/singlePlayerView"

android:layout_width="fill_parent"

android:layout_height="fill_parent"

/>

<!—Dodamo še gumbe-->

<ImageButton

android:id="@+id/options_button"

android:layout_width="48dp"

android:layout_height="48dp"

android:contentDescription="@string/desc"

android:layout_gravity="right|top"

android:layout_margin="4dp"

android:background="@drawable/options_image_button" />

<ImageButton

android:id="@+id/info_button"

android:layout_width="48dp"

android:layout_height="48dp"

android:contentDescription="@string/desc"

android:layout_gravity="right|top"

android:layout_marginRight="53dp"

android:layout_marginTop="4dp"

android:background="@drawable/info_image_button" />

<ImageButton

android:id="@+id/check_shape_button"

android:layout_width="48dp"

android:layout_height="48dp"

android:contentDescription="@string/desc"

android:layout_gravity="left|top"

android:layout_margin="4dp"

android:background="@drawable/ok_image_button" />

</FrameLayout>

Vsak element, do katerega dostopamo iz programa, mora vsebovati svojo oznako id.

To definicijo uporabniškega vmesnika shranimo kot single_player_layout.xml.

46

Vključitev v razred Activity

Da bomo dobili delujočo igro, moramo vse zgornje elemente vključiti v razred, ki je podrazred razreda Activity. V tem razredu bomo uporabili zgornji uporabniški vmesnik ter določili, kaj se zgodi ob kliku gumbov, določili bomo naloge za reševanje, prikaz navodil za reševanje. Tu bomo tudi poskrbeli, da se bo risalna površina osveževala vsakih nekaj milisekund.

Ker je tudi ta razred obsežen (nekaj več kot 700 vrstic), si bomo pogledali samo pomembnejše odseke.

Najprej kreirajmo nov razred:

public class SinglePlayerActivity extends Activity implements OnClickListener, OnLongClickListener {

Naš razred razširja razred Activity, poleg tega pa mora implementirati metode, ki bodo skrbele za izvajanje ob kliku gumbov.

Nato deklariramo spremenljivke (prikazane so samo pomembnejše):

public static final int SHAPE_DP_SIZE = 80; // Konstanta, ki določa velikost likov

public static final int REFRESH_RATE = 30; // Na koliko ms osvežimo

private Thread refreshThread; // Nit, ki bo skrbela za osveževanje

public SinglePlayerView myView; // Površina z liki

public ImageButton optionsButton; // Gumbi

public ImageButton checkForShapesButton;

public ImageButton infoButton;

private boolean drawFrameOnly; // Spremenljivki, ki določata način izrisa likov

private boolean useRandomColors;

// Ti elementi se uporabljajo za prikaz navodil in jih kreiram sproti

RelativeLayout instructionsLayout;

RelativeLayout instructionsContent;

public ImageButton okButton;

public TextView instructionsView;

ImageButton dismissButton; // Gumba bosta postavljena na isto mesto, preklop

ImageButton nextLevelutton; // med njima bo s pomočjo nastavljanja vidljivosti

Levels myLevels; // Razred, v katerem so zapisane stopnje

LevelData[] levelData; // Podatki ene stopnje

// za štetje števila nalog v stopnji

int numOfTasks;

// trenutni rezultat telesa in mreže, ki jih preverjam

int currentShape;

int currentNet;

47

V metodi onCreate poskrbimo za pripravo na igranje igre:

@Override

public void onCreate(Bundle bundle)

{

super.onCreate(bundle);

// brez naslovne vrstice, celozaslonski način, orientacija zaslona

requestWindowFeature(Window.FEATURE_NO_TITLE);

getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);

setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);

// Preračun univerzalne enote dp v točke na zaslonu

Lik.oneUnit = (int) convertDpToPixel(SinglePlayerActivity.SHAPE_DP_SIZE, this);

// določimo uporabniški vmesnik

this.setContentView(R.layout.single_player_layout);

// povezava z elementi uporabniškega vmesnika, za dostop do elementov

myView = (SinglePlayerView) findViewById(R.id.singlePlayerView);

optionsButton = (ImageButton) findViewById(R.id.options_button);

instructionsLayout = (RelativeLayout) findViewById(R.id.instructions_layout);

instructionsView = (TextView) findViewById(R.id.level_instructions);

okButton = (ImageButton) findViewById(R.id.ok_button);

checkForShapesButton =(ImageButton) findViewById(R.id.check_shape_button); instructionsContent = (RelativeLayout) findViewById(R.id.instructions_content);

infoButton = (ImageButton) findViewById(R.id.info_button);

// Stopnje myLevels = new Levels(this);

// pripravimo okno z opisom naloge

prepareInstructionsPage();

// priprava gumbov na sprejemanje klikov

optionsButton.setOnClickListener(this);

okButton.setOnClickListener(this);

checkForShapesButton.setOnClickListener(this);

infoButton.setOnClickListener(this);

// Nit, ki pokliče invalidate() vsakih nekaj ms (definirano s konstanto)

refreshThread = new Thread(new RefreshRunner());

refreshThread.start();

}

Poglejmo si še način osveževanja površine z liki:

class RefreshRunner implements Runnable {

public void run() {

while (!Thread.currentThread().isInterrupted()) {

// če želimo sprožiti zahtevo za ponoven izris iz druge niti, je //potrebno poklicati metodo postInvalidate() namesto invalidate()

myView.postInvalidate();

try {Thread.sleep(REFRESH_RATE); } // izvajanje niti začasno ustavimo

catch (InterruptedException e){ Thread.currentThread().interrupt();

} } } }

48

V razredu Levels so zapisane naloge, ki jih rešujemo. Naloge so shranjene v tabeli objektov tipa LevelData, kjer so zapisani podatki posamezne stopnje.

Razred LevelData:

public class LevelData {

// možni odgovori, zapisani s konstantami

public static final int ANSWER_WRONG_ANSWER = 0;

public static final int ANSWER_LEVEL_COMPLETED = 1;

public static final int ANSWER_PARTLY_COMPLETED = 2;

public static final int ANSWER_ALREADY_USED = 3;

// tekst naloge

public String levelText;

// V primeru, da zahtevamo nekaj odgovorov izmed naštetih, uporabljamo te tabele

public int[] possibleAnswers; // tu se zapišejo možni odgovori

public boolean[] currentAnswers; // sledenje že uporabljenih odgovorov

public int numOfRequiredAnswers; // število zahtevanih odgovorov

// Če zahtevamo točno določen odgovor, ga zapišemo v to spremenljivko

public int requiredAnswer;

public boolean levelCompleted; // Za informacijo

public int timeToComplete; // Čas

// število likov, ki bodo na voljo

public int numOfSmallSquares;

public int numOfSmallEquilateralTriangles;

public int numOfIsoscelesTriangles;

public int numOfRectangles;

public int numOfBigSquares;

public int numOfBigEquilateralTriangles;

// Konstruktor. Tu shranimo čas, ki bo na voljo in poskrbimo za inicializacijo

public LevelData(int time )

{ … }

// Če bo naloga zahtevala točno določen odgovor, npr. točno določeno mrežo ali telo, bomo dodali pogoj s to metodo

public void addRequiredAnswer(int answer)

{ … }

// Če bo možnih več odgovorov, bomo pogoje dodali s to metodo

public void addPossibleAnswers(int... answers)

{ … }

//s klicem te metode določimo koliko odgovorov zahtevamo (npr. 2 mreži od štirih)

public void addNumberOfRequiredAnswers(int numOfAnswers)

{ … }

// Metoda vrne število zahtevanih odgovorov

public int getNumberOfRequiredAnswers()

{ … }

// Metoda vrne trenutno število pravilnih odgovorov public int getCorrectAnswers()

{ … }

// Metoda bo preverila, ali je dan odgovor pravilen. Metoda vrne eno od konstant, // ki predstavljajo odgovor

public int checkAnswer(int ans)

{ … }

}

49

V razredu Levels uporabljamo razred LevelData, da sestavimo naloge:

public class Levels {

// konstanta določa največje število nalog na stopnjo.

// konstanto uporabimo, ker se število uporablja za računanje pravilnih odgovorov.

public static final int MAX_TASKS = 3; private LevelData[][]levelData; // tabela, v kateri so zapisane stopnje

private int currentLevel; // za sledenje trenutni stopnji

// Konstruktor. Parameter je objekt tipa Context, da lahko dostopamo do prevodov

public Levels(Context context)

{

currentLevel = 0; // inicializacija stopnje

levelData = new LevelData[5][MAX_TASKS]; // ustvarimo tabelo

// ustvarimo objekt v tabeli

levelData[0][0] = new LevelData(30);

// Navodilo naloge dodamo iz datoteke. S tem poskrbimo za pravilen prevod

levelData[0][0].levelText = context.getResources().getString(R.string.level_1_4piramida);

// Pri prvi stopnji zahtevamo točno določen odgovor – štiristrano prizmo

levelData[0][0].addRequiredAnswer(ShapeCheckerV2.TELO_STIRISTRANA_PIRAMIDA); //določimo koliko likov bo na voljo

levelData[0][0].numOfBigEquilateralTriangles = 4;

levelData[0][0].numOfBigSquares = 1;

levelData[0][0].numOfSmallSquares = 1;

levelData[0][0].numOfSmallEquilateralTriangles = 4;

… // podobno so definirane še ostale stopnje }

// To metodo uporabimo, če želimo ponovno začeti igro

public void reset()

{…}

// Metoda vrne podatke o stopnji

public LevelData[] getNextLevelData()

{…}

// metoda, s katero lahko nastavimo trenutno stopnjo

public void setCurrentLevelNuber(int levelNumber)

{…}

// Metoda vrne trenutno stopnjo

public int getCurrentLevelNumber()

{…}

}

To so glavni elementi, katere moramo še logično povezati. Določimo, kaj se zgodi ob kliku posameznega gumba, poleg tega pa še preverimo, ali imajo vse naloge v stopnji oznako, da so končane. Šele nato dovolimo prehod v novo stopnjo. Paziti moramo še, da ob izhodu iz igre shranimo podatke o stopnjah, da lahko kasneje igranje nadaljujemo.

50

4 Končni rezultat

Slika 20: meni igre

Slika 21: navodilo naloge

Slika 22: sestavljena mreža piramide

51

Slika 23: zapiranje mreže v geometrijsko telo

Slika 24: sporočilo, da je naloga končana

Slika 25: stopnja z dvema nalogama

52

Slika 26: mreža tristrane prizme

Slika 27: animacija zapiranja tristrane prizme

53

Slika 28: možnosti animacije

Slika 29: neprosojne stranice

54

Slika 30: okvir geometrijskega telesa

5 Mnenja Ko je bila igra dovolj razvita, da je bila primerna za predstavitev, sem obiskal nekaj profesorjev in jim predstavil cilje svojega diplomskega dela. Nato sem predstavil samo igro – najprej sem razložil navodila in odigral eno stopnjo, nato pa so profesorji sami preigrali vse stopnje v igri. Igro sem predstavljal z dvema napravama: tabličnim računalnikom Samsung Galaxy Tab (Android 2.2) ter telefonom Samsung Galaxy Nexus (Android 4.1).

Ko so profesorji zaključili z igranjem igre, sem jim zastavil naslednja vprašanja:

- Ali je problem prostorske predstave pri učencih zelo opazen? - Ali je temu problemu treba posvečati posebno pozornost? - Ali poznate kakšne didaktične računalniške igre? Ali jih kdaj predstavite

učencem? - Ali menite, da bi igra pripomogla k izboljšanju prostorske predstave?

55

- Ali bi igro omenili učencem? Bi jo učencem tudi predstavljali ali mogoče celo uporabljali pri pouku?

Odgovori profesorjev:

Prof. Goran Vujović, Tehniška gimnazija, TŠC Kranj

- Ali je problem prostorske predstave pri učencih zelo opazen?

Da, definitivno. Opazimo ga pri geometriji v prostoru, vendar pa je bolj očiten pri vektorjih v tridimenzionalnem prostoru. Ko na tablo narišemo tridimenzionalni koordinatni sistem in krajevne vektorje, moramo narisati tudi pravokotno projekcijo teh vektorjev na xy-ravnino, kar pa veliko dijakov ne zna. Prav tako si dijaki ne znajo predstavljati naloge, ki jo vsako leto rešujemo, kjer je pri piramidi treba izračunati kot med dvema stranicama.

- Ali je temu problemu treba posvečati posebno pozornost?

Da, menim, da bi bilo treba temu posvečati pozornost, vendar tega ne počnemo. Razlog je v tem, da smo profesorji omejeni s časom in z učnim načrtom, najvišjo prioriteto pa ima matura. Pomembno je, da so dijaki dobro pripravljeni na maturo in ker se s problemom prostorske predstave na maturi ne srečujejo, se s tem posebej ne spopadamo.

- Ali poznate kakšne didaktične računalniške igre? Ali jih kdaj predstavite

učencem?

Poznam igro Abaku. To je češka spletna igra, ki je podobna igri Scrabble (sestavljanje besed), kjer je iz več številk potrebno sestaviti račun. Recimo, da imaš številke 1, 2, 3 in 7. Potem lahko iz teh številk sestaviš račun 3 * 7 = 21.

- Ali menite, da bi igra pripomogla k izboljšanju prostorske predstave?

- Ali bi igro omenili učencem? Bi jo učencem tudi predstavljali ali mogoče celo

uporabljali pri pouku?

Igra se mi zdi izredno zanimiva, ker je aktivna. Predlagam, da bi jo uporabljali tudi v osnovni šoli. Lahko bi jo uporabljali tudi v nižjih razredih, ne samo v devetem razredu. Učenci bi lahko s pomočjo žičnatega modela ugotavljali, kako ploskve združiti, da dobiš želeno geometrijsko telo. Zelo dobro se mi zdi to, da vsebuje 3D animacijo, poleg tega pa je zanimivo tudi to, da je pri nalogah na voljo več likov in mora igralec izbrati prave like glede na nalogo.

Če se postavim v vlogo učencev, je pa igra še veliko bolj zanimiva – in če bi bil še enkrat učenec, bi si želel pouk, ki bi bil bolj pester tudi na račun takih iger in dobro izkoriščenih elektronskih naprav. Profesorji so pogosto preveč dolgočasni, monotoni in ponavljajoči se, zaradi tega pa se učenci premalo naučijo v šoli.

Računalniška oprema ne bo nikoli mogla nadomestiti dokazovanja izrekov na tabli, saj lahko na tabli namenoma narediš napako, da ugotoviš, ali dijaki spremljajo pouk,

56

ali pa se lahko sproti odločaš, na kakšen način rešiš nalogo. Vendar sem prepričan, da so elektronski učbeniki, podprti z dobrimi interaktivnimi vsebinami prihodnost. Kot zanimivost lahko povem, da so se v Južni Koreji za to že odločili.

Prof. Alenka Jurančič, OŠ Preddvor

- Ali je problem prostorske predstave pri učencih zelo opazen?

Problem prostorske predstave se najprej opazi v 8. razredu pri obravnavanju kocke in kvadra. Nekateri učenci zelo težko narišejo skico telesa, zelo težko pa si tudi predstavljajo telesno diagonalo.

- Ali je temu problemu treba posvečati posebno pozornost?

Temu se prav posebej nismo posvečali.

- Ali poznate kakšne didaktične računalniške igre? Ali jih kdaj predstavite

učencem?

Včasih smo imeli igro za razredno stopnjo, s katero so učenci trenirali računanje. Za predmetno stopnjo pa iger ne poznam. Zato pa pri urah matematike pogosto uporabljamo projektor in platno, da si pogledamo vsebine in animacije iz spletne strani E-UM.

- Ali menite, da bi igra pripomogla k izboljšanju prostorske predstave?

Igra se mi zdi zanimiva in bi lahko pripomogla k izboljšanju prostorske predstave, vendar bi morali igro testirati z dvema skupinama učencev, da bi lahko primerjali rezultate, iz katerih bi nato prišli do zaključka, kako uspešna je pri tem igra. V igri bi lahko imeli liki narisane še telesne diagonale.

- Ali bi igro omenili učencem? Bi jo učencem tudi predstavljali ali mogoče celo

uporabljali pri pouku?

Igro bi vsekakor predstavila učencem. Igro bi lahko tudi uporabljali pri pouku, vendar bi za to vsi učenci potrebovali ustrezne naprave.

Prof. Francka Planinc, OŠ Preddvor

- Ali je problem prostorske predstave pri učencih zelo opazen?

To je zelo odvisno od razvoja posameznika. Razlike med učenci so lahko zelo velike, prav tako pa lahko nekateri učenci v enem letu zelo napredujejo. Če je v osmem razredu za nekoga prostorska predstava zahtevna, ima lahko v devetem razredu prostorsko predstavo že veliko bolj razvito. Spet pri drugih pa je ta razlika lahko zelo majhna.

57

- Ali je temu problemu treba posvečati posebno pozornost?

Prostorsko predstavo je treba čim bolj razvijati, mi si pomagamo z žičnatimi modeli geometrijskih teles.

- Ali poznate kakšne didaktične računalniške igre? Ali jih kdaj predstavite

učencem?

Računalniških didaktičnih iger ne poznam, poznam pa klasične igre, ki jih tudi pogosto uporabljamo. To so igre matematične igre s kartami, dominami…

- Ali menite, da bi igra pripomogla k izboljšanju prostorske predstave?

Igra bi bila otrokom najbrž zanimiva. Če bi jo radi igrali in dovolj pogosto, bi bil učinek najbrž zelo dober. Se pa tudi jaz strinjam, da bi bilo zanimivo izvesti primerjavo med skupinama, kjer bi ena skupina igrala igro, druga pa ne.

- Ali bi igro omenili učencem? Bi jo učencem tudi predstavljali ali mogoče celo

uporabljali pri pouku?

Raje imam klasične igre, vendar bi vseeno učencem igro predstavila.

Prof. Jožica Mlakar Broder, OŠ Preddvor

- Ali je problem prostorske predstave pri učencih zelo opazen?

Nekateri učenci imajo s tem probleme, večina pa s tem nima večjih težav.

- Ali je temu problemu treba posvečati posebno pozornost?

Mislim da ne, pri pouku se do sedaj s tem nismo posebej ukvarjali, le takrat, ko je snov to zahtevala.

- Ali poznate kakšne didaktične računalniške igre? Ali jih kdaj predstavite

učencem?

Ne, računalniških didaktičnih iger ne poznam.

- Ali menite, da bi igra pripomogla k izboljšanju prostorske predstave?

Najbrž bi pripomogla k temu, saj je vsaka vaja dobrodošla

- Ali bi igro omenili učencem? Bi jo učencem tudi predstavljali ali mogoče celo

uporabljali pri pouku?

Igro bi predstavila, seveda ob pogoju, da bi imeli vsi učenci ustrezno opremo.

58

6 Zaključek Ugotovili smo, da so video igre tesno povezane z učenjem, čeprav ob besedi »učenje« le redkokdo pomisli na igre, ki jih otroci igrajo na računalnikih in mobilnih telefonih. Prvi razlog je seveda ta, da skoraj nobena igra nima vsebine, ki se jih danes učenci učijo v šolah, drugi razlog je pa ta, da so igre zabavne, čeprav se mora uporabnik oz. igralec naučiti veliko novih spretnosti in dejstev, če želi igro preigrati do konca.

Zasnova igre, ki je namenjena za izobraževanje, je zelo zahtevna. Najti moramo način, kako vklopiti želena poglavja v samo igro, saj mora igra zadržati vse elemente, ki jo naredijo zabavno. Namen takih iger ne sme biti zamenjava učbenika in delovnega zvezka, temveč njuno dopolnilo.

Pri izdelavi iger (in aplikacij) se srečamo z ogromno problemi, ki so v fazi zasnove težko predvidljivi. Zato je pomembna podrobna izdelava načrta, kjer je treba predvideti čim več podrobnosti, da se izognemo sprotnim popravkom in dopolnilom že narejenih komponent. Pri načrtu moramo tudi upoštevati možne ali načrtovane posodobitve, zato morajo imeti nekateri deli programa modularno zasnovo, da si olajšamo delo, ki nas čaka v prihodnosti.

Za konec bi še dodal svoj pogled na prihodnost iger in izobraževanja. Ena igra v procesu izobraževanja ne more narediti bistvene spremembe. Vendar pa bi lahko posodobili način izobraževanja tako, da bi prešli na elektronska gradiva, katera bi imeli učenci na svojih tabličnih računalnikih. Tako bi lahko na koncu snovi ali poglavja vključili igre, ki bi se na to navezovale. Čeprav bi učenci še vedno potrebovali zvezek in svinčnik, bi bolj pogosto uporabljali elektronsko gradivo (učbenik in delovni zvezek), poleg tega pa bi obstajala tudi večja možnost, da bi si kakšno snov pogledali (in preigrali) vnaprej.

7 Viri 1. Brookhaven National Laboratory. URL:

http://www.bnl.gov/bnlweb/history/images/D2231008_TENNIS4TWO-300px.jpg (17. 8. 2012)

2. Wikipedia. World of Warcraft. URL: http://en.wikipedia.org/wiki/World_of_Warcraft (citirano 17. 8. 2012)

3. Steam stats. URL: http://store.steampowered.com/stats/ (citirano 17. 8. 2012) 4. Entertainment Software Asociation. Game Player Data. URL:

http://www.theesa.com/facts/gameplayer.asp (citirano 17. 8. 2012) 5. Business Degree. URL: http://www.businessdegree.net/little-games-big-business/

(citirano 17. 8. 2012)

59

6. Stat spotting. URL: http://statspotting.com/2011/11/angry-birds-statistics-200000-years-of-angry-birds-have-been-played/ (citirano 17. 8. 2012)

7. Paul Gee, J.(2007). What Video Games Have To Teach Us About Learning And Literacy. Palgrave Macmillan.

8. Devlin, K. (2011). Mathematics Education for a New Era: Video Games As a Medium for Learning. A K Peters.

9. International Data Corporation. Tržni delež operacijskih sistemov pametnih telefonov. URL: http://www.idc.com/getdoc.jsp?containerId=prUS23638712 (citirano 23. 8. 2012)

10. Data Corporation. Tržni delež operacijskih sistemov tabličnih računalnikov. URL: http://www.idc.com/getdoc.jsp?containerId=prUS23371312 ( citirano 23. 8. 2012)

11. developer.android.com. Android NDK. URL: http://developer.android.com/tools/sdk/ndk/index.html (citirano 26. 8. 2012)

12. Oracle.com, URL: http://www.oracle.com/technetwork/java/javase/downloads/index.html (citirano 26. 8. 2012)

13. developer.android.com. SDK. URL: http://developer.android.com/sdk/index.html (citirano 26. 8. 2012)

14. Eclipse Foundation. Eclipse IDE URL: http://www.eclipse.org/downloads/ (citirano 26. 8. 2012)

15. developer.android.com. ADT. URL: http://developer.android.com/sdk/installing/installing-adt.html (citirano 26. 8. 2012)

16. developer.android.com. Android Emulator Limitations. URL: http://developer.android.com/tools/devices/emulator.html#limitations (citirano 26. 8. 2012)

17. Wikipedia. Debugging. URL: http://en.wikipedia.org/wiki/Debugging (citirano 10. 9. 2012)

18. developer.android.com. Verzije in razširjenost. URL: http://developer.android.com/about/dashboards/index.html#Platform (citirano 11. 9. 2012)

19. developer.android.com. Activity. URL: http://developer.android.com/reference/android/app/Activity.html (citirano 11. 9. 2012)

20. developer.android.com. Supporting different screens. URL: http://developer.android.com/training/basics/supporting-devices/screens.html (citirano 11. 9. 2012)

21. developer.android.com. Supporting different screens. URL: http://developer.android.com/training/multiscreen/screensizes.html (citirano 11. 9. 2012)

22. developer.android.com. Supporting different densities. URL: http://developer.android.com/training/multiscreen/screendensities.html (citirano 11. 9. 2012)

23. developer.android.com. Canvas. URL: http://developer.android.com/reference/android/graphics/Canvas.html (12.9.2012)

60

24. Wikipedia. Linked data structure. URL: http://en.wikipedia.org/wiki/Linked_data_structure (citirano 13. 9. 2012)

25. developer.android.com. OpenGL. URL: http://developer.android.com/guide/topics/graphics/opengl.html (citirano 14. 9. 2012)

26. developer.android.com. View. URL: http://developer.android.com/reference/android/view/View.html (citirano 14. 9. 2012)