qr code

Villkor och händelser med Processing

Villkor och händelser med Processing

Det finns kontrollstrukturer som återfinns i alla strukturerade programmeringspråk. Man brukar tala om de tre grundläggande kontrollstrukturerna:

  • Sekvens, programmet utför en följd av satser som exekveras i tur och ordning efter varandra.
  • Selektion, programmet kan välja att utföra olika block av satser beroende på villkor.
  • Iteration, programmet kan upprepa block av kod ett antal gånger.

Vi ska gå igenom selektion. En selektion kan också kallas för en villkorssats.

Vi ska också gå igenom olika sätt att hantera händelser. För händelsestyrda program, vilket de flesta moderna program är, är händelsestyrning ett grundläggande begrepp.

Villkorssatser

En villkorssats används om programmet ska utföra olika saker beroende på om något villkor är sant eller falskt. Det är också mycket vanligt att man kallar villkorssatser för if-satser eller if-else-satser.

Villkorssatser i Processing har samma struktur som om-block och om-annars-block i Scratch.

jämförelse 2
Villkorssatser i Scratch och i Processing.

För att koden ska vara lättare att läsa, indenteras den kod som ligger inuti villkorssatsen.

Måsvingarna används för att stänga in flera enkla satser. Om en villkorssats bara använder sig av en enda sats, går det bra att inte använda måsvingar. Med följande kod ska bara en sats utföras om poängen är noll:

if (poäng == 0) 
		text("Bu!", 100, 100);

Om du i efterhand kommer på att flera satser ska utföras om något villkor är sant, måste du i efterhand lägga till måsvingar. För nybörjare kan det vara bra att alltid använda måsvingar till villkorssatser, även om det bara är en enkel sats som ska utföras. Med måsvingar blir det inga nybörjarfel om villkorssatsen måste ändras.

Skriv måsvingar

Om du använder Windows eller Linux, ser du vilka knappar på tangentbordet som ger måsvingar. Måsvingarna finns i det nedre högra hörnet på tangenterna 7 och 0. För att skriva en måsvinge klickar du på Alt Gr samtidigt som du klickar på 7 eller 0. Andra specialtecken fungerar på liknande sätt.

Om du använder Mac får du ingen hjälp av tangentbordet. För att skriva specialtecken med en Mac, se sidan Backslash och andra specialtecken på en Mac.

Booleska variabler

En variabel som bara kan anta värdet sann eller falsk kallas för en boolesk variabel. I Processing används värdena true och false för booleska variabler. Booleska variabler kan användas som villkor i villkorssatser

Det finns två fördefinierade booleska variabler mouseIsPressed och keyIsPressed som håller reda på om musknappen är nedtryckt respektive om någon tangent är nedtryckt.

Exempel 1

Gör ett enkelt ritprogram med följande kod:

function setup() {
	createCanvas(windowWidth, windowHeight);
	background(100);
}

function draw() {
	if (mouseIsPressed) {
		ellipse(mouseX, mouseY, 20);
	}
}

Lägg till kommandot

print(mouseIsPressed);

i draw-funktionens if-sats. Testkör programmet för att se vilka värden som skrivs ut i konsolen.

Jämförelseoperatorer

Eftersom likhetstecknet används för att tilldela variabler värden, används dubbla likhetstecken för logisk likhet. Det finns flera jämförelseoperatorer i OpenProcessing.

Jämförelseoperatorer i Processing.
operator jämförelse
== lika med
!= skilt från
< mindre än
> större än
<= mindre än eller lika med
>= större än eller lika med

En jämförelse är antingen sann eller falsk och fungerar därför som villkor till en villkorssats.

Logiska operatorer

Det finns tre logiska operatorer i Processing: och, eller, inte.

Logiska operatorer i Processing.
operator logisk operation
&& och
|| eller
! inte
Exempel 2

Gör en studsande boll genom att lägga in följande kod:

let x, y, ySteg;

function setup() {
	createCanvas(windowWidth, windowHeight);
	x = width/2;
	y = height/2;
	ySteg =  5;
}

function draw() {
	background(100);
	if (y > height || y < 0) {
		ySteg = -ySteg;
	}
	y = y + ySteg;
	ellipse(x, y, 20);
}

Lägg till en variabel xSteg och se till att bollen studsar också studsar i x-led.

Prioritetsordningen är sådan att först beräknas aritmetiska operationer, sedan jämförelser och sist logiska operationer. På så vis fungerar följande kod:

if (y + 5 > height || y - 5 < 0) {
	//kod
}

Först beräknas y + 5 och y - 5, sedan utförs större än och mindre än, sist utförs logiskt eller.

Flera förgreningar

En villkorssats i sin enklaste form ser till att något utförs om ett villkor är sant.

if (<villkor>) {
	// Kod som utförs om villkor sant.
}

En villkorssats kan också förgrena sig till två alternativ.

if (<villkor>) {
	// Kod som utförs om villkor sant.
} else {
	// Kod som utförs om villkor falskt.
}

Om du vill ha flera förgreningar kan du använda else if konstruktioner.

if (<villkor1>) {
	// Kod som utförs om villkor1 sant.
} else if (<villkor2>) {
	// Kod som utförs om villkor1 falskt och villkor2 sant.
} else if (<villkor3>) {
	// Kod som utförs om villkor1 och villkor2 är falska
	// men villkor3 sant.
} else {
	// Kod som utförs om alla villkor är falska.
}

En villkorssats kan innehålla ett godtyckligt antal else if men högst ett else.

Exempel 3

Testa att rita tre olika färger med följande kod:

function setup() {
	createCanvas(windowWidth, windowHeight);
	background(100);
	noStroke();
}

function draw() {
	if (mouseX < width/3) {
		fill(255, 0, 0);
	} else if (mouseX < 2*width/3) {
		fill(0, 255, 0);
	} else {
		fill(0, 0, 255);
	}
	ellipse(mouseX, mouseY, 20, 20);
}

Kollisionsdetektering

I Scratch finns det flera block som används för att kolla om en sprajt rör en färg, annan sprajt eller kant. I Processing måste programmeraren själv programmera alla kollisioner. För att kontrollera om en position är vid kanten kan man använda att alla x-koordinater i ritområdet är begränsade av 0 och width, y-koordinaterna begränsas av 0 och height.

Kommandot dist(<x1>, <y1>, <x2>, <y2>) beräknar avståndet mellan punkterna (x1, y1) och (x2, y2). Avståndet mellan punkter kan användas för att kolla om muspekaren befinner sig på en cirkel.

Exempel 4

Följande kod upptäcker om muspekaren befinner sig på en cirkel:

let x, y, radie;

function setup() {
	createCanvas(windowWidth, windowHeight);
	x = width/2;
	y = height/2;
	radie =  100;
}

function draw() {
	background(100);
	ellipse(x, y, 2*radie, 2*radie);
	if (dist(mouseX, mouseY, x, y) < radie) {
		text("Innanför", 100, 100);
	} else {
		text("Utanför", 100, 100);
	}
}

Testa koden!

Lägg till kommandot

ellipseMode(RADIUS);

i setup-funktionen och ändra i koden för ellipsen så att programmet fortfarande fungerar.

Att upptäcka kollision mellan muspekare och rektangel är något besvärligare.

Exempel 5

Utgå ifrån följande kod för att upptäcka kollision med rektangel:

let x, y, bredd, höjd;

function setup() {
	createCanvas(windowWidth, windowHeight);
	x = width/2;
	y = height/2;
	bredd =  200;
	höjd = 100;
}

function draw() {
	background(100);
	rect(x, y, bredd, höjd);
	if (mouseX > x && mouseX < width) {
		text("Innanför", 100, 100);
	} else {
		text("Utanför", 100, 100);
	}
}

Lägg till kod i if-satsens villkor så att texten "Innanför" bara visas då muspekaren befinner sig innanför rektangeln.

Händelser

En händelse i Processing är exempelvis när användaren klickar på en tangent eller musen. En del händelsehantering kan hanteras inuti draw-funktionen med hjälp av variablerna mouseIsPressed och keyIsPressed. Det finns också funktioner för händelsehantering som ligger utanför draw-funktionen.

Mushändelser

Det finns fyra funktioner för att hantera mushändelser: mouseMoved(), mouseDragged(), mouseReleased() och mouseClicked()

Exempel 6

Testa följande kod:

function setup() {
	createCanvas(windowWidth, windowHeight);
	background(100);
}

function draw() {
	ellipse(mouseX, mouseY, 20, 20);
}

function mouseReleased() {
	print("Du släppte upp musen.");
}

Lägg på liknande sätt till två funktioner mouseMoved() och mouseDragged() som skriver ut lämpliga meddelanden i konsolen. Testa ditt program för att se vad skillnaden är mellan dessa två händelser.

Tangenthändelser

Alfanumeriska tangenter är sådana tangenter som skriver ut någon symbol om man exempelvis använder en ordbehandlare. Andra tangenter skriver inte ut något utan har speciella funktioner, exempelvis kontrolltangenten, piltangenter, tab, m.fl.

För att upptäcka händelsen att en alfanumerisk tangent trycks ner, kan du använda funktionen keyTyped() som utlöses exakt en gång när en alfanumerisk tangent trycks ner. Den tangent som tryckts ner lagras i variabeln key.

Exempel 7

Testa följande kod:

let meddelande;

function setup() {
	createCanvas(windowWidth, windowHeight);
	meddelande = "";
	textAlign(CENTER);
}

function draw() {
	background(100);
	text("meddelande = " + meddelande, width/2, height/2);
}

function keyTyped() {
	meddelande = meddelande + key;
}

Testkör koden och se vad som händer om du klickar på alfanumeriska tangenter. Vad händer om du klickar på enter, tab, och piltangenter?

För att kontrollera vilken alfanumerisk tangent som tryckts ner kan du jämföra key med valfritt tecken innesluten av citationstecken eller apostrof.

För att upptäcka alla sorters tangenttryckningar kan funktionen keyPressed() användas, vilken utlöses precis en gång när någon tangent trycks ner.

För icke-alfanumeriska tangenter används variabeln keyCode. För att ta reda på vilken icke-alfanumerisk tangent som tryckts ner, kan du jämföra keyCode med något av följande:

BACKSPACE, DELETE, ENTER, RETURN, TAB, ESCAPE, SHIFT, CONTROL, OPTION, ALT, UP_ARROW, DOWN_ARROW, LEFT_ARROW, RIGHT_ARROW

Exempel 8

Testa följande kod:

function setup() {
	createCanvas(windowWidth, windowHeight);
}

function keyTyped() {
	if (key == "a") {
		print("Du skrev a");
	}
}

function keyPressed() {
	if (keyCode == ENTER) {
		print("Du klickade på enter.");
	}
}

Testkör koden och se vad som händer om du klickar på lilla a respektive stora A.

Om du vill upptäcka att en bokstav tryckts ner men inte bryr dig om huruvida det är en stor eller liten bokstav, kan du jämföra key med en stor bokstav i funktionen keyPressed(). Lägg till följande kod i keyPressed():

if (key == "B") {
	print("Du skrev b");
}

Testa sedan att klicka på b och på B.

Om du vill kunna styra ett objekt genom att hålla två tangenter nere samtidigt, kan du använda funktionen keyIsDown(<tangentkod>)> inuti draw-funktionen.

Exempel 9

Testa följande kod:

let x, y;

function setup() {
	createCanvas(windowWidth, windowHeight);
	background(100);
	x = width/2;
	y = height/2;
}

function draw() {
	ellipse(x, y, 20, 20);
	if (keyIsDown(LEFT_ARROW)) {
		x = x - 5;
	}
	if (keyIsDown(RIGHT_ARROW)) {
		x = x + 5;
	}
	if (keyIsDown(UP_ARROW)) {
		y = y - 5;
	}
	if (keyIsDown(DOWN_ARROW)) {
		y = y + 5;
	}
}

Testkör koden och prova att styra med två tangenter samtidigt.

Tid

Den fördefinierade variabeln frameCount håller reda på hur många gånger draw-funktionen genomlöpts. Det går att stänga av draw-metoden när den genomlöpts ett visst antal gånger med kommandot noLoop(). Koden

if (frameCount == 60) {
	noLoop();
}

stänger av draw-funktionen efter 60 tickningar.

Funktionen draw genomlöps ungefär 60 gånger per sekund, andelen frames per second (fps) är 60. Du kan göra så att draw-funktionen tickar långsammare genom att använda funktionen frameRate(<fps>). Exakt hur ofta draw-funktionen tickar beror på hur snabb datorn är.

Om du vill mäta tid exakt, kan du använda funktionen millis() vilken mäter hur många millisekunder det gått sedan programmet startade.

Exempel 10

Följande kod visar hur en enkel timer kan göras:

let start, stopp;

function setup() {
	createCanvas(windowWidth, windowHeight);
	start = -1;
	stop = -1;
	textSize(32);
}

function draw() {
	background(100);
	if (start == -1) {
		text("Klicka på mellanslag två gånger!", 100, 100);
	} 
	if (stop != -1) {
		text("Det tog "+stop +" millisekunder.", 100, 200);
	}
}

function keyTyped() {
	if (key == " ") {
		if (start == -1) {
			start = millis();
		} else {
			stop = millis()-start;
			start = -1;
		}
	}
}

Testkör koden. Om du inte vill visa en massa decimaler kan du avrunda med hjälp av funktionen round(<tal>)

Funktionen millis() mäter tid med hjälp av datorns klocka. Det finns flera funktioner som med hjälp av datorns klocka kan ta reda på vilket år det är eller vilken månad, dag, timme, minut, sekund det är. Funktionerna är:

year(), month(), day(), hour(), minute(), second()

Programmeringsuppgifter

Uppgift 1

Rita ellipser eller rektanglar

Gör ett program som ritar en rektangel om man trycker ner någon tangent och annars ritar en ellips. Använd en if-else-sats och den fördefinierade booleska variabeln keyIsPressed.

Dra med musen och håll tangent nedtryckt!"

Uppgift 2

Färglägg Tysklands flagga

Tysklands flagga har dimensionerna 3:5, dvs om höjden är 3 längdenheter så är bredden 5 längdenheter. Flaggan är indelat i tre lika stora horisontella band. Det översta bandet är svart. Det mellersta bandet är rött med RGB-färgen (221,0,0). Det nedersta bandet är gult med RGB-färgen (255,206,0).

Se till att ritområdet har rätt dimensioner. Lägg in kod som ritar en ellips i rätt färg beroende på let muspekaren befinner sig så att flaggan ritas ut när man drar med musen över ritområdet. Använd en villkorssats med en else if konstruktion.

Dra med musen!

Uppgift 3

Färglägg Sveriges flagga

Sveriges flagga har dimensionerna 10:16, dvs om höjden är 10 längdenheter så är bredden 16 längdenheter.

Den blå färgen är RGB-färgen (0, 106, 167) och den gula RGB-färgen (254, 204, 0).

De horisontella fälten är i förhållandet 5:2:9, dvs 5 längdenheter blått, 2 längdenheter gult, 9 längdenheter blått (från vänster till höger).

De vertikala fälten är i förhållandet 4:2:4, dvs 4 längdenheter blått, 2 längdenheter gult, 4 längdenheter blått.

Se till att ge ritområdet har rätt dimensioner. Börja sedan med att lägga in kod som ritar de horisontella fälten med korrekta färger. Använd samma struktur som i koden nedan fast fyll i kod för villkoret och för färgsättningen. För att skriva det villkor för muspekarens x-koordinat som ger gul färg kan du använda lämpliga jämförelser och en och-operator (och-operatorn skrivs &&). Testkör din kod!

if (<villkor för x-koordinat som ger gult>) {
	// gul färg
} else {
	// blå färg
}

Det mellersta horisontella fältet ska alltid vara gult oavsett vilken y-koordinat musen har. De blå horisontella fälten ska däremot antingen vara gula eller blå beroende på y-koordinaten. Lägg nu in en if-sats inuti din ursprungliga if-sats. En if-sats inuti en if-sats kallas för en nästlad if-sats. Det går att använda samma princip med en logisk och-operator för y-koordinaten (vilken ger gul färg) men prova istället att använda en logisk eller-operator (eller skrivs ||) vilken ger villkoret för blå färg.

if (<villkor för x-koordinat som ger gult>) {
	// gul färg
} else {
	if (<villkor för y-koordinat som ger blått>) {
		// blå färg
	} else {
		// gul färg
	}
}

Testkör ditt program och se till att flaggan ritas ut med korrekt färgsättning.

Dra med musen!

Uppgift 4

Enkelt ritprogram

Utgå ifrån Exempel 1 och lägg till funktionalitet så att användaren kan välja färg och ändra på cirkelns storlek.

Gör en variabel som används för cirkelns storlek och se till att denna kan ändras av användaren genom att exempelvis klicka på pil upp eller ned.

Låt användaren välja mellan några färger exempelvis genom att klicka på 'r' för röd osv.

Du kan exempelvis utgå ifrån denna struktur som placeras längst ned i programmet.

function keyTyped() {
	if (key == "r") {
		// kod för färgen röd.
	}
}

function keyPressed() {
	if (keyCode == UP_ARROW) {
		// kod för större storlek
	}
}

Uppgift 5

Studsande boll

Utgå ifrån Exempel 2. Gör en variabel för cirkelns radie så att denna lätt kan ändras. Ändra i olikheterna som får bollen att studsa så att bollen studsar när bollens kant rör ritområdets kant. Testkör ditt program med en stor radie så att det tydligt syns att studsarna är korrekta.

Uppgift 6

Studsande sprajt

Utgå från kod för en studsande boll men ändra på koden så att en bild används istället för en uppritad cirkel.

En bild är rektangelformad. Hur ska jämförelserna göras så att bilden studsar när bildens kant rör ritområdets kant?

Uppgift 7

En klocka

Använd de inbyggda funktionerna för tidmätning till att visa dagens datum och en klocka. Du konkatenerar text du själv skriver med funktionsvärden genom att använda tecknet +, exempelvis som i koden:

text("Det är just nu år " + year() + ".", width*0.5, height*0.25);

Se till att texten är horisontellt centrerad genom att skriva

textAlign(CENTER);

i setup-funktionen.

Koden för att visa texterna ska ligga i draw-funktionen så att de hela tiden uppdateras.

Uppgift 8

Pricka studsande boll

Utgå ifrån kod för en studsande boll. Gör om denna kod till ett spel som ger spelaren poäng varje gång spelaren klickar på bollen. Spelet ska fungera så här:

  • I början av spelet ska det visas en textinstruktion, exempelvis "Klicka på bollen". Denna text ska bara visas en kort tid. Använd variabeln frameCount och en villkorssats för att visa instruktionen. Bestäm själv hur länge instruktionen ska visas. Denna kod ska ligga i draw-funktionen.
  • Dela ut poäng varje gång spelaren klickar på bollen med muspekaren. Gör en variabel för poängen. Se till att poängen är noll när programmet startar. Använd mushändelsen mouseClicked genom att nederst i programmet lägga till följande kod:
    function mouseClicked() {
    	// kod som utförs vid musklickning
    }
    Gör en villkorssats inuti mouseClicked som kontrollerar om muspekaren befinner sig på bollen och öka i sådana fall poängen. Kod för att upptäcka kollisionsdetektering visas i Exempel15.
  • Efter en viss tid ska spelet avslutas. Använd återigen en villkorssats och frameCount. Bestäm själv efter hur lång tid spelet ska avslutas. När detta händer ska något sorts resultat visas, exempelvis "Du fick 3 poäng". Du stänger av draw-funktionen med kommandot noLoop();. Välj själv om poängen ska visas under spelets gång eller bara på slutet.
Klicka på knappen för att starta spelet.

Uppgift 9

På tio sekunder

För att mäta tid kan du använda funktionen millis() vilken mäter hur många millisekunder det gått sedan programmet startade.

Gör ett program som låter användaren klicka på en cirkel. Vid varje träff ska cirkeln få en ny slumpmässig position och användaren ska få en poäng. Användaren har tio sekunder på sig att samla poäng. Använd variabler för cirkelns position och radie. Du behöver även en variabel för att räkna poäng. Använd funktionen millis() för att mäta hur många millisekunder det gått sedan programmet startat.

I och med att cirkeln byter position varje gång användaren klickar på den, går det bra att räkna poäng i draw-funktionen genom att använda variabeln mouseIsPressed. Utgå exempelvis från följande kod:

let x, y, r, poäng;

function setup() {
	createCanvas(windowWidth, windowHeight);
	x = random(width);
	y = random(height);
	r = 50;
	poäng = 0;
	textAlign(CENTER);
}

function draw() {
	background(100);
	ellipse(x, y, 2 * r);
	text("Poäng = " + poäng, width * 0.2, height * 0.2);
	if (mouseIsPressed) {
		// Kod för träff.
		// Vid träff ska användaren få poäng och cirkeln en ny position.
	}
	// Kod för att kontrollera om det gått tio sekunder.
	// Efter tio sekunder ska resultat visas och draw-funktionen stängas av.
}
Klicka på knappen för att börja mäta.

Uppgift 10

Modellera gravitation

Låt en boll falla till marken. Använd två variabler för bollens position och en variabel för bollens hastighet i y-led. Se till att bollen startar någonstans i den övre delen av ritområdet och att hastigheten i y-led är noll från början.

Så länge bollen befinner sig ovanför den nedre kanten ska den accelereras neråt, annars ska y-koordinaten sättas så att bollen placeras precis vid nedre kanten och hastigheten i y-led sättas till noll. Använd en if-else-sats med en lämplig olikhet för att avgöra när bollen är vid den nedre kanten eller inte.

Se till att bollen börjar om med hastigheten noll vid muspekarens koordinater när användaren klickar med musen i ritområdet.

Klicka i ritområdet för att släppa bollen.

Uppgift 11

Dämpad studsning

Utgå ifrån kod som låter en boll falla vid marken. Ändra i koden så att hastigheten inte sätts till noll när bollen rör vid marken utan byter tecken så att bollen rör sig uppåt. För att programmet ska fungera måste du efter att du ändrat tecken på hastigheten se till att y-koordinaten ändras så att den får en första knuff upp ifrån nedre kanten, annars kommer den att fastna vid den nedre kanten.

För att se till att studsen dämpas kan du istället för att byta tecken multiplicera hastigheten i y-led med -0.9 eller liknande negativt tal. Testa olika dämpningsfaktorer.

Klicka i ritområdet för att släppa bollen.

Observera att med denna kod kommer bollen troligen inte att sluta studsa.

Uppgift 12

Modellera hopp

Utgå från kod för en boll som faller till marken. Byt kod för musclickning så att användaren kan hoppa genom att klicka i ritområdet. Vid ett hopp ska bollen få en hastighet i riktning uppåt, sedan ska positionen ändras direkt så att bollen kommer ovanför nedre kanten.

Lägg till en variabel för hastigheten i x-led och se till att denna har värdet noll från början. Lägg till en funktion keyPressed längst ner i programmet och lägg in kod som ger bollen en hastighet åt höger eller vänster när användaren klickar på höger respektive vänster piltangent. Se slutligen till att bollen studsar i sidorna genom att lägga till lämplig kod i draw-funktionen.

Hoppa genom att klicka i ritområdet. Gå åt vänster/höger med piltangenterna.