T8 Verwerkingsopdrachten 2324
Inleiding
Om te leren hoe je objectgeoriënteerd programmeert, gaan we stap voor stap een objecgeoriënteerd programma maken. We maken hiervoor een epidemiesimulator die visueel maakt hoe organismen elkaar kunnen besmetten met een ziekteverwekker. Tussen de opdrachten door vind je theorie over objectgeoriënteerd programmeren.
Opdracht 0 - Klaar voor de start
Start een eigen repo en begrijp de code:
- Ga naar GitHub classroom en schrijf je in voor de opdracht ‘Epidemiesimulator’
- Bekijk in je browser wat de simulator nu al doet. De simulator doet nog niet veel: het laat een vierkantje bewegen en stuiteren tegen de randen van het scherm.
- Bekijk de code van de simulator. In de code zie je globale variabelen die de positie en de horizontale en verticale snelheid bevatten. Ook zie je de constante
BREEDTE
, die de waarde van de grootte van het vierkantje bevat.
var x;
var y;
var speedX;
var speedY;
const BREEDTE = 20;
In setup
krijgen deze variabelen hun initiële waarde. De positie is in het midden van het canvas. (Het midden van het vierkant is overigens niet exact in het midden. De waarden x
en y
worden gebruikt voor de linkerbovenhoek…) De horizontale en verticale snelheid krijgen bij de start een random waarde tussen -5 en 5.
x = width / 2;
y = heigth / 2;
speedX = random(-5, 5);
speedY = random(-5, 5);
In draw
wordt netjes een wit vierkantje getekend met behulp van de waarden van x
, y
en BREEDTE
. Herinner je je nog dat de functie
rect
een vierkant tekent met de linkerbovenhoek op de meegeven positie?
rect(x, y, BREEDTE, BREEDTE);
Lees nu hoofdstuk 1 van de theorie
Opdracht 1 – 25 random ‘mensen’ maken. En wat doen die katten daar? 😼
In de theorie van hoofdstuk 1 is een heel groot deel van de klasse Mens
gegeven. Je maakt deze klasse verder af en gebruikt deze om 25 mensobjecten te maken die zich in onze simulatie bewegen:
Programmeren
a) 25 random mensen
We gaan nu de array mensen
vullen met 25 random mens-objecten. Verwijder de code die je bij opdracht 2 in setup
hebt gezet om handmatig 5 mens-objecten te maken. Schrijf in plaats daarvan deze code:
// maak 25 random mensen
for (var teller = 0; teller < 25; teller++) {
// we moeten ze niet te dicht bij de rand tekenen
// om geen problemen met stuiteren te krijgen
var ruimteTotRand = 50;
// creëer random positie en snelheid
var randomX = random(ruimteTotRand, width - ruimteTotRand);
var randomY = random(ruimteTotRand, height - ruimteTotRand);
var randomSpeedX = random(-5, 5);
var randomSpeedY = random(-5, 5);
// maak nieuw mensobject
var nieuwMens = new Mens(randomX, randomY, randomSpeedX, randomSpeedY);
// voeg mensobject toe aan array
mensen.push(nieuwMens);
}
Deze code maakt 25 keer een nieuw mens-object met
random
waarden aan en voegt deze toe aan de array mensen
. Zorg ervoor dat je deze regels begrijpt. Uitleg over push vind je onder andere op de shite van
w3schools
Bekijk het resultaat. Als het goed is, heb je nu 25 vierkantjes die door elkaar heen vliegen en tegen de randen stuiteren.
b) besmettingen
Het wordt tijd dat deze mensen elkaar kunnen besmetten. Het idee is dat mensen elkaar besmetten als ze elkaar in hun beweging overlappen.
Geef de klasse
Mens
een nieuw attribuutisBesmet
. Dit attribuut initialiseer je in de constructor opfalse
. Je hoeft hiervoor dus geen argument aan je constructor toe te voegen.Voeg in
setup
, na defor
-loop die de 25 mensen aanmaakt, deze regel code toe:mensen[0].isBesmet = true;
Hierdoor wordt alvast één mens besmet.
Verander de code in de methode
show
zo, dat een mens als rood vierkant wordt getekend als deze besmet is. Als het goed is, wordt één vierkant nu rood getekend.Vervolgens maken we een methode die kan controleren of een ander mens-object overlap heeft met het object dat de methode uitvoert. Ga voor jezelf na of je de volgende zin begrijpt: Omdat een mens getekend wordt als een vierkant, overlappen twee mensen elkaar als één van de hoeken van het ene vierkant zich binnen de randen van het andere vierkant bevindt. Onderstaande code bevat het begin van de methode
isOverlappend
. Voeg deze code toe aan de klasseMens
.
isOverlappend(andereMens) {
// zet teruggeefwaarde standaard op false
var overlappend = false;
// zet teruggeefwaarde op true als er een overlap is
if ( (this.x + this.breedte >= andereMens.x &&
this.x <= andereMens.x + andereMens.breedte &&
this.y + this.breedte >= andereMens.y &&
this.y <= andereMens.y + andereMens.breedte)
) {
overlappend = true;
}
// stuur de teruggeefwaarde terug
return overlappend;
}
- Nu moeten we in
draw
code toevoegen die alle mogelijke paren van mensobjecten controleert of ze overlappen. Indien ze overlappen, controleren we of een van die objecten besmet is. Als dat zo is wordt het andere ook besmet (als het dat nog niet is). Een simpele manier om dit te controleren is in eenfor
-loop ieder object te controleren met ieder ander object, behalve zichzelf. Dit ziet er zo uit:
// ga alle mensen langs
for (var i = 0; i < mensen.length; i++) {
var mensA = mensen[i];
// ga met mensA opnieuw alle mensen langs om te checken op overlap, behalve met zichzelf
for (var j = 0; j < mensen.length; j++) {
var mensB = mensen[j];
if (mensA != mensB) {
// check overlap
var mensenOverlappen = mensA.isOverlappend(mensB);
if (mensenOverlappen) {
// check of er een besmetting optreedt
if (mensA.isBesmet || mensB.isBesmet) {
// als er één besmet is, wordt ze allebei besmet
// als ze allebei besmet zijn, verandert deze code niets.
mensA.isBesmet = true;
mensB.isBesmet = true;
}
}
}
}
}
Ga de code eens regel voor regel af en leg aan jezelf (of je buur) uit wat hier gebeurt.
c) katten… 🐈
Helaas komen de gezondheidsinstanties erachter dat ook katten een rol spelen in de verspreiding van de ziekte. We zullen ook deze moeten opnemen in onze simulatie.
De array
mensen
gaat ook dieren bevatten. Het is raar als deze naam hetzelfde blijft. Alle ‘dingen’ die iets in onze simulatie doen, heten ‘actoren’. Verander door je hele code de naam van de arraymensen
inactoren
. Dat kan in GitPod heel handig: Zoek de regel waar je demensen
als globale variabele declareert. Waarschijnlijk staat ervar mensen;
. Klik met de rechtermuisknop opmensen
en kies in het menu dat verschijnt ‘Rename Symbol’. Wanneer je op deze manier de naam wijzigt, wordt de naam van deze variabele overal gewijzigd. Wel moet je nog even door de comments gaan om te zien of je ook daar misschien ‘mensen’ moet wijzigen in ‘actoren’Maak onder de klasse
Mens
een nieuwe klasse met de naamKat
. Laat deze precies hetzelfde doen alsMens
, maar met deze verschillen:- de breedte van een kat is 10 pixels
- een niet-besmette kat is blauw in plaats van wit
- een besmette kat is oranje in plaats van rood
Voeg in
setup
na de 25 mensen ook 10 katten toe aan de simulatie. Geef de katten een random snelheid tussen -2 en 2.
Lees nu hoofdstuk 2 van de theorie
Opdracht 4
In de theorie van hoofdstuk 2 heb je de gezien hoe de code van de superklasse Actor
eruit ziet. Je gaat nu de code van Mens
en Kat
aanpassen.
Programmeren
a)
- Voeg, zoals in de theorie voorgedaan, de klasse
Dokter
toe aan je code en voeg 1 dokterobject toe aan de actoren. Controleer of de dokter verschijnt en anderen geneest.
b)
- Maak
Mens
enKat
subklassen vanActor
. Bedenk goed welke code weg mag en welke code veranderd moet worden. Eén methode blijft onveranderd. Weet je welke?
c)
- Vervolgens gaan we de ‘statistieken’ van onze simulatie laten zien. De verantwoordelijkheid voor deze code ligt niet bij een van de actoren, maar bij het ‘raamwerk’ van de simulatie. Deze code schrijven we daarom in dit geval onder
draw
. Zorg dat je op die plek met behulp van de p5js-functie text twee regels in de linkerbovenhoek plaatst: een met het aantal onbesmette actoren en een met het aantal besmette actoren.
d)
- Iedere actor die eenmaal besmet is, wordt in onze simulatie nooit meer beter, tenzij de dokter langskomt. Dat moet veranderen. Actoren moeten ook uit zichzelf weer beter kunnen worden. We gaan daarvoor een teller maken die bij besmetting voor een
Mens
begint bij 400 en voor eenKat
begint op 200. Bij iedere aanroep van de methodeupdate
wordt de afteltimer 1 kleiner. Als de afteltimer 0 is, wordt het attribuutisBesmet
weer opfalse
gezet. Vraag jezelf hiervoor het volgende af:- in welke klasse definieer je
besmettelijkheidsTeller
? - hoe zorg je dat
besmettelijkheidsTeller
wordt ingesteld wanneer er een besmetting plaatsvindt? Tip: maak een methodebesmet()
dieisBesmet
optrue
zet EN debesmettelijkheidsTeller
instelt. - hoe maak je het verschil in gedrag tussen
Mens
enKat
? Als je het in kleine stapjes wilt doen:- Maak het eerst werkend voor één klasse.
- Maak het daarna werkend voor de andere klasse.
- Verplaats waar mogelijk dubbele code naar
Actor
.
- wat gebeurt er met de
besmettelijkheidsTeller
alsupdate
wordt aangeroepen en de actor is niet besmet? - wat gebeurt er met de
besmettelijkheidsTeller
als deze aan het aflopen is en er opnieuw contact is met een andere, besmette, actor?
- in welke klasse definieer je
Speel gerust eens met de waarden van de besmettelijkheidsTeller of het aantal dokters om te zien wat er in je simulatie gebeurt.
Lees nu hoofdstuk 3 van de theorie
opdracht 5
Programmeren
- In de theorie van hoofdstuk 3 is een heel aantal veranderingen genoemd. Verander je code zo, dat de genoemde attributen private worden en ze de juiste getters en setters hebben.
- Alle code staat nog in één bestand: script.js. Dit is niet handig als je code gemakkelijk herbruikbaar wilt maken. Daarom doen we het volgende:
- we maken voor iedere klasse een apart bestand aan, zoals
actor.js
,mens.js
etc. - je javascript wordt uitgevoerd binnen de HTML-pagina
index.html
. Het JavaScript-bestand wordt hierin netjes geladen. Nu we de code hebben verdeeld over meerdere bestanden, moeten we ook aangeven dat deze worden geladen. Voeg boven de regel:
voor ieder bestand nieuwe regel toe zoals:<script id="canvas" src="script.js"></script>
<script src="actor.js"></script>
- we maken voor iedere klasse een apart bestand aan, zoals
- Maak zelf een heel nieuwe actor voor de simulatie. Je mag zelf weten of het een directe subklasse van
Actor
,Mens
,Kat
ofDokter
is, zolang je maar geen code in (één van de) superklassen gaat veranderen om jouw nieuwe klasse te laten werken. Zet deze code in een los bestand. - Maak een volledig UML klassendiagram van de vijf klassen die in jouw simulatie voorkomen.
- Wissel met een klasgenoot jullie zelfbedachte actorklassen uit en neem deze op in je eigen simulatie. Als het goed is, heb je niet veel code nodig om dit voor elkaar te krijgen.
Lees nu hoofdstuk 4 van de theorie
Opdracht 6
In deze opdracht maak je een eigen klasse in C++. Kies uit de volgende twee klassen:
- Een klasse die twee LEDs om en om laat knipperen, dus als de waarschuwingslichten bij een spoorwegovergang. Deze lichten kunnen ook in zijn geheel uit staan.
- Een klasse die een knop uitleest. Bij het indrukken van de knop wisselt de status van het bebehorende object van
aan
naaruit
en andersom.
a) uitdenken
Maak, met theorie van het hoofdstuk 4 in je achterhoofd, een beschrijving (d.w.z. een UML-schets en informele beschrijving van methoden) van de nieuwe klasse. Probeer uit hoever je kan bedenken wat er allemaal in de klasse moet komen.
b) programmeren
- Maak in C++ de klasse zoals je die hebt bedacht.
- Test de klasse uit en pas aan waar nodig, totdat deze werkt zoals gevraagd.
c) uitbreiden
- Heb je gekozen voor de waarschuwingslichten? Kun je het zo maken dat je de knippersnelheid kunt aanpassen? Op welke manier maak je deze eigenschap toegankelijk voor andere programmeurs?
- Heb je gekozen voor de knop. Kun je het zo maken dat de lichte storing die optreedt rond het indrukken van de knop weggefilterd wordt? Je noemt dit debouncen. Check deze voorbeeldcode voor een idee.