Animaatio ja satunnaisuus

Satunnaisuus

Edellisessä luvussa tutustuit Processinging setup() ja draw() -metodeihin. Nyt pääset vihdoin luomaan liikettä töihisi käyttämällä satunnaisuutta draw-metodin komennoissa!

Aiemmin olet määritellyt metodien parametrien arvot kiinteillä lukuarvoilla. Parametrit ovat olleet muuttumattomia ohjelman jokaisella suorituskerralla. Eli esimerkiksi komento ellipse(0,0,100,100) piirtää läpimitaltaan sadan pikselin ympyrän ruudun vasempaan ylänurkkaan jokaisella suorituskerralla. Jos arvoja muutetaan, ympyrä tulee piirretyksi eri kohtaan ruutua.

Kokeile nyt lisätä satunnaisuutta tämän yksinkertaisen esimerkin avulla. Ohjelma arpoo point-metodin parametreiksi satunnaisen x- ja y-koordinaatin random-metodin avulla:

void setup(){
 // täällä oleva koodi suoritetaan vain kerran 
}

void draw(){
  // täällä oleva koodi suoritetaan oletusarvoisesti
  // 60 kertaa sekunnissa kunnes ohjelma suljetaan
  point(random(100), random(50, 100));
}

Processing suorittaa draw-metodin ja sen sisältämät komennot yhä uudestaan ja uudestaan ohjelman suorituksen aikana. Jokaisen kerran kun draw-metodi suoritetaan, kirjoittamasi ohjelma piirtää pisteen ruudulle. Koska piste saa sattumanvaraiset parametrit koordinaateiksi, piste piirretään jokaisella kierroksella eri kohtaan ruutua.

Random-metodin parametriksi annetaan arvottavan luvun minimi ja maksimi. Jos parametreja on vain yksi, arvotaan luku nollan ja annetun parametrin välillä. Nyt koodi arpoo siis x-koordinaatin arvoksi luvun väliltä 0-100 ja y-koordinaatin arvoksi luvun väliltä 50-100:

X- tai y-koordinaatin sijaan voit korvata minkä tahansa parametrin arvon random-metodilla!


Miksi random-metodi voi olla point-metodin parametri?

Random-metodi palauttaa satunnaisen desimaaliluvun, joka puolestaan annetaan parametrina point-metodille (eli random-metodi on tyyppiä float). Metodeja, jotka palauttavat jonkin arvon (eli jotka eivät ole tyyppiä void), voidaan siis käyttää parametreina toisen metodin sisällä, aivan kuten tässä käytimme random-metodia point-metodin parametrina. Perehdymme tyyppeihin lisää myöhemmin.

Alla oleva kuva selventää, mistä osista rect-metodin kutsu koostuu, kun sen sisältä kutsutaan random-metodia.


Harjoitus
Piirrä draw-metodissa pisteitä (point) sattumanvaraisilla koordinaateilla. Pidä kuitenkin huoli, että pisteet osuvat ikkunan alueelle.

Ruudun päivitys

Oletusarvoisesti ruutu päivittyy 60 kertaa sekunnissa. Voit vaikuttaa ruudun päivitysnopeuteen frameRate-metodin avulla. Seuraavassa esimerkki havainnollistaa random-metodin toimintaa hidastamalla ruudun päivitystiheyttä.

Asetetaan aluksi ruudun koko hieman suuremmaksi size-metodilla ja asetetaan valkoinen tausta background-metodilla. Asetetaan sitten frameRate -metodin arvoksi 1, mikä tarkoittaa sitä, että ruutu päivitetään kerran sekunnissa. Tulostetaan lopuksi konsoliin (musta laatikko IDE:n alareunassa) teksti, joka ilmoittaa setup-metodin olevan valmis. Näitä metodeja kutsutaan setup-metodin sisällä, joten ne suoritetaan vain kerran ohjelman alussa.

void setup(){
 size(500, 500);
 background(255);
 frameRate(1);
 println("setup suoritettu!");
}

void draw(){
  ellipse(random(width), random(height), 20, 20);
  println("Ruutu päivitetty " + frameCount + " kertaa");
}
Huom

Ole tarkkana metodien kuten frameRate kirjoitusasun kanssa!

Isot ja pienet kirjaimet täytyy olla juuri oikein, jotta ohjelma toimii.

Draw-metodin sisältö suoritetaan nyt siis 60 kerran sijaan vain kerran sekunnissa. Eli kerran sekunnissa piirretään ympyrä satunnaiseen kohtaan ruutua ja tulostetaan konsoliin teksti, montako kertaa draw-metodin sisältö on suoritettu ohjelman käynnistämisestä alkaen.

Kopioi ja suorita ylläoleva ohjelma. Kokeile myös muuttaa frameRate-metodin parametria pienemmäksi tai suuremmaksi. Kuinka usein ruutu päivitetään, jos se päivitetään 0.2 kertaa sekunnissa?

Huomaa, että println-metodi on melko hidas eikä välttämättä pysy isommilla arvoilla ihan mukana suoritustahdissa. Tärkeää on hahmottaa random-metodin toiminta ja se, miten draw-metodi suoritetaan yhä uudestaan ja uudestaan kunnes ohjelman suoritus lakkaa.


Muuttujista

Widthheight ja frameCount ovat muuttujia. Muuttujiin tutustutaan tarkemmin seuraavassa kappaleessa. Tällä hetkellä riittää tietää, että:

  • width on ruudun leveys
  • height on ruudun korkeus
  • frameCount on ruutujen päivitysten määrä ohjelman käynnistämisen jälkeen

Tämä helpottaa ohjelmointia, sillä voit esimerkiksi piirtää jotakin kohtaan (width/2, height/2), joka on aina ruudun keskellä riippumatta ruudun koosta. Näin voit myöhemmin muuttaa ruudun kokoa ilman että piirtokoodia täytyy korjata useammasta kohdasta.


Häivytys

Voit tyhjentää ruudun joka ruudun päivityksellä kutsumalla background-metodia draw-metodin sisällä:

void setup(){
  size(500, 500);
  background(255);
  frameRate(1);
}

void draw(){
  background(255);
  ellipse(random(width), random(height), 20, 20);
}

Background-metodi täyttää ruudun annetulla värillä ja kaikki aiemmin ruudulle piirretty peittyy. Esimerkistä voit huomata, että vain uusin, viimeisimmässä draw-metodissa suoritettu ympyrä jää näkyviin. Kaikki muut peittyvät valkoisen taustan alle.

Entä jos haluatkin häivyttää piirrettyjä ympyröitä vain hiukan täyden peittämisen sijaan? Luonnollinen idea voisi olla läpinäkyvän värin käyttäminen background-metodin värinä: background(0, 15); Ikävä kyllä tämä ei toimi: background-metodi ei voi käyttää täyttövärinään läpinäkyvää väriä. Tämä liittyy Processinging tapaan piirtää asioita näytölle. Ratkaisuna voit kuitenkin piirtää draw-metodin alussa koko ruudun kokoisen nelikulmion, jonka täyttöväri on läpinäkyvä:

void setup(){
  size(500, 500);
  background(255);
  frameRate(1);
}

void draw(){
  fill(255, 50);
  rect(0, 0, width, height);
  ellipse(random(width), random(height), 20, 20);
}

Ohjelma piirtää jokaisen draw()-metodin suorituksen alussa koko ruudun peittävän nelikulmion, joka läpinäkyvyytensä ansiosta peittää osin alleen kaiken aiemmin piirretyn. Lopputuloksena on vaikutelma ruudun asteittaisesta häivytyksestä:


Koodin siisteydestä

Kun kutsut metodeja setup- ja draw-metodien sisällä, muuttuu ohjelman rakenne heti ratkaisevasti monimutkaisemmaksi. Siksi on tärkeää pitää koodi luettavana ja selkeänä. Erityisen tärkeää on sisentäminen, joka auttaa hahmottamaan, missä suhteessa metodit ovat toisiinsa nähden. Voit sisentää välilyönneillä tai tabeilla, kunhan kaikki on sisennetty samalla tavalla. Mikäli huomaat koodisi sisennysten menneen pahasti sijoiltaan, voit myös käyttää IDE:n auto format -työkalua painamalla ctrl + t.

Koodin pitäminen siistinä helpottaa ohjelmointia huomattavasti. Kumpaa allaolevista koodinpätkistä on mielestäsi mukavampaa lukea?

  void setup() {
size(500,500);
    background (255);
    frameRate(1);
println("setup suoritettu!");
}

void draw() {
fill(255, 255,  255, 50);
 rect(0,0,width,height);
    ellipse(random(width),random(height),20,  20);
println("Ruutu päivitetty "+frameCount+" kertaa");
}
void setup() {
  size(500, 500);
  background(255);
  frameRate(1);
  println("setup suoritettu!");
}

void draw() {
  fill(255, 255,  255, 50);
  rect(0, 0, width, height);
  ellipse(random(width), random(height), 20, 20);
  println("Ruutu päivitetty " + frameCount + " kertaa");
}