Liikumine


Eelnevas näites liigutasime nupuvajutusel ühe sammu kaupa. Samuti sai varem panna kujundi hiire järgi liikuma. Kui aga panna sammud iseenesest ja piisava sagedusega korduma, siis kasutajale jääb mulje liikumisest ilma, et selle jaoks peaks ta midagi ise pidevalt tegema.


Korduvalt käivituv käsk


Tehniliselt saab käsu korduvalt käivitumise panna kirja kujul


window.onload=setInterval("paremale()", 500);


Lahtiseletatult pannakse funktsioon paremale() tööle iga viiesaja millisekundi tagant ehk praegusel juhul kaks korda sekundis. Nõnda siis liigubki ruut me silmade ees vaiksete hüpetega edasi. Ooteaega vähendades või sammu pikkust suurendades saab liikumist sujuvamaks või kiiremaks muuta. Samas seab masina tehniline võimsus piltide joonistamise sagedusele piirid. Enamasti ei tasu veidigi suurema joonistustahvli korral loota ülejoonistusajale alla 100 millisekundi.


<!DOCTYPE html>

<html>

<head>

<title>Joonis</title>

<script type="text/javascript">

var x=20, samm=5;

function joonista(){

var t=document.getElementById("tahvel");

var g=t.getContext("2d");

g.clearRect(0, 0, t.width, t.height);

g.fillRect(x, 20, 50, 50); //x, y, laius, kõrgus

}

function vasakule(){

x=x-samm;

joonista();

}

function paremale(){

x=x+samm;

joonista();

}

window.onload=setInterval("paremale()", 500);

</script>

</head>

<body>

<h1>Joonis</h1>

<canvas id="tahvel" width="300" height="200"

style="background-color:yellow"></canvas><br />

<input type="button" value="v" onclick="vasakule()" />

<input type="button" value="p" onclick="paremale()" />

</body>

</html>







Ülesandeid


* Ruut liigub vasakult paremale, klahvidega saab ruutu samal ajal liigutada alla ja üles

* Korraga liigub kaks ruutu - üks paremale, teine vasakule

* Vasakule liikuva ruudu suurus liikumise ajal väheneb

* Sammu pikkus ja sellega koos liikumise kiirus valitakse juhuslikult



Liikumise suuna määramine


Siiani liikus ruut ühes suunas, suuna määras muutuja nimega samm. Kui sellele sammule anda negatiivne väärtus, siis liigub ruut vasakule. Liikumissuuna muutmiseks rakenduse töö ajal tuleb ka sammu väärtust muuta. Eraldi lisati muutuja nimega kiirus, mille abil võimalik määrata, kui ruttu ruut liigub. Suuna määramiseks tuleb kiiruse väärtus lihtsalt sammule üle kanda - olgu siis pluss- või miinusmärgiga. Ja kui tahta ruut seisma jätta, piisab, kui sammu pikkuseks sättida null.Alla siis vastavad nupud, et kasutaja võiks vastavaid käsklusi käivitada.


Nuppude väärtuseks olevad &lt;- ja -&gt; võivad tunduda raskelt mõistetavad.


      <input type="button" value="&lt;-" onclick="vasakule()" />
      <input type="button" value="x" onclick="seis()" />
      <input type="button" value="-&gt;" onclick="paremale()" />

Tegelikult aga tegemist erisümbolitega, mille abil saab sinna noole kujutise kuvada. &lt; tähendab "less than" ehk "väiksem kui" ehk siis sümbol "<". Teistpidine &gt; on "greater than" ehk "suurem kui" ehk ">". Kuna need märgid niisamuti kirjutatuna tähistavad HTML koodis erisümboleid, siis ei või neid otse nuputeksti kohale kirjutada, et saada noole kuju <- tekitada. Asenduse abil aga õnnestub ning nupu silt täiesti loetav.



<!doctype html>
<html>
  <head>
    <title>Liikumine</title>
        <script>
           var x=20, kiirus=2, samm=kiirus;
           function joonista(){
             var t=document.getElementById("tahvel");
             var g=t.getContext("2d");
             g.clearRect(0, 0, t.width, t.height);
             g.fillRect(x, 20, 50, 50);
           }
           function liigu(){
             x=x+samm;
             joonista();
           }
           function vasakule(){
             samm=-kiirus;
           }
           function seis(){
             samm=0;
           }
           function paremale(){
             samm=kiirus;
           }
        </script>
  </head>
  <body onload="setInterval('liigu()', 100)">
      <canvas id="tahvel" width="300" height="200"  
                  style="background-color:yellow"></canvas><br />
      <input type="button" value="&lt;-" onclick="vasakule()" />
      <input type="button" value="x" onclick="seis()" />
      <input type="button" value="-&gt;" onclick="paremale()" />
  </body>
</html>



Ülesandeid


* Pane näide käima, uuri. Muuda liikumise kiirust

* Võimalda ruudul liikuda vasakule-paremale suuna asemel üles-alla

* Loo nupud, et saaks määrata liikumise kõigi nelja ilmakaare suunas.



Seiskumine vasakus servas


Nõnda järjest liikudes on ruut küllalt varsti ekraanilt läinud. Ise pidevalt juhtides saab usinasti liikumist sättida. Kui aga tegemist hiljem rakendusega, kus korraga enam kujundeid liikumas, siis ei saa kõigil pidevalt käsitsi silma peal pidada ja kontrollida, et kuidas keegi käitub. Kontrollimiseks sobib tingimuslause nimega if. Praegusel juhul, kui ruut liigub liiga vasakule ehk x läheb negatiivseks, siis paras aeg öelda, et ta seisma jääks. Ning kasulik on ruudule märkida ka, et ta serva juurde tagasi tuleks (x-i väärtuseks arv 0).


             if(x<0){seis(); x=0;}

Siis pääseb ruut näiteks paremale suunava nupu vajutamisel taas liikuma. Muidu tekiks imelik olukord, kus pole võimalik ka üle ääre sattununa sealt tagasi minna, sest nullist väiksema iksi puhul antakse kohe seiskumiskäsklus.


<!doctype html>
<html>
  <head>
    <title>Liikumine</title>
        <script>
           var x=100, kiirus=2, samm=-kiirus;
           function joonista(){
             var t=document.getElementById("tahvel");
             var g=t.getContext("2d");
             g.clearRect(0, 0, t.width, t.height);
             g.fillRect(x, 20, 50, 50);
           }
           function liigu(){
             if(x<0){seis(); x=0;}
             x=x+samm;
             joonista();
           }
           function vasakule(){
             samm=-kiirus;
           }
           function seis(){
             samm=0;
           }
           function paremale(){
             samm=kiirus;
           }
        </script>
  </head>
  <body onload="setInterval('liigu()', 100)">
      <canvas id="tahvel" width="300" height="200"  
                  style="background-color:yellow"></canvas><br />
      <input type="button" value="&lt;-" onclick="vasakule()" />
      <input type="button" value="x" onclick="seis()" />
      <input type="button" value="-&gt;" onclick="paremale()" />
  </body>
</html>


Ülesandeid


* Tee näide läbi

* Pane ruut liikuma alt üles. Ruut seiskub ülesse serva jõudmisel

* Ruutu saab liigutada iga ilmakaare suunas. Seiskub nii vasakusse kui ka ülemisse serva jõudmise puhul.



Seespüsimise kontroll


Vasaku ja ülemise serva tabamise kontroll on suhteliselt lihtne vähemasti ruudu puhul. Kuna ruut joonistatakse vasaku ülemise nurga koordinaatide järgi, siis juhul, kui need on nullist väiksemad, siis järelikult ollakse servast üle läinud. Parema ja alumise poolega on veidi rohkem arvutamist. Parema serva koordinaadi saab kätte liites vasaku serva koordinaadile ruudu laiuse. Kui nüüd selle parema serva koordinaadi väärtus ületab tahvli laiust ehk tahvli parema serva koordinaadi väärtust, sellisel juhul on ruut sealtpoolt üle läinud.


Iseenesest on võimalik nõnda tingimusi sättides ruudu seiskamist täiesti kontrollida. Arvestades aga tulevikku ning võimalust, et kontrollitavaid kujundeid tuleb rohkem, siis mitmekülgsema kontrolli tarbeks on hea teha omaette funktsioon. Näiteks selline:


           function kasSees(uusX){
             if(uusX<0){return false;}
             if(uusX+laius>t.width){return false;}
             return true;
           }

Funktsiooni nimeks on kasSees - nagu nimest aimata võib, siis sealt vastatakse kas jah või ei. Ehk siis true või false. Selle järgi siis võimalik hiljem otsustada kuidas käituda - kui ruudu uuritav asukoht on tahvli sees, võib sinna julgelt asuda. Kui mitte, ei tasu sinna ronida. Funktsiooni ümarsulgude sees olev uusX tähendab, et funktsioonile etteantav väärtus nimetatakse funktsiooni sees kasutamiseks uusX-i nime alla ning sealtkaudu saab tema sisu pruukida. Edasi juba järgnevad kontrollid ja vastused.


             if(uusX<0){return false;}

teatab, et kui etteantud parameetri (uusX) väärtus on väiksem kui null, siis funktsioon tagastab (return) false, ehk siis ruut pole tervikuna tahvli sees. Sama lugu parema serva kontrolliga. Muutujas t meil eelnevalt tahvli andmed olemas. Seega siis avaldis


              uusX+laius>t.width

kontrollib, et kas ruudu parema serva koordinaadi väärtus (uusX+laius) ületab tahvli laiust (t.width).


Kui mõlemad kontrollid edukalt läbitud, siis järelikult ruut x-telge pidi alas sees ning funktsioon võib tagastada väärtuse, et on sees küll (return true).


Liikumisfunktsioonis saab eelneva kontrolli tulemust kasutada.


             if(kasSees(x+samm)){
               x=x+samm;                 
             } else {
               seis();
             }

Esimene lause siis vaatab, et kui ruudu eeldatav uus asukoht (x+samm) on tahvli sees, siis minnakse sinna uude kohta kohale (x=x+samm). Muul juhul jäädakse seima (seis()).


<!doctype html>
<html>
  <head>
    <title>Liikumine</title>
        <script>
           var x=100, laius=50;
           var kiirus=2, samm=-kiirus;
           var t, g; //tahvel, graafiline kontekst
           
           function algus(){
             t=document.getElementById("tahvel");
             g=t.getContext("2d");
             setInterval('liigu()', 100);
           }
           function joonista(){     
             g.clearRect(0, 0, t.width, t.height);
             g.fillRect(x, 20, laius, 50);
           }
           function kasSees(uusX){
             if(uusX<0){return false;}
             if(uusX+laius>t.width){return false;}
             return true;
           }
           function liigu(){
             if(kasSees(x+samm)){
               x=x+samm;                 
             } else {
               seis();
             }
             joonista();
           }
           function vasakule(){
             samm=-kiirus;
           }
           function seis(){
             samm=0;
           }
           function paremale(){
             samm=kiirus;
           }
        </script>
  </head>
  <body onload="algus()">
      <canvas id="tahvel" width="300" height="200"  
                  style="background-color:yellow"></canvas><br />
      <input type="button" value="&lt;-" onclick="vasakule()" />
      <input type="button" value="x" onclick="seis()" />
      <input type="button" value="-&gt;" onclick="paremale()" />
  </body>
</html>




Ülesandeid


* Pane näide tööle. Muuda ruudu suurust ning veendu, et näide töötab endiselt.

* Pane ruut liikuma ülalt alla ning selles suunas mõlemast servast seisma

* Ruutu saab liigutada iga ilmakaare suhtes. Ruut seiskub, kui jõuab serva.



Ruudu kutsumine hiirega


Nuppudega saab lehel toimetada küll. Mõnikord aga animatsioonide ja mängude juures mõistlik, kui õnnestub otse lehel olles kujundeid juhatada. Siinjuures aitavad samamoodi hiirevajutused nagu õpikus eespool kirjeldatud. Väike hoiatus: kui lehte vaadata mobiiliekraanil, siis seal tavalised hiiresündmused ei toimi, sest mobiil püüab korraga mitut näppu jälgida ning selle tarbeks on loodud touch-event. Aga sellest edasipidi.


Tahvli küljes olevale onmousedown-sündmuse külge sidusime funktsiooni hiirAlla, mille parameetrina tulnud e-ks nimetatud väärtuse kaudu saab kätte hiire andmed. Arvutus e.clientX-tahvlikoht.left annab hiire x-koordinaadi väärtuse tahvli asukoha suhtes. See püüti praegu muutujasse nimega hx (hiire x).


Praegusel juhul otsustatakse hiire järgi, et kas ruut peaks liikuma vasakule või paremale. Kui hiire x-koordinaadi väärtus on suurem, kui ruudu x-koordinaadi väärtus, siis asub hiir ruudust paremal ning järelikult peaks ruut liikuma paremale, kui soovime, et ta hiire poole tuleks. Ehk siis ruudu liikumise sammuks saab koodi algul märgitud kiirus (mis hetkel positiivse väärtusega). Kui hiir sattus ruudust vasakule, siis sammuks saab kiiruse vastandarv, ehk siis ruut hakkab liikuma vasakule.


           function hiirAlla(e){
             var tahvlikoht=t.getBoundingClientRect();
             var hx=e.clientX-tahvlikoht.left;
             if(hx>x){samm=kiirus;}
             else{samm=-kiirus;}
           }

Edasi kood tervikuna.


<!doctype html>
<html>
  <head>
    <title>Liikumine</title>
        <script>
           var x=100, laius=50;
           var kiirus=2, samm=-kiirus;
           var t, g; //tahvel, graafiline kontekst
           
           function algus(){
             t=document.getElementById("tahvel");
             g=t.getContext("2d");
             setInterval('liigu()', 100);
           }
           function joonista(){     
                 g.clearRect(0, 0, t.width, t.height);
                 g.fillRect(x, 20, laius, 50);
           }
           function kasSees(uusX){
             if(uusX<0){return false;}
             if(uusX+laius>t.width){return false;}
             return true;
           }
           function liigu(){
             if(kasSees(x+samm)){
               x=x+samm;                 
             } else {
               seis();
             }
             joonista();
           }
           function hiirAlla(e){
             var tahvlikoht=t.getBoundingClientRect();
             var hx=e.clientX-tahvlikoht.left;
             if(hx>x){samm=kiirus;}
             else{samm=-kiirus;}
           }
           function seis(){
             samm=0;
           }

        </script>
  </head>
  <body onload="algus()">
      <canvas id="tahvel" width="300" height="200"  
                  style="background-color:yellow" 
                          onmousedown="hiirAlla(event)"></canvas><br />

  </body>
</html>



Ülesandeid


* Pane näide käima.

* Pane ruut liikuma ülalt-alla suunas (vertikaalselt). Võimalda selles sihis ruutu enese poole kutsuda.

* Muuda koodi nõnda, et hiirevajutus lükkaks ruutu pigem hiirest eemale.

* Ruut saab liikuda kõigi nelja ilmakaare suhtes. Võimalda igal pool ruutu hiirest eemale liikuma lükata (puhuda).



Liikumiskiiruse määramine hiirega


Eelmises näites lihtsalt vaadati, kuidas ruutu hiire poole meelitada. Arvestades aga kaugust hiirest, saab nõnda määrata ruudu liikumise kiiruse. Olgu siis nii, et lähemale vajutus tõmbab/lükkab tugevamini, või kehtib sama kaugema vajutuse kohta. Üheks mooduseks oleks öelda, et uueks ruudu liikumise sammuks saab kaugus hiire ja ruudu vahel (samm=hx-x). Sellisel puhul aga oleks ruut esimese sammuga juba hiire juures, teise sammuga sama palju möödas. Ning vähegi suurema sammude tiheduse ehk kaadrisageduse ja pikema sammu korral juba ekraanilt väljas. Sammu võib veidi väiksemas võtta seda nulli ja ühe vahel oleva kiiruskoefitsiendiga korrutades. Näiteks, kui see kordaja on 0,1 (arvutikoodis vaja koma asemel punkt kirjutada), siis kui hiir vajutatakse ruudust 30 punkti kaugusele, saab tegelikuks sammu pikkuseks kolm punkti, mida on silmaga juba suhteliselt sujuv vaadata.


             samm=(hx-x)*kiiruskoef;

Muu jääb üllatuslikult samaks, aga kiiruse muutmise paindlikkus on märgatavalt suurem.


<!doctype html>
<html>
  <head>
    <title>Liikumine</title>
        <script>
           var x=100, laius=50;
           var kiirus=2, samm=-kiirus;
           var kiiruskoef=0.1;
           var t, g; //tahvel, graafiline kontekst
           
           function algus(){
             t=document.getElementById("tahvel");
                 g=t.getContext("2d");
                 setInterval('liigu()', 100);
           }
           function joonista(){     
                 g.clearRect(0, 0, t.width, t.height);
                 g.fillRect(x, 20, laius, 50);
           }
           function kasSees(uusX){
             if(uusX<0){return false;}
                 if(uusX+laius>t.width){return false;}
                 return true;
           }
           function liigu(){
             if(kasSees(x+samm)){
               x=x+samm;                 
             } else {
               seis();
             }
             joonista();
           }
           function hiirAlla(e){
             var tahvlikoht=t.getBoundingClientRect();
             var hx=e.clientX-tahvlikoht.left;
             samm=(hx-x)*kiiruskoef;
           }
           function seis(){
             samm=0;
           }

        </script>
  </head>
  <body onload="algus()">
      <canvas id="tahvel" width="300" height="200"  
                  style="background-color:yellow" 
                          onmousedown="hiirAlla(event)"></canvas><br />

  </body>
</html>

Ülesandeid


* Võimalda liikumise kiirust määrata ülalt-alla liikuva ruudu puhul.

* Ruut saab liikuda iga ilmakaare suunas. Samuti saab hiire abil määrata liikumise kiirusi.


* Pane ristkülik ekraanil laiustpidi suurenema

* Pane ristkülik ekraanil suurenema hiirevajutuse peale

* Üks hiirevajutus paneb ristküliku suurenema, teine vähenema

* Vähenemisel jääb ristküliku parem külg paigale. Nõnda on võimalik kordamööda hiirevajutuste abil jäljendada ussikese liikumist edasi.

* Ussikene pole enam ristkülik, vaid on ovaal

* Ussikene koosneb mitmest üksteise sappa ühendatud ovaalist.