Interactie
Deze site is grotendeels een vertaling van een tutorial van Allison Parrish en is vertaald en bewerkt door Marijn van der Meer voor het gebruik bij Informatica lessen op het IJburg College
In dit hoofdstuk ga je leren hoe je in p5.js sketches kan maken die reageren op input van de gebruiker.
Ingebouwde p5.js variabelen
Je hebt gezien hoe je variabelen in je sketch moet gebruiken om ze flexibeler te maken: je kan de waarde van de variabele steeds opnieuw gebruiken. p5.js heeft een aantal ingebouwde variabelen die je zo in je sketch kan gebruiken zonder ze te moeten aanmaken. Deze variabelen geven informatie over dingen die normaal buiten je sketch zouden liggen.
Je hebt al een handige ingebouwde variabele geleerd,frameCount
, in een vorig hoofdstuk.
Breedte en hoogte
De width
en height
variabelen bevatten altijd de waarde die gelijk zijn aan de breedte en hoogte van je sketch (in pixels). Dit is eigenlijk altijd gelijk aan de waarde die je aan de parameters van de createCanvas()
functie geeft.
De width
en height
variabelen zijn handig omdat ze je in staat stellen om sketches te maken die rekening houden met de grootte van het canvas. Hier zijn bijvoorbeeld twee versies van dezelfde sketch, beiden hebben alleen een andere grootte, maar beiden laten de cirkel op exact een derde van het canvas zien:
Deze verhouding blijft zelfs bestaan als we het canvas rechthoekig maken in plaats van vierkant:
Muispositie
p5.js heeft twee heel speciale variabelen, mouseX
en mouseY
, die
de X en Y coordinaten van de muis cursor bevatten van het huidige frame. Als je bedenkt dat de code in draw()
continue draait en heel snel: tot zestig keer per seconde. Een stukje code van p5.js dat deel uitmaakt van de library roept continue deze functie aan en iedere keer dat p5.js dat doet wordt de waarde van de mouseX
en de mouseY
variabelen geupdated met de huidige positie van de cursor op het scherm. De twee variabelen samen maken het heel makkelijk om je sketch te laten reageren met input van de gebruiker in de vorm van muisbewegingen.
Hier is een kort en simpel voorbeeld dat een cirkel tekent op de postitie van de muisaanwijzer:
Natuurlijk kan je de mouseX
en mouseY
niet alleen gebruiken voor de positie van de vormen die je tekent, maar ook voor andere elementen. Hier is een sketch die de
mouseX
waarde gebruikt om de breedte van de lijn en de mouseY
waarde om de grootte van de ellips te bepalen:
Een klassieke voorbeeld sketch van p5.js is om de background()
functie in
draw()
weg te laten, terwijl je de muispositie variabelen gebruikt. Nu heb je eigenlijk de basis van een tekenprogramma:
We kunnen een wat onvoorspelbaarder tekenprogramma maken door wat veranderingen in tijd in te voeren en wat andere kleine aanpassingen:
Gedrag sturen met if
Wanneer je te maken hebt met input van een gebruiker zou je vaak willen dat je sketch verschillende soorten reacties geeft. Onder de ene omstandigheid zou je willen dat je sketch op de ene manier reageert; en onder een tweede omstandigheid wil je dat je sketch anders reageert op de gebruiker.
Stel je bijvoorbeeld eens voor dat je een sketch wil maken waarbij er alleen een rechthoek verschijnt wanneer de muiscursor zich op de onderste helft van de sketch bevindt. Dus als de muispositie groter is dan de helft van de hoogte dan moet de rechthoek te zien zijn (en anders niets).
Om deze taak te volbrengen moeten we de sketch sturen. We moeten een mogelijkheid hebben om te vragen "controleer of iets zo is; als dat zo is doe dan dit." Javascript (en iedere andere programmeertaal) heeft speciale syntax voor juist dit doel: het if
statement.
Hier is de sketch die precies de bovenstaande situatie uitvoert.
Het nieuwe gedeelte van deze code zijn deze drie regels:
if (mouseY > height/2) {
rect(100, 100, 200, 200);
}
Dit is een voorbeeld van een if
statement. Schematisch gezien ziet een if
statement er zo uit:
if (expr) {
code-die-uitgevoerd-moet-worden
}
… waarbij expr
een relationale expressie (uitleg volgt hieronder) is en
code-die-uitgevoerd-moet-worden
een of meer Javascript statements zijn (zoals functie aanroepen, for
loops, of zelfs andere if
statements). Als de relationale expressie waar
is, dan wordt de code-die-uitgevoerd-moet-worden
uitgevoerd. Anders worden de statements niet uitgevoerd en wordt de betreffende code overgeslagen.
Relationele expressies
Relationale expressies lijken op die andere expressies waar we al naar hebben gekeken maar zij hebben de volgende structuur:
expr operator expr
Dus een operator met aan beide kanten een expressie. Het verschil tussen relationele operatoren en andere operator is dat de relationele operatoren niet een ander getal als antwoord krijgen maar een van de twee bijzondere waarden: true (waar)
of false (onwaar)
. Relationele expressies worden gebruikt om vast te stellen hoe twee waarden relateren met elkaar. Meer specifiek: of een waarde groter is dan de andere of dat beide waarden gelijk zijn.
De meest gebruikte relationele operatoren zijn:
operator | betekenis |
---|---|
> | groter dan |
< | kleiner dan |
== | gelijk aan |
>= | groter of gelijk aan |
<= | kleiner dan of gelijk aan |
!= | niet gelijk aan |
Probeer de volgende statement eens uit in de p5.js webeditor zie wat de antwoorden zijn in het consolevenster:
console.log(15 > 10);
console.log((3 * 30) < (2 * 40));
console.log((3 + 5) * 2 == (10 + 6));
Je zou dit moeten zien in het consolevenster:
true
false
true
Meerdere ifs
Je kan meerdere if
statements in de draw()
sectie van je code plaatsen. (In
feite, kan je if
statements overal plaatsen waar je zou willen, zelfs in for
loops of andere if
statements!). Hier een voorbeeldsketch dat een rechthoek tekent als de muis in de de onderste helft is en een cirkel als de muis op de rechterhelft van de sketch is:
Je kan ook een if
statement in een andere if
plaatsen. Hier dezelfde sketch, maar nu wordt de cirkel alleen getoond wanneer de muis aan de rechterkant en op de onderste helft van het scherm is:
Muiskliks
p5.js heeft een speciale ingebouwde variabele genaamd mouseIsPressed
waar de waarde true
is als de gebruiker de muisknop ingedrukt houdt en false
als dat niet zo is. Je kan dit gebruiken om je sketch verschillende dingen te laten doen afhankelijk van of de gebruiker de muisknop ingedrukt houdt of niet.
Hier een voorbeeld waarbij alleen een cirkel te zien als de muisknop ingedrukt wordt:
Anders…
Stel dat je de volgende opdracht krijgt: maakt een sketch waarbij een cirkel wordt getoond aan de bovenkant van de sketch als de muis bovenin de sketch is en een cirkel onderin de sketch in de andere gevallen.
Je eerste poging zal er waarschijnlijk zoiets uit zien:
Maar dat is niet helemaal goed! De onderste cirkel wordt nu altijd getoond en niet alleen wanneer de relationele conditie in de if
statement daarboven false
is. Dit voorbeeld laat zien dat iedere code die na een if
statement’s sluitingsaccolade wordt uitgevoerd, ongeacht of de if
statement slaagt.
Je zou dit kunnen oplossen door twee verschillende if
statements te gebruiken, een om te checken of de muispositie in de bovenste helft is en een andere om te checken of de muispositie op de onderste helft is:
OEFENING: Waarom gebruikt de tweede
if
statement>=
als operator, in plaats van de>
?
Dit werkt, maar het kan veel makkelijker. Het blijkt dat heel gebruikelijk is bij het programmeren dat je een bepaald gedrag wilt bij een bepaalde conditie en een ander gedrag wanneer niet aan deze conditie voldaan wordt. Om je tijd te besparen in het typen van een tweede if
statement dat eigenlijk het omgekeerde is van het eerste statement heeft Javascript een else
statement die je na iedere if
statement kan plaatsen.
Het ziet er zo uit:
if (expr) {
wat-code
}
else {
wat-andere-code
}
… waarbij expr
een expressie dat als antwoord true
of false
heeft (net als een relationele expressie of een variabele als mouseIsPressed
). Als deze expressie als antwoord true
heeft zal de code uit wat-code
uitgevoerd worden.
Anders zal wat-andere-code
uitgevoerd worden.
Dus we kunnen het bovenstaande voorbeeld wat herschrijven in nog kortere code:
En hier een voorbeeld dat een rechthoek tekent als de muis wordt ingedrukt en anders een lijn:
Een vreemde eend
Het komt voor dat je in een for
loop bij een keer tijdens die loop eigenlijk net iets anders wil laten gebeuren. Een if
statement is het perfecte gereedschap in dit geval! Je kan een if
statement in een for
loop stoppen om te zien of de loop variabele (meestal de i) een bepaalde waarde heeft en juist op dat moment iets anders laten gebeuren, zoals hier:
Meer dan twee: else if
We leven niet in een het-een-of-het-ander wereld en is een het hebben van alleen een if
en een else
niet genoeg. Neem bijvoorbeeld eens het if
/else
voorbeeld van eerder, waar een cirkel bovenaan het scherm wordt getoond als de muis over de bovenste helft gaat en een cirkel aan de onderkant als de muis over de onderste helft gaat. Als je bijvoorbeeld een zelfde soort sketch wil maar dan met drie cirkels met een scherm dat in drie delen wordt gedeeld: als de muis op de bovenste derde deel gaat moet daar een cirkel verschijnen; over het midden dan een cirkel daar en op het onderste deel een cirkel daar.
In dit voorbeeld hebben we drie absoluut andere condities die we moeten testen. En de logica van de code zit er ongeveer zo uit:
- Is de muisaanwijzer boven het bovenste derde deel van het scherm?
- Als dat zo is: teken daar een cirkel.
- Als dat niet zo is, vraag: Is de muisaanwijzer boven het middelste derde deel van het scherm?
- Als dat zo is: teken daar een cirkel.
- Als dat niet zo is: moet de muisaanwijzer over het onderste derde deel gaan, dus teken de cirkel daar.
Het makkelijkst om deze logica te beschrijven in Javascript is om de else if
clausule te gebruiken. Qua syntax ziet deze structuur er zo uit:
if (test) {
statements
}
else if (test) {
statements
}
else {
statements
}
Hier een code die de boven beschreven situatie uitvoerd met het gebruik van een else if
:
Iedere if
statement kan een ongelimiteerde hoeveelheid else if
clausules bevatten. Een else
clausule is zelfs helemaal niet altijd nodig bij een else if
.
Relationele expressies combineren met && en ||
Ik heb hierboven al uitgelegd dat relationele expressies met <
en >
altijd bijzondere waarden als uitkomst hebben, namelijk booleans. Een booleaanse waarde is true
(waar) of false
(onwaar).
Er zijn nog twee speciale operatoren die gebruikt worden met booleaanse waarden: &&
en ||
. De &&
heet de “logische EN” en de ||
is de “logische OF.”
Wanneer expressies met deze operatoren worden geevalueerd (het antwoord van deze vergelijking) is de waarde van het resultaat zelf ook een boolean. Je kan met deze operatoren relationele expressies combineren om nog diepere relationele expressies te formeren.
De &&
en ||
operatoren werken net als iedere andere Javascript operator die je tot nu toe hebt gezien: ze verwachten een expressie links en een expressie rechts van de operator om te vergelijken. De uitkomst van de &&
operator is alleen true (waar) las zowel de expressie aan de linkerkant als aan de rechterkant true zijn, en de uitkomst is anders false (onwaar). De ||
operator daarintegen evalueert alleen tot true als een van beide expressies aan de linker- of rechterkant waar is, en alleen tot false als beide expressies niet waar zijn.
Je kan deze operatoren, net als de eerder getestte operatoren, in de console.log()
testen in de webeditor. Dus, bijvoorbeeld:
console.log((6 > 5) && (7 > 6))
… zal true
laten zien in het consolevenster, en
console.log((6 > 5) && (10 < 9))
… zal tot false
leiden. En als we de ||
operator gebruiken:
console.log((6 > 5) || (10 < 9))
… laat true
zien (omdat alleen een van de expressies waar hoeft te zijn voor de <||
operator om te slagen), en leidt
console.log((4 > 5) || (10 < 9))
… tot false
(omdat beide expressies links en rechts van de ||
false
) zijn.
Hier is een voorbeeld dat de &&
operator gebruikt om te zien of de muispositie in een bepaald gebied is. Net als het voorbeeld in het vorige stuk, alleen wordt nu een cirkel in het midden getoond als de muispositie groter is dan een derde van boven en lager is dan een derde van onderen. Anders wordt er boven en onder een cirkel getekend.
Hier wordt een cirkel getekend als of de muisknop wordt ingedrukt of de muiscursor zich bevind op de onderste helft van het scherm:
OEFENING: Maak een sketch dat een rechthoek tekent, die blauw is wanneer de muiscursor over de rechthoek gaat, en anders rood.
Samenwerken: alles binnenboord houden
Men gebruikt if
statements in combinatie met relationele expressies om dingen binnenboord te houden. Als je een waarde hebt die met de tijd verandert wil je kunnen checken of die waarde een bepaalde grens is overschreden en als dat zo is moet er iets met die waarde gebeuren om deze te resetten of om van richting te laten veranderen.
Het klassieke voorbeeld is de stuiterende bal: teken een ellips die van links naar rechts beweegt. En wanneer het de rand van de sketch raakt moet de ellips van rechts naar links bewegen tot het weer de rand raakt, enzovoort:
Je kan dit bereiken door de xspeed
variabele te vermenigvuldigen met -1
,
dus eigenlijk de richting omkeren, wanneer de X-positie “buitenboord raakt":
OEFENING: Pas de bovenstaande sketch zo aan dat het de snelheid van de ellips in zowel de X- als de Y-dimensie bijhoudt. Voeg een tweede
if
statement toe dat de ellips binnenboord houdt ook in de Y-richting (net zoals dat gebeurt met de bestaandeif
statement voor de X-as).