Sessies
Kies een reeks hieronder. De Python-sessies bouwen games met Pygame. De Git-sessies leren je versiebeheer: van je eerste commit tot pull requests.
Kies een reeks hieronder. De Python-sessies bouwen games met Pygame. De Git-sessies leren je versiebeheer: van je eerste commit tot pull requests.
Tien sessies waarin je elke maand een compleet Pygame-spel bouwt. Elke sessie bevat een worksheet, een cheatsheet en startcode om te downloaden.
draw()/update() loop en beweegt een sprite met pijltjestoetsen.pygame.Rect, laat de bal stuiteren door de snelheid om te keren en houdt de score bij voor twee spelers.pygame.mixer en bouwt een win- en verlies-scherm.vel_y variabele en detecteert platformbotsingen met pygame.Rect.__init__ en maakt een subklasse via overerving.In deze sessie bouw je een mini-spel: een ster valt naar beneden en jij vangt hem op met een basket. Aan het einde van de sessie beweegt alles, houdt het spel bij hoeveel sterren je vangt, en heb je je eerste eigen game.
draw() functie: wat je elke frame tekentupdate() functie: wat er elke frame verandertmain.py in Thonny.De update() functie draait 60 keer per seconde. Alles wat je daarin zet, wordt dus 60 keer per seconde uitgevoerd. Dat is hoe beweging werkt in een game.
Op dit moment staat er alleen pass in update(). Dat betekent “doe niks”. Verwijder pass en voeg dit toe:
def update():
star.y = star.y + 3Klik op Run. De ster valt nu van boven naar beneden. Als hij het scherm uit valt, verdwijnt hij. Dat lossen we zo op.
Wat gebeurt hier? star.y is de verticale positie van de ster. Hoe groter y, hoe lager op het scherm. Door elke frame + 3 toe te voegen, zakt de ster steeds een beetje.
Het coördinatenstelsel: (0, 0) zit linksboven, niet linksonder zoals in wiskunde. x loopt naar rechts, y loopt naar beneden. De ster begint op y = 30 (bijna helemaal boven), de basket staat op y = 370 (bijna helemaal onder).
Beweeg je muis over het scherm hieronder om de coördinaten te zien:
Beweeg je muis over het scherm om de coördinaten te zien.
Wil je meer weten over hoe het scherm werkt? → Coördinaten uitgelegd
Pas de schuifbalken aan en kijk hoe actor.x en actor.y veranderen als de actor beweegt:
Tijd om de basket te besturen. Pygame Zero heeft een handige keyboard-variabele die bijhoudt welke toetsen ingedrukt zijn.
Voeg dit toe aan update(), na de regel over de ster:
def update():
star.y = star.y + 3
if keyboard.left:
basket.x = basket.x - 5
if keyboard.right:
basket.x = basket.x + 5Klik op Run en gebruik de pijltjestoetsen. De basket beweegt nu mee!
Tip (optioneel, telt als Stretch): Als je de basket te ver naar links of rechts beweegt, verdwijnt hij van het scherm. Kun jij een check toevoegen die dat voorkomt? Hint: gebruik WIDTH en vergelijk met basket.x.
Nu wil je dat er iets gebeurt als de basket de ster raakt. Daarvoor gebruik je colliderect. Die controleert of twee rechthoeken elkaar overlappen.
Voeg dit toe aan update():
if star.colliderect(basket):
star.y = 0De ster springt terug naar boven als je hem vangt. Maar wat als je hem mist? Voeg ook dit toe:
if star.y > HEIGHT:
star.y = 0Bonus: Laat de ster elke keer op een willekeurige plek terug verschijnen. Voeg bovenaan het bestand toe:
import randomVervang dan star.y = 0 (op beide plekken) door:
star.x = random.randint(20, WIDTH - 20)
star.y = 0Nu valt de ster steeds op een andere plek. Veel moeilijker te vangen!
Een echte game houdt bij wat je scoort. Daarvoor heb je een variabele nodig die buiten de functies leeft: een globale variabele.
Klik op de knop hieronder om te zien hoe score verandert elke keer dat je een ster vangt:
Voeg dit toe bovenaan, buiten alle functies (na de regels over basket en star):
score = 0In draw(), voeg toe:
screen.draw.text(f"Score: {score}", topleft=(10, 10), color="white")In update(), pas de catch-code aan zodat de score omhoog gaat:
if star.colliderect(basket):
global score
score = score + 1
star.x = random.randint(20, WIDTH - 20)
star.y = 0global score vertelt Python: “ik bedoel de score van buiten deze functie, niet een nieuwe lokale variabele.” Zonder die regel krijg je een foutmelding.
Klik op Run. De score staat linksboven en telt op elke keer dat je een ster vangt!
Laat je spel zien aan een coach en een buddy. Vertel wat je gemaakt hebt: wat werkt, en wat je nog extra hebt toegevoegd.
“Volgende keer: dingen die TERUGSLAAN. En ze gaan BOEM, met echt geluid.”
Probeer thuis één van deze uitbreidingen. Bij elke staat een code-hint om je op weg te helpen.
Beperk levens — Voeg levens = 3 toe. Bij een misser (star.y > HEIGHT): levens -= 1. Stop het spel als levens == 0 met game_over = True en toon “Game Over” in draw().
Willekeurige ster-kleur — Bij elke vangst: geef de ster een nieuwe kleur met random.randint(50, 255) voor rood, groen en blauw. Begin bij 50, niet bij 0 — anders is de ster soms zwart en onzichtbaar.
Achtergrond — Teken vaste sterren op de achtergrond in draw() voor de score. Gebruik screen.draw.filled_circle(x, y, 2, "white") op 20 willekeurige posities. Zaai random.seed(42) zodat ze niet flikkeren.
Tweede ster — Maak sterren = [star, Actor("star")]. Geef elke ster een eigen x. Werk ze allebei bij in update() en teken ze in draw().
Hoge score — Houd high_score bij. Als score > high_score: high_score = score. Toon f"Beste: {high_score}" naast de score.
Basket kleiner — Na elke 5 punten: basket.width = max(30, basket.width - 5). Zet basket.width terug bij herstart.
Bom — Voeg een rode cirkel toe die af en toe valt. Gebruik een timer bom_timer en random.randint om te bepalen wanneer hij verschijnt. Als de basket de bom raakt: score -= 2.
Moeilijkheidsgraad — Na elke 5 sterren: verhoog de valsnelheid met 1. Bouw een maximum in: max(3, star_snelheid).
Je ruimteschip zweeft in de donkere ruimte terwijl meteoren van boven naar beneden komen. Ontwijk ze, of verlies een leven. Hoe langer je overleeft, hoe sneller ze gaan. En deze keer bouw je ook Dojo Defender: het grotere project dat elke sessie groeit.
main.py.Vul de functie spawn_meteor() in. Een meteoor is een Actor die bovenaan het scherm begint op een willekeurige x-positie:
import random
def spawn_meteor():
rock = Actor('meteor')
rock.x = random.randint(30, WIDTH - 30)
rock.y = 0
meteors.append(rock)Roep de functie aan in update(), maar niet élke frame, anders wordt het scherm meteen volgestort. De update() functie draait 60 keer per seconde. Gebruik dat om een teller bij te houden:
Zie hieronder hoe snel een meteoor beweegt bij verschillende snelheden en hoeveel pixels dat per seconde is:
Gebruik een teller:
# bovenaan, buiten de functies:
timer = 0
def update():
global timer
timer += 1
if timer % 60 == 0: # elke seconde (60 frames)
spawn_meteor()Klik op Run. Na een seconde verschijnt de eerste meteoor, maar hij beweegt nog niet.
Laat alle meteoren in de lijst zakken, en verwijder ze als ze het scherm uit vallen:
def update():
global timer
timer += 1
if timer % 60 == 0:
spawn_meteor()
for rock in meteors[:]: # [:] = kopie zodat je veilig kunt verwijderen
rock.y += 4
if rock.y > HEIGHT + 30:
meteors.remove(rock)Collision detecteren: Als een meteoor het schip raakt, verlies je een leven. Voeg dit toe in de loop:
if rock.colliderect(ship):
meteors.remove(rock)
global lives
lives -= 1
if lives <= 0:
# TODO: game over (stap 3)
passGame over: Voeg een variabele game_over = False toe bovenaan. Als lives == 0, zet game_over = True. In draw(), toon een tekst als game_over True is:
if game_over:
screen.draw.text(
"GAME OVER",
center=(WIDTH / 2, HEIGHT / 2),
color="red",
fontsize=60,
)Stop het bewegen in update() als game_over True is:
def update():
if game_over:
return
...Snelheid verhogen: Laat meteoren sneller gaan naarmate de score stijgt:
snelheid = 3 + score // 5 # elke 5 punten +1 snelheid
rock.y += snelheidScore: Elke seconde dat je overleeft, +1 punt. Voeg global score toe en verhoog in update():
if timer % 60 == 0:
global score
score += 1
spawn_meteor()Meerdere groottes: Maak kleine, middel en grote meteoren. Gebruik een schaal-variabele en pas de hitbox aan:
def spawn_meteor():
rock = Actor('meteor')
rock.x = random.randint(30, WIDTH - 30)
rock.y = 0
rock.schaal = random.choice([0.5, 1.0, 1.5])
meteors.append(rock)Kleinere meteoren bewegen sneller; grotere zijn moeilijker te ontwijken maar geven meer punten.
Download de Dojo Defender starter voor vandaag. Dit is de basis van het project dat elke sessie groeit. Voeg vandaag je ruimteschip toe en laat het bewegen met de pijltjestoetsen.
Was je er vorige keer niet bij? Geen probleem — download de oplossing van vorige keer en je kan meteen mee.
Het volledige Dojo Defender werkblad vind je op de Dojo Defender pagina.
Laat je spel zien aan een coach en een buddy. Hoe lang overleef jij? Wie haalt de hoogste score?
“Volgende keer: je eigen ruimteschip SCHIET TERUG. Vijanden in formatie, en jij blast ze weg.”
sounds/hit.wav).Vijanden staan in formatie bovenaan het scherm. Jij staat onderaan met een ruimteschip en één doel: ze allemaal uitschakelen voordat ze de bodem bereiken. Druk op SPATIE om te schieten, en mis niet.
main.py.Het schip beweegt al met de pijltjestoetsen. Controleer de code in update(). Zorg dat het schip niet buiten het scherm gaat:
if keyboard.left and ship.x > 30:
ship.x -= 5
if keyboard.right and ship.x < WIDTH - 30:
ship.x += 5Vul de functie shoot() in. Een kogel is een Actor die begint op de positie van het schip:
def shoot():
kogel = Actor('bullet')
kogel.x = ship.x
kogel.y = ship.y - 20
bullets.append(kogel)Roep shoot() aan als de spatiebalk wordt ingedrukt. Gebruik on_key_down (Pgzero-stijl):
def on_key_down(key):
if key == keys.SPACE:
shoot()Laat de kogels omhoog bewegen in update() en verwijder ze als ze het scherm uit gaan:
for kogel in bullets[:]:
kogel.y -= 8
if kogel.y < -10:
bullets.remove(kogel)colliderect controleert of de rechthoekige hitbox van twee actors overlapt. Beweeg je muis over het scherm hieronder om te zien wanneer dat gebeurt:
Controleer in update() of een kogel een vijand raakt:
for kogel in bullets[:]:
kogel.y -= 8
if kogel.y < -10:
bullets.remove(kogel)
continue
for vijand in enemies[:]:
if kogel.colliderect(vijand):
bullets.remove(kogel)
enemies.remove(vijand)
global score
score += 10
breakWin-conditie: Als enemies leeg is, heb je gewonnen:
if not enemies:
screen.draw.text("JE WINT!", center=(WIDTH/2, HEIGHT/2), color="yellow", fontsize=60)Laat de vijanden langzaam naar beneden komen. Gebruik een timer:
vijand_timer = 0
def update():
global vijand_timer
vijand_timer += 1
if vijand_timer % 90 == 0: # elke 1,5 seconde
for vijand in enemies:
vijand.y += 20Game over als een vijand de bodem bereikt:
for vijand in enemies:
if vijand.y > HEIGHT - 30:
global game_over
game_over = TrueSnellere schietfrequentie: Bouw een cooldown in zodat de ninja niet oneindig snel kan schieten:
shoot_cooldown = 0
def update():
global shoot_cooldown
if shoot_cooldown > 0:
shoot_cooldown -= 1
def on_key_down(key):
global shoot_cooldown
if key == keys.SPACE and shoot_cooldown == 0:
shoot()
shoot_cooldown = 15Laat je spel zien aan een coach. Hoe snel maak jij alle vijanden weg? Vergelijk scores met een buddy.
“Volgende keer: twee spelers, één bal: PONG. En je leert echte pygame zonder pgzrun.”
Bekijk de cheatsheet voor deze sessie
Download de Dojo Defender starter voor vandaag.
Was je er vorige keer niet bij? Download de oplossing van sessie 1 en begin daarmee.
Het volledige werkblad: Dojo Defender Sessie 2.
Twee paddles, één bal: het klassieke Pong-spel. Maar er is een verrassing: deze sessie schrijf je het spel in echte pygame, zonder pgzrun. Je leert de game loop zelf Installeren. Dat is hoe de meeste echte games werken.
pygame.Rect voor rechthoeken en botsingenmain.py.Verschil met pgzrun: Er zijn geen draw() en update() functies meer. Alles zit in één while running: loop.
Zoek de regels:
# bal.x += ball_dx # zet dit aan als je klaar bent
# ball.y += ball_dyVerwijder de # voor beide regels. Maar stel eerst een startsnelheid in. Zoek ball_dx, ball_dy = 0, 0 en verander naar:
ball_dx, ball_dy = 4, 4Klik op Run. De bal beweegt nu, maar verdwijnt door de rand. Dat lossen we op in stap 2.
Voeg na ball.x += ball_dx en ball.y += ball_dy het volgende toe:
# Stuiteren op boven- en onderrand
if ball.top <= 0 or ball.bottom >= HEIGHT:
ball_dy = -ball_dy
# Stuiteren op paddles
if ball.colliderect(left_paddle) or ball.colliderect(right_paddle):
ball_dx = -ball_dxDe bal stuitert nu oneindig. Voeg ook grenzen toe voor de paddles zodat ze niet buiten het scherm gaan. Kijk naar de code die al in de starter staat.
Als de bal links het scherm uitvalt, scoort de rechter speler. Als hij rechts uitvalt, scoort de linker:
# Bal uit links → rechts scoort
if ball.left <= 0:
score_right += 1
ball.center = (WIDTH // 2, HEIGHT // 2)
ball_dx = 4
# Bal uit rechts → links scoort
if ball.right >= WIDTH:
score_left += 1
ball.center = (WIDTH // 2, HEIGHT // 2)
ball_dx = -4De score staat al in draw(). Controleer dat de variabelen kloppen.
Win bij 5 punten: Voeg een variabele won toe. Als een speler 5 bereikt, stop dan het spel:
if score_left >= 5:
won = "Links wint!"
if score_right >= 5:
won = "Rechts wint!"Toon de winnaar op het scherm en stop de beweging.
Snelheid verhogen: Na elke rally wordt de bal een beetje sneller:
if ball.colliderect(left_paddle) or ball.colliderect(right_paddle):
ball_dx = -ball_dx * 1.05 # 5% sneller
ball_dy = ball_dy * 1.05Bouw een maximum in: ball_dx = max(-12, min(12, ball_dx)).
Speel een potje tegen een buddy. Eerste naar 5 punten wint. Laat het zien aan een coach.
“Volgende keer: Breakout: de bal beukt stenen kapot. En er is GELUID.”
Vandaag verhuist Dojo Defender naar echte Pygame! Download de starter. Was je er niet bij? Download de oplossing van sessie 2. Werkblad: Dojo Defender Sessie 3.
Een bal kaatst heen en weer en beukt rijen gekleurde stenen kapot. Jij bestuurt de paddle om de bal in de lucht te houden. En deze keer hoor je het ook: er zijn geluidseffecten bij elke botsing.
pygame.mixermain.py.Zoek deze regel in de starter:
ball_dx, ball_dy = 4, 0
# ball_dy = -4 ← verwijder de # om de bal te laten bewegen!Verwijder de # voor ball_dy = -4. Nu heeft de bal een verticale snelheid. Voeg beweging toe in de game loop (zoek de update-sectie):
ball.x += ball_dx
ball.y += ball_dyKlik op Run. De bal beweegt diagonaal maar verdwijnt door de randen.
Voeg stuiteren toe:
# Boven-, links- en rechtsrand
if ball.left <= 0 or ball.right >= WIDTH:
ball_dx = -ball_dx
if ball.top <= 0:
ball_dy = -ball_dy
# Paddle
if ball.colliderect(paddle):
ball_dy = -ball_dy
if snd_hit:
snd_hit.play()Levens: Als de bal de onderkant bereikt, verlies je een leven:
if ball.top > HEIGHT:
levens -= 1
# Reset bal bovenop de paddle
ball.center = (paddle.centerx, paddle.top - BALL_SIZE)
ball_dy = -4Controleer collision met elke steen in de loop:
for steen in stenen[:]:
if ball.colliderect(steen['rect']):
stenen.remove(steen)
ball_dy = -ball_dy
score += 10
if snd_hit:
snd_hit.play()
break # slechts één steen per frame brekenWin-conditie: Als alle stenen weg zijn, heeft de ninja gewonnen. Toon een bericht:
if not stenen:
# toon win-schermExplosiegeluid als een steen breekt (gebruik snd_explode uit de starter):
if snd_explode:
snd_explode.play()Game over bij 0 levens: toon een scherm en stop de bal.
Snelheid verhogen naarmate er minder stenen overblijven:
snelheid_factor = 1 + (1 - len(stenen) / totaal_stenen) * 0.5
ball_dx_huidig = ball_dx * snelheid_factorNieuwe rij stenen als alles weg is: roep stenen = maak_stenen() opnieuw aan en verhoog de moeilijkheidsgraad.
Wie haalt de meeste stenen weg? Vergelijk scores en laat je coach de hoogste streak zien.
“Volgende keer: zwaartekracht. Jouw karakter valt, en jij moet hem laten springen op platforms.”
Bekijk de cheatsheet voor deze sessie
Dojo Defender krijgt een menu en nieuwe vijandtypes! Download de starter. Was je er niet bij? Download de oplossing van sessie 3. Werkblad: Dojo Defender Sessie 4.
In deze sessie bouw je een micro-platformer. Je speler heeft zwaartekracht, kan springen, en verzamelt sterren op platforms. Je gebruikt voor het eerst pygame direct, zonder pgzrun, en voegt geluidseffecten toe met pygame.mixer.
vel_y variabelevel_y negatief te makenpygame.Rectpygame.mixermain.py in Thonny.In een platformer valt de speler continu naar beneden, tenzij hij op een platform staat. We simuleren dat met vel_y: een verticale snelheid die elke frame groter wordt door zwaartekracht.
Zoek de # STAP 1 comment in main.py en vervang de pass door:
# Zwaartekracht toepassen
vel_y += GRAVITY
player_rect.y += vel_y
# Controleer of speler op een platform staat
on_ground = False
for platform in platforms:
if (player_rect.colliderect(platform) and vel_y > 0):
player_rect.bottom = platform.top
vel_y = 0
on_ground = TrueGRAVITY = 0.5 staat al bovenaan het bestand. Klik Run. De speler valt nu naar het dichtstbijzijnde platform en blijft daar staan.
Wat gebeurt hier? Elke frame wordt vel_y iets groter (de speler versnelt naar beneden). Als de speler een platform raakt terwijl hij naar beneden valt (vel_y > 0), zet je zijn onderkant (bottom) precies op de bovenkant van het platform en stop je de val (vel_y = 0).
Een platformer zonder springen is maar half af. Druk op SPATIE om te springen: dat is niets anders dan vel_y plotseling negatief maken.
Zoek de # STAP 2 comment en voeg toe:
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT]:
player_rect.x -= SPEED
if keys[pygame.K_RIGHT]:
player_rect.x += SPEED
# Springen — alleen als je op de grond staat
if keys[pygame.K_SPACE] and on_ground:
vel_y = -12Klik Run en test:
Tip: Als de speling te hoog of te laag voelt, verander dan -12 in -10 (lager springen) of -15 (hoger springen).
Laten we iets te verzamelen toevoegen. De starter heeft al een lijst stars met pygame.Rect-objecten. Jij schrijft de botsingsdetectie.
Zoek de # STAP 3 comment:
for star in stars[:]: # [:] zodat je veilig kunt verwijderen tijdens het loopen
if player_rect.colliderect(star):
stars.remove(star)
score += 1En in de tekenfunctie (zoek # TEKEN STERREN):
for star in stars:
pygame.draw.polygon(screen, YELLOW, star_points(star.centerx, star.centery, 12, 5))star_points() is al gedefinieerd in de starter. Die berekent de punten van een 5-puntige ster.
Bovenaan het spel staat score = 0. Teken de score op het scherm (zoek # TEKEN SCORE):
score_surf = font.render(f"Sterren: {score}", True, WHITE)
screen.blit(score_surf, (10, 10))Nu voeg je een springgeluid toe en een win-scherm als alle sterren verzameld zijn.
Geluid laden (dit staat al klaar in de starter; controleer dat jump.wav in de sounds/ map zit):
pygame.mixer.init()
jump_snd = pygame.mixer.Sound("sounds/jump.wav")Geluid afspelen bij springen: voeg toe aan de sprong-code:
if keys[pygame.K_SPACE] and on_ground:
vel_y = -12
jump_snd.play()Win-scherm: voeg toe na de ster-loop:
if len(stars) == 0:
win_surf = font.render("Gewonnen! Alle sterren verzameld!", True, YELLOW)
screen.blit(win_surf, (WIDTH // 2 - win_surf.get_width() // 2, HEIGHT // 2))
pygame.display.flip()
pygame.time.wait(3000)
running = FalseLaat je spel zien aan een coach en een buddy. Kun je alle sterren verzamelen voor de tijd om is?
De Dojo Defender snapshot van vandaag bouwt verder op sessie 5:
Download de Dojo Defender starter of oplossing.
“Volgende keer: klik op bugs en ZAP ze weg, met je eigen klassen.”
Probeer thuis één van deze uitbreidingen:
Bugs vallen van boven naar beneden. Jij schiet omhoog om ze te raken. In deze sessie leer je OOP: je schrijft je eerste eigen klasse (Bug), en daarna twee subklassen: een die slingert en een die op je duikt. Klassen zijn de bouwstenen van bijna alle grote programma’s.
__init__ en eigen methodenmain.py in Thonny.De Bug-klasse
Zoek de # STAP 1 — BUG KLASSE comment en schrijf:
class Bug:
def __init__(self, x, y):
self.x = x
self.y = y
self.alive = True
def update(self):
self.y += 2 # valt naar beneden
def draw(self, screen):
pygame.draw.circle(screen, GREEN, (int(self.x), int(self.y)), 15)
# Ogen
pygame.draw.circle(screen, BLACK, (int(self.x) - 5, int(self.y) - 4), 3)
pygame.draw.circle(screen, BLACK, (int(self.x) + 5, int(self.y) - 4), 3)Bugs laten spawnen: de starter heeft al een timer. Zoek # SPAWN BUG:
bugs.append(Bug(random.randint(30, WIDTH - 30), -20))Schieten: zoek # SCHIET (dit staat in de event-loop bij K_SPACE):
bullets.append(pygame.Rect(player_x - 3, player_y - 20, 6, 12))Update bullets elke frame (zoek # UPDATE BULLETS):
for b in bullets[:]:
b.y -= 10
if b.y < 0:
bullets.remove(b)
pygame.draw.rect(screen, YELLOW, b) # dit staat al klaarNu schrijf je de botsingsdetectie: als een kogel een bug raakt, sterft de bug.
Zoek # STAP 2 — BOTSING:
for bug in bugs[:]:
bug.update()
bug.draw(screen)
if bug.y > HEIGHT + 20:
bugs.remove(bug)
continue
bug_rect = pygame.Rect(bug.x - 15, bug.y - 15, 30, 30)
for bullet in bullets[:]:
if bullet.colliderect(bug_rect):
bug.alive = False
bullets.remove(bullet)
score += 1
break
if not bug.alive:
bugs.remove(bug)Klik Run. Schiet op de bugs: ze verdwijnen bij een treffer!
Nu maak je een subklasse: een Bug die heen en weer slingert.
import math
class SlingerBug(Bug):
def __init__(self, x, y):
super().__init__(x, y)
self.start_x = x
self.timer = 0
def update(self):
self.timer += 0.05
self.x = self.start_x + math.sin(self.timer) * 60
self.y += 1.5 # iets langzamer, maar moeilijker te raken
def draw(self, screen):
super().draw(screen)
# Oranje cirkel eromheen als visuele aanwijzing
pygame.draw.circle(screen, ORANGE, (int(self.x), int(self.y)), 18, 2)Spawnen van SlingerBugs: voeg toe aan de spawn-code (bijv. elke 3e bug):
if random.random() < 0.3:
bugs.append(SlingerBug(random.randint(30, WIDTH - 30), -20))
else:
bugs.append(Bug(random.randint(30, WIDTH - 30), -20))super().__init__(x, y) roept de __init__ van de ouderklas (Bug) aan, dus je hoeft self.x, self.y en self.alive niet opnieuw te schrijven.
De DuikBug detecteert de positie van de speler en duikt er recht op af.
class DuikBug(Bug):
def __init__(self, x, y, player_x_ref):
super().__init__(x, y)
self.player_x_ref = player_x_ref # functie die huidige speler-x geeft
self.speed_x = 0
self.speed_y = 1
def update(self):
target_x = self.player_x_ref()
dx = target_x - self.x
dist = max(abs(dx), 1)
self.x += dx / dist * 2
self.y += 2.5
def draw(self, screen):
super().draw(screen)
pygame.draw.circle(screen, RED, (int(self.x), int(self.y)), 18, 2)Spawnen: gebruik een lambda om de speler-x door te geven:
bugs.append(DuikBug(random.randint(30, WIDTH - 30), -20, lambda: player_x))Bonus: Teken een HP-balk. Start met lives = 3 en trek er één af als een bug de onderkant haalt.
Laat je spel zien aan een coach en een buddy. Hoeveel bugs kun je neerzappen voor je levens op zijn?
“Volgende keer: een oneindige weg in de lucht, en alles SCROLT voorbij.”
Probeer thuis één van deze uitbreidingen:
lives-systeem toe met 3 levens, en als een bug de onderkant haalt, verlies je er één.PantserbBug die 3 treffers nodig heeft voor hij sterft (gebruik een hp-attribuut).Deze sessie bouw je ook verder aan Dojo Defender. Je voegt een eindbaas (boss) toe die om de 5 waves verschijnt met 3 fases.
Bekijk de Dojo Defender sessie 6 voor de instructies.
De starter en oplossing staan klaar.
Je schip vliegt door een eindeloze luchtweg. De achtergrond scrolt langs je heen, rode obstakels komen van rechts, en sterren geven punten. Hoe langer je overleeft, hoe sneller het wordt!
scroll_x variabelemain.py in Thonny.Een scrollende achtergrond geeft de illusie van beweging. We tekenen de achtergrond twee keer naast elkaar en schuiven de positie elke frame op.
Zoek # STAP 1 en voeg toe:
# Beweeg achtergrond naar links
scroll_x -= speed
if scroll_x <= -WIDTH:
scroll_x = 0
# Teken achtergrond twee keer
screen.blit(bg_image, (int(scroll_x), 0))
screen.blit(bg_image, (int(scroll_x) + WIDTH, 0))scroll_x begint op 0 en wordt elke frame kleiner. Als het -WIDTH bereikt, springen we terug naar 0: een naadloze loop.
Klik Run. De lucht scrolt nu voorbij je schip!
Obstakels komen van rechts en bewegen naar links. Als je ze raakt, verlies je een leven.
Obstakels updaten (zoek # STAP 2):
for obs in obstacles[:]:
obs.x -= speed
if obs.x < -obs.width:
obstacles.remove(obs)
pygame.draw.rect(screen, RED, obs)
# Botsing
if ship_rect.colliderect(obs):
obstacles.remove(obs)
lives -= 1
if lives <= 0:
running = FalseLevens tekenen:
for i in range(lives):
pygame.draw.rect(screen, RED, (10 + i * 25, 10, 18, 18))Obstakels spawnen (in de spawn-timer-event):
h = random.randint(40, 120)
obstacles.append(pygame.Rect(WIDTH, random.randint(50, HEIGHT - h - 50), 30, h))Sterren geven punten en verdwijnen als je ze raakt.
Zoek # STAP 3:
for star in stars[:]:
star.x -= speed
if star.x < -20:
stars.remove(star)
continue
pygame.draw.circle(screen, YELLOW, star.center, 10)
if ship_rect.colliderect(star):
stars.remove(star)
score += 1
# Score tekenen:
score_surf = font.render(f"Score: {score}", True, WHITE)
screen.blit(score_surf, (WIDTH - 120, 10))Spawnen van sterren (in dezelfde spawn-timer, maar minder vaak):
if random.random() < 0.4:
stars.append(pygame.Rect(WIDTH, random.randint(40, HEIGHT - 40), 20, 20))Nu maak je de game steeds moeilijker naarmate de score stijgt.
Snelheid schalen (zoek # STAP 4):
speed = BASE_SPEED + score * 0.1BASE_SPEED = 4 staat al bovenaan. Bij score 20 gaat alles dubbel zo snel!
Spawn-interval aanpassen: hoe hoger de score, hoe vaker nieuwe obstakels komen:
spawn_interval = max(500, 1800 - score * 30) # min. 500ms
pygame.time.set_timer(SPAWN_EVENT, spawn_interval)Game over scherm:
if not running:
go_surf = font.render("GAME OVER", True, RED)
screen.blit(go_surf, (WIDTH // 2 - go_surf.get_width() // 2, HEIGHT // 2 - 30))
sc_surf = font.render(f"Score: {score}", True, WHITE)
screen.blit(sc_surf, (WIDTH // 2 - sc_surf.get_width() // 2, HEIGHT // 2 + 10))
pygame.display.flip()
pygame.time.wait(3000)Laat je spel zien aan een coach en een buddy. Wie haalt de hoogste score?
“Volgende keer: een baas die terugvecht, in DRIE fases.”
Probeer thuis één van deze uitbreidingen:
Vastgelopen? Vraag het volgende dojo aan een coach, of probeer gewoon iets anders. Programmeren is doen.
Vandaag werk je ook verder aan Dojo Defender — maar niet met stap-voor-stap instructies. Jij kiest wat je bouwt.
Download de Dojo Defender starter — dit is de complete game met alles erop en eraan (schip, vijanden, asteroïden, waves, boss). Kies een feature uit de lijst, plan hem kort met een coach, en ga aan de slag.
👉 Alles over Dojo Defender vind je op de Dojo Defender pagina.
De eindbaas wacht op je. Hij beweegt heen en weer, schiet kogels en wordt steeds gevaarlijker naarmate zijn HP daalt. Jij schiet terug, houdt zijn HP bij op een balk, en overleeft drie fasen. Dit is de moeilijkste sessie, en de meest bevredigende als je hem haalt.
main.py in Thonny.De baas beweegt heen en weer over het scherm. Als hij de rand raakt, keert hij om.
Zoek # STAP 1 en voeg toe:
boss_rect.x += boss_speed
# Omdraaien bij de rand
if boss_rect.right >= WIDTH or boss_rect.left <= 0:
boss_speed = -boss_speedboss_speed = 3 staat al bovenaan. Klik Run: de baas dendert van links naar rechts!
Speler bewegen en schieten (zoek # SPELER):
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT] and player_rect.left > 0:
player_rect.x -= PLAYER_SPEED
if keys[pygame.K_RIGHT] and player_rect.right < WIDTH:
player_rect.x += PLAYER_SPEED
# Schiet (zoek # SCHIET in event-loop):
player_bullets.append(pygame.Rect(player_rect.centerx - 3, player_rect.top - 15, 6, 15))Botsing speler-kogel met baas:
Zoek # STAP 2:
for b in player_bullets[:]:
b.y -= 8
if b.y < 0:
player_bullets.remove(b)
continue
pygame.draw.rect(screen, YELLOW, b)
if b.colliderect(boss_rect):
player_bullets.remove(b)
boss_hp -= 1
if boss_hp <= 0:
running = False # speler wint!HP-balk tekenen (zoek # HP BALK):
# Achtergrond van de balk
pygame.draw.rect(screen, DARK_RED, (10, 10, 300, 20))
# Gevulde balk op basis van huidige HP
breedte = int(300 * boss_hp / BOSS_MAX_HP)
pygame.draw.rect(screen, RED, (10, 10, breedte, 20))
# Label
hp_surf = font.render(f"Baas HP: {boss_hp}", True, WHITE)
screen.blit(hp_surf, (320, 10))Klik Run. Schiet op de baas: de HP-balk slinkt!
De baas schiet elke N frames een kogel naar beneden.
Zoek # STAP 3:
boss_shoot_timer += 1
if boss_shoot_timer >= boss_shoot_interval:
boss_shoot_timer = 0
boss_bullets.append(pygame.Rect(boss_rect.centerx - 4, boss_rect.bottom, 8, 16))Baas-kogels updaten:
for b in boss_bullets[:]:
b.y += 6
if b.y > HEIGHT:
boss_bullets.remove(b)
continue
pygame.draw.rect(screen, ORANGE, b)
if b.colliderect(player_rect):
boss_bullets.remove(b)
player_lives -= 1
if player_lives <= 0:
running = FalseTeken player_lives als hartjes of rode blokjes onderaan het scherm.
Nu reageert de baas op zijn HP:
Zoek # STAP 4:
if boss_hp > 50:
boss_phase = 1
boss_speed_abs = 3
boss_shoot_interval = 60
elif boss_hp > 25:
boss_phase = 2
boss_speed_abs = 5
boss_shoot_interval = 35
else:
boss_phase = 3
boss_speed_abs = 7
boss_shoot_interval = 20
# Pas de snelheid aan zonder de richting te wisselen:
boss_speed = boss_speed_abs * (1 if boss_speed > 0 else -1)Fase 3: dubbele kogels (voeg toe in de shoot-code):
if boss_phase == 3:
boss_bullets.append(pygame.Rect(boss_rect.left + 10, boss_rect.bottom, 8, 16))
boss_bullets.append(pygame.Rect(boss_rect.right - 18, boss_rect.bottom, 8, 16))
else:
boss_bullets.append(pygame.Rect(boss_rect.centerx - 4, boss_rect.bottom, 8, 16))Win-scherm bij boss_hp <= 0:
screen.fill(BLACK)
win = font.render("BAAS VERSLAGEN!", True, YELLOW)
screen.blit(win, (WIDTH // 2 - win.get_width() // 2, HEIGHT // 2))
pygame.display.flip()
pygame.time.wait(3000)Laat je spel zien aan een coach en een buddy. Wie haalt fase 3 en overleeft?
“Volgende keer: jouw eigen spel, van nul, helemaal jouw idee.”
Probeer thuis één van deze uitbreidingen:
Dit is jouw sessie. Geen vaste stappen, geen verplichte mechanics. Jij beslist wat je bouwt, en vandaag maak je het.
In negen sessies heb je geleerd:
Al die bouwstenen liggen klaar. Vandaag combineer je ze in je eigen spel.
Nog geen idee? Hier zijn wat genres om van te starten:
Dodge-game: wijk objecten uit die steeds sneller komen. Simpel maar verslavend.
Platformer: spring van platform naar platform, verzamel items, vermijd vijanden.
Shooter: schiet vijanden neer die van boven of van de zijkant komen.
Puzzelgame: schuif blokjes, verbind punten, of los een patroon op.
Racegame: ontwerp een parcours en beweeg zo snel mogelijk naar de finish.
Vertel een verhaal: geen score, geen levens. Laat de speler klikken en keuzes maken.
Je mag ook iets combineren: een shooter met puzzelelementen, een platformer met een baas aan het einde. Alles mag.
Vóór je code schrijft, beantwoord deze drie vragen:
Schrijf je antwoorden op een papiertje of in een comment bovenaan je code. Dit helpt je gefocust te blijven als je vastloopt.
Wil je een loopanimatie, een explosie of een knipperend object? Maak een lijst met afbeeldingsnamen en wissel actor.image elke N milliseconden. De demo hieronder laat zien hoe dat werkt: gebruik de schuifbalk om de snelheid aan te passen en de knop om te pauzeren:
In Python gebruik je dan een lijst met afbeeldingsnamen en een timer:
frames = ['lopen_1', 'lopen_2', 'lopen_3', 'lopen_4']
anim_timer = 0
FRAME_DUUR = 10 # frames (bij 60 fps = ~167 ms)
def update():
global anim_timer
anim_timer += 1
speler.image = frames[(anim_timer // FRAME_DUUR) % len(frames)]Download de starter via deze link. De starter heeft:
draw()- en update()-sectieOpen main.py en begin met Stap 1 van je eigen plan. De cheatsheet op deze pagina heeft alle patronen van de vorige sessies bij de hand.
Vastgelopen? Vraag een coach. Beschrijf wat je wilt bereiken, niet alleen wat niet werkt. Dan kunnen we samen de beste aanpak bedenken.
Te snel klaar? Voeg geluid toe, maak een start-scherm, of voeg een tweede speler toe.
Aan het einde van de sessie presenteert iedereen zijn spel. Je hoeft het niet af te hebben. Laat zien wat je gemaakt hebt en vertel:
CoderDojo stopt na tien sessies. Zelf bouwen stopt niet.
Blijf bouwen. Kleine projectjes leren je meer dan grote cursussen. Maak een spel voor je broer of zus, je huisdier, of gewoon voor jezelf.
Inspiratie nodig?
CoderDojo komt terug. Jij ook?
Vijf sessies over Git en GitHub, van je eerste commit tot pull requests. Plus een bonus-sessie over Markdown, de taal waarin je notities en documentatie schrijft.
.gitignore en workflow-tips.Stel je voor: je werkt drie uur aan je game. Je voegt een cool nieuw wapen toe. Maar… nu doet de rest van je game het niet meer. En je weet niet meer wat je precies veranderd hebt. Weg drie uur werk.
Git is de oplossing. Git onthoudt élke versie van je bestanden. Als een oneindige “undo”-knop die nooit vergeet wat je gedaan hebt.
In deze sessie installeer je Git, maak je je eerste repository en leg je voor altijd vast wat je doet: stap voor stap, versie voor versie. En het leuke: Git werkt niet alleen voor code. Ook voor notities, schoolverslagen en verhalen.
Git is een versiebeheersysteem. Het houdt bij wat jij verandert in je bestanden, wanneer je dat deed, en waarom. Elke keer dat je een stukje werk af hebt, maak je een commit: een foto van al je bestanden op dat moment.
Wat Git bijzonder maakt:
Git is gemaakt door Linus Torvalds, dezelfde persoon die Linux bouwde. Hij had iets nodig om met duizenden programmeurs tegelijk aan de Linux-kernel te werken. In 2005 bouwde hij Git in een weekend. Vandaag gebruikt bijna elke ontwikkelaar ter wereld het.
Git is gebouwd voor broncode, maar het werkt met alle tekstbestanden. Een tekstbestand is elk bestand dat je met Kladblok of een simpele editor kunt openen en lezen: .py, .html, .css, .json, .txt, .csv, .md (Markdown), .yml, .toml, noem maar op.
Wat Git níet goed kan: binaire bestanden. Dat zijn bestanden die niet uit leesbare tekst bestaan: afbeeldingen (.png, .jpg), video’s (.mp4), gecompileerde programma’s (.exe), Word-documenten (.docx). Git kan ze wél bijhouden, maar het is trager en je kunt niet zien wát er precies veranderd is. Bij tekstbestanden toont git diff elke letter die je toevoegde of weghaalde. Bij een .png zegt Git alleen “dit bestand is gewijzigd”, maar niet wát er aan de afbeelding veranderde.
Veel notitie-apps van tegenwoordig gebruiken Markdown (.md-bestanden) om je documenten op te slaan. Denk aan:
.md-bestanden in een map op je computerOmdat Markdown-bestanden gewone tekstbestanden zijn, kun je er Git op loslaten. Je houdt de geschiedenis van je notities bij, je kunt terug naar een vorige versie van een document, en je kunt je notities delen via GitHub, precies zoals je met code doet.
Een map met Markdown-notities onder Git zetten is even simpel als een Python-project:
mkdir mijn-notities
cd mijn-notities
git init
echo "# Mijn Notities" > start.md
git add start.md
git commit -m "Eerste notitie: startpagina"Vanaf dat moment bewaart Git elke wijziging aan je notities. Schrijf je een verslag voor school in Markdown? Commit elke paragraaf. Werk je aan wereldbouw voor een verhaal? Git onthoudt elke versie van je plot.
| Wél Git gebruiken | Beter iets anders |
|---|---|
Notities in Markdown (.md) | Notities in Word (.docx) |
Configuratiebestanden (.json, .yml) | Grote afbeeldingen of video’s bij je notities |
| Schrijfwerk: verslagen, verhalen, blogs | Realtime samenwerking zoals Google Docs (daar is Git te traag voor) |
| Je CoderDojo-cheatsheets | Wachtwoorden of persoonlijke dagboeken (tenzij private repo) |
Kortom: alles wat tekst is, kun je in Git stoppen. Alles wat binair is, beter niet.
Zonder Git ziet je workflow er zo uit:
game.py
game_backup.py
game_backup2.py
game_final.py
game_final_echt.py
game_final_echt_nieuwe_wapens.pyHerkenbaar? Met Git heb je maar één bestand nodig: game.py. Git onthoudt de rest.
Wat versiebeheer je oplevert:
Git is gemaakt voor tekstbestanden: bestanden die jij zelf schrijft: code, notities, configuratie. Er zijn dingen die je beter buiten Git houdt:
| Stop wél in Git | Stop NIET in Git |
|---|---|
Je Python-bestanden (.py) | Wachtwoorden, API-sleutels, tokens |
| Afbeeldingen die je game gebruikt | Bestanden die je programma zelf maakt (.exe, .pyc) |
Geluidsbestanden (.wav, .mp3) | De __pycache__ map |
| Tekstbestanden, configuratie | Grote bestanden (>50 MB) zoals video’s |
Je README.md | Instellingen van jouw specifieke computer |
Waarom geen wachtwoorden in Git? Omdat Git álles onthoudt, voor altijd. Zelfs als je later een wachtwoord verwijdert, zit het nog in de geschiedenis. Iedereen die jouw code ooit ziet, kan terugscrollen naar die commit. En als je code ooit op GitHub komt, staat je wachtwoord op het internet. Voor eeuwig.
Gebruik een .gitignore-bestand om Git te vertellen welke bestanden het moet negeren. Daar kom je zo meteen achter.
Open de Terminal (zoek naar “Terminal” in Spotlight) en typ:
git --versionAls Git niet geïnstalleerd is, vraagt macOS je om de developer tools te installeren. Klik op “Install”. Klaar.
sudo apt install gitOpen een terminal (Git Bash op Windows) en typ:
git --versionJe ziet iets als git version 2.47.0. Dat betekent: Git staat klaar.
Git wil weten wie jij bent, zodat het jouw naam bij elke commit kan zetten. Dit doe je één keer, daarna onthoudt Git het.
git config --global user.name "Jouw Naam"
git config --global user.email "jouw@email.com"Gebruik hetzelfde e-mailadres dat je straks voor GitHub gebruikt. Dat maakt koppelen makkelijker.
Tip: --global betekent: deze instelling geldt voor ál je Git-projecten. Je hoeft dit maar één keer te doen.
Een repository (of “repo”) is een map waar Git de versies bijhoudt. Laten we er één maken.
Maak eerst een nieuwe map voor je project:
mkdir mijn-eerste-git-project
cd mijn-eerste-git-projectNu vertel je Git: “Deze map is een repository.”
git initJe ziet: Initialized empty Git repository in .../mijn-eerste-git-project/.git/
Git heeft een verborgen map .git aangemaakt. Daar bewaart het álles: de geschiedenis, de commits, de configuratie. Raak die map nooit met de hand aan, want Git beheert hem zelf.
Maak een bestand aan. Bijvoorbeeld een Python-bestand met één regel:
echo 'print("Hallo Git!")' > hallo.pyNu vertel je Git: “Let op dit bestand.”
git add hallo.pyMet git add zet je bestanden in de staging area: een tussenstation. Je zegt tegen Git: “Deze wijzigingen wil ik in mijn volgende commit.”
Controleer wat er klaarstaat:
git statusGit toont:
On branch master
Changes to be committed:
new file: hallo.pyNu komt de commit zelf:
git commit -m "Mijn eerste commit: hallo.py toegevoegd"Wat gebeurt hier? -m staat voor “message”. De tekst tussen aanhalingstekens is je commit message: een korte uitleg van wat je veranderd hebt. Git heeft nu een permanente foto van je project gemaakt.
Goede commit messages: Schrijf in het Engels (dat is de afspraak in bijna alle projecten). Begin met een werkwoord: “Add”, “Fix”, “Update”. Hou het kort: maximaal 72 karakters.
Open hallo.py in een teksteditor. Verander de regel naar:
print("Hallo Git! Jij onthoudt mijn code.")Sla het bestand op. Kijk nu wat Git ziet:
git statusGit weet dat hallo.py gewijzigd is. Maar wát is er precies veranderd?
git diffgit diff toont exact welke regels je toegevoegd (groen met +) en verwijderd (rood met -) hebt. Dit is één van de krachtigste dingen van Git: je ziet letterlijk wat er veranderd is, karakter voor karakter, sinds je laatste commit.
Commit de wijziging:
git add hallo.py
git commit -m "Update: begroeting uitgebreid"Dit is waar Git magisch wordt. Stel: je hebt spijt van je laatste wijziging. Je wilt terug naar de eerste versie.
Toon eerst alle commits:
git log --onelineJe ziet zoiets:
a1b2c3d Update: begroeting uitgebreid
e4f5g6h Mijn eerste commit: hallo.py toegevoegdElke commit heeft een unieke code, een hash. Die lange code (verkort tot 7 karakters) identificeert exact die ene versie van je project.
Om te zien hoe hallo.py eruitzag in de eerste commit:
git show e4f5g6h:hallo.pyDaar is je originele print("Hallo Git!") weer.
Wil je écht terug in de tijd? Dat kan:
git checkout e4f5g6h -- hallo.pyNu staat hallo.py weer zoals in je eerste commit. Controleer met cat hallo.py. Je ziet de oude versie. Maar maak je geen zorgen: je tweede commit is niet weg. Met git checkout master -- hallo.py ga je weer naar de nieuwste versie.
.gitignoreMaak een bestand aan dat Git moet negeren:
echo "GEHEIM_WACHTWOORD=12345" > geheimen.txtgit status toont dit bestand nu als “untracked”. Git heeft het gezien, maar weet niet of je het wilt bijhouden. Je kunt het negeren met een .gitignore-bestand:
echo "geheimen.txt" > .gitignoreNu git status opnieuw en geheimen.txt is verdwenen uit de lijst. Git negeert het. (Voeg .gitignore zelf wél toe aan Git met git add .gitignore en git commit, zodat anderen ook weten wat er genegeerd moet worden.)
Een goed .gitignore voor een Python-project:
# Python
__pycache__/
*.pyc
*.pyo
# Geheimen
*.env
secrets.txt
# Jouw editor
.vscode/
.idea/Laat aan een coach en een buddy zien:
git log --oneline: jouw commit-geschiedenis.git diff die toont wat je veranderd hebt..gitignore-bestand.“Volgende keer: twee versies van je code tegelijk. Je werkt aan een nieuwe feature terwijl de oude versie gewoon blijft werken. Dat heet branches, en het is wat Git écht krachtig maakt.”
git diff om de wijziging te bekijken, en commit hem met een goede message.git show om elke versie te bekijken. Gebruik git checkout om terug te gaan naar de eerste commit, en daarna weer naar de laatste..gitignore. Zorg dat __pycache__/ en .pyc-bestanden écht genegeerd worden (check met git status).Vastgelopen? Vraag het volgende dojo aan een coach, of probeer gewoon iets anders. Programmeren is doen. Git leren is doen.
Vorige sessie leerde je commits maken: foto’s van je code op één tijdlijn. Alles netjes achter elkaar.
Maar wat als je een nieuw idee wil uitproberen? Een lasergun toevoegen aan je game, bijvoorbeeld. Je weet niet of het gaat werken. Je wil je werkende code niet kapot maken.
Daar zijn branches voor.
Een branch is een kopie van je code waar je vrij kunt experimenteren. Je hoofdcode (de master-branch) blijft veilig. Als je experiment werkt, plak je het terug in master. Werkt het niet? Je gooit de branch weg. Je master-branch heeft er nooit iets van gemerkt.
Noot: Op GitHub en in veel nieuwe projecten heet de hoofdbranch
mainin plaats vanmaster. Dat is exact hetzelfde, alleen de naam is anders. In deze cursus gebruiken wemaster, maar als je onlinemaintegenkomt, weet je dat het hetzelfde betekent.
Open je terminal in het project van vorige sessie. Check waar je bent:
git status
git log --onelineJe hebt een paar commits op master. Dit is je stabiele basis: hier ga je straks vanaf splitsen.
Je gaat een nieuwe feature toevoegen: een highscore.txt-bestand dat de hoogste score bijhoudt. Maar eerst maak je een branch:
git branch highscore-featureGit heeft nu een nieuwe branch aangemaakt. Maar je staat nog steeds op master. Check welke branches er zijn:
git branchJe ziet:
highscore-feature
* masterHet sterretje bij master betekent: “hier sta je nu.” Wissel naar je nieuwe branch:
git switch highscore-feature(Oudere Git-versies gebruiken git checkout highscore-feature. Beide werken.)
Nog een keer git branch: het sterretje staat nu bij highscore-feature. Alles wat je nu commit, gebeurt op deze branch. master blijft onaangeroerd.
Tip: Je kunt een branch aanmaken en er meteen naartoe switchen in één commando:
git switch -c mijn-nieuwe-branch-c staat voor “create”. Dit is sneller en je vergeet nooit te switchen.
Maak een nieuw bestand aan:
echo "HIGHSCORE: 0" > highscore.txtCommit je werk:
git add highscore.txt
git commit -m "Add highscore.txt met beginwaarde 0"Voeg nog een bestand toe dat de highscore leest:
echo 'def lees_highscore():' > highscore_manager.py
echo ' with open("highscore.txt") as f:' >> highscore_manager.py
echo ' return int(f.read().split(": ")[1])' >> highscore_manager.pyCommit opnieuw:
git add highscore_manager.py
git commit -m "Add highscore_manager: functie om highscore te lezen"Kijk nu naar je log:
git log --onelineJe ziet al je commits van master, plus de twee nieuwe. Git onthoudt de hele keten.
Switch terug naar master:
git switch masterKijk wat er hier is:
lshighscore.txt en highscore_manager.py zijn… weg. Ze bestaan alleen op de highscore-feature-branch. Op master is alles nog precies zoals je het achterliet.
Dit is de magie van branches: twee (of meer) versies van je project, tegelijk op je computer, zonder dat ze elkaar in de weg zitten.
Switch nog eens heen en weer om het te voelen:
git switch highscore-feature # bestanden zijn terug
git switch master # bestanden zijn weer weggit mergeJe highscore-feature werkt. Tijd om hem terug in master te zetten. Dit heet mergen.
Zorg dat je op master staat:
git switch masterVoeg de branch samen:
git merge highscore-featureGit toont iets als Updating a1b2c3d..e4f5g6h en Fast-forward. Je highscore-feature-commits zijn nu onderdeel van master. Controleer:
ls
git log --onelinehighscore.txt en highscore_manager.py staan nu op master. Alle commits van de feature-branch zijn opgenomen in de geschiedenis.
Stel: je hebt op master iets veranderd in highscore.txt, bijvoorbeeld “HIGHSCORE: 100” in plaats van “HIGHSCORE: 0”. En tegelijkertijd heb je op een andere branch highscore.txt ook veranderd, naar “HIGHSCORE: 500”.
Als je nu probeert te mergen, weet Git niet welke versie de juiste is. Dat is een merge conflict. Git vraagt jóu om te beslissen.
Laten we het expres uitlokken.
Op master:
echo "HIGHSCORE: 100" > highscore.txt
git add highscore.txt
git commit -m "Update highscore naar 100 op master"Maak een nieuwe branch en verander daar hetzelfde bestand:
git switch -c andere-highscore
echo "HIGHSCORE: 500" > highscore.txt
git add highscore.txt
git commit -m "Update highscore naar 500"Switch terug naar master en probeer te mergen:
git switch master
git merge andere-highscoreGit zegt: CONFLICT (content): Merge conflict in highscore.txt. Open highscore.txt in je editor. Je ziet:
<<<<<<< HEAD
HIGHSCORE: 100
=======
HIGHSCORE: 500
>>>>>>> andere-highscoreDit zijn de twee versies. HEAD is jouw master-versie. Daaronder staat de versie van andere-highscore. Jij kiest welke je houdt, of je combineert ze.
Verwijder de markers en kies één versie:
HIGHSCORE: 500Sla het bestand op. Vertel Git dat het conflict is opgelost:
git add highscore.txt
git commit -m "Merge: highscore van andere-highscore gekozen"Conflict opgelost. Git kan weer verder.
Je feature is gemerged. De branch heb je niet meer nodig:
git branch -d highscore-feature
git branch -d andere-highscore-d staat voor “delete”. Git weigert een branch te verwijderen die nog niet gemerged is: dat is een veiligheidsklep. Als je écht weg wil gooien zonder mergen, gebruik je -D (hoofdletter). Maar wees daar voorzichtig mee.
| Wél een branch | Géén branch |
|---|---|
| Nieuwe feature die tijd kost | Typo in een comment fixen |
| Experiment waarvan je niet weet of het werkt | Kleine bugfix van één regel |
| Iets dat je werkende code kan breken | Je werkt alleen en je wijziging is duidelijk |
| Je werkt samen met anderen | (bij solo-werk is master vaak genoeg) |
Vuistregel: Als je twijfelt, maak een branch. Een branch kost niks. Code kwijtraken wel.
master verandert, en hoe groter de kans op conflicts.master. Kleine, frequente merges zijn makkelijker dan één groot monster-merge.highscore-feature is goed. test123 of branch2 zijn slecht. Over een week weet je niet meer wat er in test123 zat.git branch of git status vertelt je op welke branch je staat. Maak hier een gewoonte van, zodat je voorkomt dat je per ongeluk op master code schrijft die eigenlijk op een feature-branch hoort.Laat aan een coach en een buddy zien:
git branch met minstens twee branches (waaronder master).master.“Tot nu toe leeft al je code alleen op jouw laptop. Volgende keer zetten we hem online. Je maakt een GitHub-account, pusht je repository naar het internet, en je game is overal ter wereld te bekijken. En: je kunt samenwerken met anderen. GitHub: je code de wereld in.”
master. Check na elke merge of alles nog werkt.master, maak daar óók een wijziging in hetzelfde bestand, en merge de branch. Los het conflict zorgvuldig op en check met git log --graph hoe de geschiedenis eruitziet.Tot nu toe leeft al je code op jouw laptop. Handig voor jou, maar niemand anders kan erbij. En als je laptop crasht, ben je alles kwijt.
GitHub is een website waar je Git-repositories online zet. Het is een back-up, een portfolio, en een samenwerkingsplatform in één. Vandaag zet je jouw code op GitHub. Aan het einde van deze sessie kan iedereen met een internetverbinding jouw projecten bekijken, en jij die van hen.
GitHub is niet hetzelfde als Git. Git is het versiebeheersysteem dat op jouw computer draait. GitHub is een website (github.com) die Git-repositories host: een soort Google Drive voor code, maar dan met Git eronder.
Wat GitHub toevoegt aan Git:
GitHub is niet de enige optie; er zijn alternatieven zoals GitLab en Bitbucket. Maar GitHub is de grootste, met meer dan 100 miljoen gebruikers. In deze sessies gebruiken we GitHub.
git config hebt ingesteld: dat scheelt gedoe.Tip voor coaches: check of de ninjas toegang hebben tot hun e-mail tijdens de sessie. Sommige laptops staan niet ingelogd op webmail. Zorg voor een plan B: als e-mailverificatie niet lukt, kunnen ninjas GitHub later thuis verifiëren. De rest van de sessie werkt ook zonder verificatie.
Je hebt een lokaal project op je computer (van sessie 11). Die ga je nu online zetten.
Op GitHub, klik rechtsboven op het + icoontje → New repository.
Vul in:
| Veld | Wat je invult |
|---|---|
| Repository name | mijn-eerste-git-project (zelfde als je lokale map) |
| Description | “Mijn eerste Git-project (CoderDojo sessie 11)” |
| Public / Private | Kies Public: anderen mogen je code zien |
| Initialize with README | NIET aanvinken: je hebt al een lokaal project |
Klik Create repository.
GitHub toont nu instructies. Kies het blok onder "…or push an existing repository from the command line". Kopieer die drie commando’s: die heb je zo nodig.
In je terminal (in je projectmap):
git remote add origin https://github.com/JOUW_USERNAME/mijn-eerste-git-project.gitWat gebeurt hier? remote is een externe locatie waar jouw repo ook staat. origin is de naam die je die locatie geeft. “origin” is de standaardnaam voor je belangrijkste remote. Je kunt meerdere remotes hebben (bijvoorbeeld origin voor GitHub, backup voor GitLab), maar één is meestal genoeg.
Controleer of het gelukt is:
git remote -vJe ziet:
origin https://github.com/JOUW_USERNAME/mijn-eerste-git-project.git (fetch)
origin https://github.com/JOUW_USERNAME/mijn-eerste-git-project.git (push)fetch = hier haal je code vandaan. push = hier stuur je code naartoe. Meestal zijn die hetzelfde.
git pushNu komt het moment: je lokale commits naar GitHub sturen.
git push -u origin masterpush = stuur mijn commits naar de remote. -u origin master = “onthoud dat master op mijn computer hoort bij master op origin.” De volgende keer kun je gewoon git push typen, want Git onthoudt de koppeling.
GitHub vraagt om in te loggen. Dat kan op twee manieren:
repo aan, kopieer de token, en plak hem als wachtwoord in de terminal.Voor ninjas: methode 1 (browser) is het makkelijkst. Als dat niet werkt, help dan met een token.
Na een succesvolle push, ververs je GitHub-pagina. Je bestanden staan er! Je hallo.py, je commit-geschiedenis: alles.
Maak een wijziging lokaal:
echo 'print("GitHub is cool!")' >> hallo.py
git add hallo.py
git commit -m "Add GitHub enthusiasm"Push naar GitHub:
git pushJe hoeft nu geen -u origin master meer, want Git weet de weg. Ververs GitHub: je nieuwe commit staat erbij.
Dit is de omgekeerde route: je begint op GitHub en haalt het naar je computer.
Op GitHub: New repository. Noem hem python-spelletje. Vink dit keer wél Add a README file aan; GitHub maakt dan een repo met één bestand erin. Klik Create repository.
Nu haal je deze repo naar je computer. Dit heet clonen:
cd ~ # ga naar je home-map
git clone https://github.com/JOUW_USERNAME/python-spelletje.gitGitHub maakt een map python-spelletje aan met de README erin. En het is meteen een volwaardige Git-repository: de .git-map zit er al in. Je hoeft geen git init te doen.
cd python-spelletje
git log --oneline # je ziet de eerste commit die GitHub voor je maakteNu kun je hier lokaal verder werken en je commits pushen naar GitHub, precies zoals in Stap 3 tot 4.
Stel: je hebt thuis aan python-spelletje gewerkt en gepusht. Nu ben je op de dojo-laptop en wil je verder. Je hebt de nieuwste versie nog niet.
git pullgit pull haalt de nieuwste commits van GitHub naar jouw computer. Het is twee acties in één: git fetch (ophalen) + git merge (samenvoegen met jouw lokale code).
Altijd git pull doen voor je begint met werken, anders loop je achter en krijg je merge conflicts.
Samenvatting van de workflow:
| Commando | Wat het doet |
|---|---|
git pull | Haal nieuwste versie op van GitHub |
Werk aan je code, maak commits (git add, git commit) | |
git push | Stuur jouw commits naar GitHub |
Onthoud: pull voor je begint, push als je klaar bent.
Laat aan een coach en een buddy zien:
git push die net op GitHub is aangekomen.“Nu staat je code online. Maar wat zet je in een commit message? Hoe schrijf je een bericht dat over drie maanden nog steeds duidelijk is? En hoe werk je met een team zonder de boel te breken? Volgende keer: de professionele kant van Git: best practices die elke developer gebruikt.”
git pull.Je kunt Git-commando’s typen. Je code staat op GitHub. Maar er is een verschil tussen “Git gebruiken” en “Git goed gebruiken.”
Deze sessie gaat over de gewoontes die ervaren developers elke dag toepassen. Geen nieuwe commando’s, wel scherpere regels. Aan het einde schrijf je commit messages waar je over een jaar nog iets aan hebt, en werk je met een branching-strategie die je project overzichtelijk houdt.
git stash is en wanneer je het gebruiktEen slechte commit message ziet er zo uit:
git commit -m "fix"
git commit -m "update"
git commit -m "dingen veranderd"Over drie maanden kijk je terug. Wat was “fix”? Welke “dingen”? Je weet het niet meer. Je moet door de code spitten om te achterhalen wat er gebeurd is. Dat is tijdverspilling.
Een professionele commit message heeft drie onderdelen:
1. Een korte samenvatting (max 72 karakters)
Schrijf in het Engels. Begin met een werkwoord in de tegenwoordige tijd. Dit heet “imperative mood”: alsof je een bevel geeft aan de codebase. Denk: “Add”, “Fix”, “Remove”, “Update”, “Refactor”.
Add highscore tracking
Fix star spawning off-screen
Remove unused collision code2. Een lege regel
3. Een langere uitleg (optioneel, als het nodig is)
Add highscore tracking
Slaat de hoogste score op in highscore.txt. De score wordt
bijgewerkt na elke game-over. Het bestand wordt aangemaakt als
het nog niet bestaat.
Dit vervangt de oude methode waarbij de score alleen in het
geheugen stond en verloren ging bij afsluiten.De uitgebreide uitleg vertelt waarom je iets veranderd hebt, niet alleen wát. De code zelf laat het “wat” al zien. Het “waarom” is wat je over drie maanden nodig hebt.
| Doe dit | Niet dit |
|---|---|
| “Add player health bar” | “added health bar thing” |
| “Fix collision detection on left wall” | “fix” |
| “Remove debug print statements” | “cleanup” |
| Max 72 karakters voor de titel | Een heel verhaal in de titel |
| Tegenwoordige tijd, Engels | Verleden tijd (“added”, “fixed”) |
Waarom Engels? Omdat bijna alle open source-projecten Engels gebruiken. Code is internationaal. Ook je Python-code schrijf je in het Engels (def calculate_score). Je commit messages volgen diezelfde taal.
Waarom tegenwoordige tijd? Een commit beschrijft wat deze wijziging dóet, niet wat jij gedaan hébt. “Add feature” (deze commit voegt een feature toe), niet “Added feature” (ik heb ooit een feature toegevoegd). Git zelf gebruikt ook tegenwoordige tijd: Merge branch 'feature', niet Merged.
Je kunt een commit message over meerdere regels schrijven door de aanhalingstekens niet te sluiten:
git commit -m "Add highscore tracking
Slaat de hoogste score op in highscore.txt. Het bestand wordt
automatisch aangemaakt bij de eerste game-over."Let op: je typt het sluitende aanhalingsteken pas op de laatste regel. Alles ertussen is onderdeel van je message.
Commit vaak. Commit klein.
Niet: drie uur werken, één enorme commit met 47 gewijzigde bestanden. Wel: elke 15 tot 30 minuten een commit, telkens als één logisch stukje af is.
Een vuistregel: als je commit message “en” bevat, is je commit te groot. “Add highscore tracking en fix menu bug en update sprites” → dit moeten drie aparte commits zijn.
Kleine commits maken het makkelijker om:
Je weet al hóe je branches maakt (sessie 12). Nu: wannéér en waaróm.
master is altijd werkendDe master-branch is je etalage. Iemand die je repo cloned, moet je code kunnen runnen zonder foutmeldingen. master bevat nooit half-af werk.
Niet oké op master: code met # TODO: dit moet nog af, uitgecommentarieerde functies, experimenten die je “later nog fixet.”
Wel oké op master: werkende code. Punt.
Een branch doet precies één ding. Niet meer.
feature/player-health-barfeature/health-bar-and-menu-and-sound-effectsAls je tijdens het werken aan een feature denkt: “Oh, ik kan ook even die menu-bug fixen”: stop. Maak een nieuwe branch voor de bugfix. Merge die eerst. Ga dan verder met je feature.
Een branch die langer dan een paar dagen bestaat, wordt een probleem. master verandert intussen, en jouw branch raakt achterop. Hoe langer je wacht met mergen, hoe groter de kans op merge conflicts.
Merge je branch zodra de feature klaar is. Voor kleine dingen (een bugfix van 10 minuten): misschien heb je niet eens een aparte branch nodig.
Geef branches namen die je over een week nog begrijpt:
feature/highscore-tracking
bugfix/star-spawn-offscreen
experiment/particle-effectsDe prefix (feature/, bugfix/, experiment/) vertelt meteen wat voor soort werk er in deze branch zit. Dit is een conventie, geen technische vereiste, maar het helpt.
git stash: werk opzij zettenStel: je bent bezig op een feature-branch. Je code is half af. Je wil even switchen naar master voor een snelle bugfix, maar je wil je half-affe werk niet committen. Daar is git stash voor:
git stashGit bewaart al je wijzigingen tijdelijk en zet je working directory terug naar de laatste commit. Je kunt nu switchen, de bugfix doen, committen, en terugkomen:
git switch master
# ... bugfix doen, committen ...
git switch feature-branch
git stash popgit stash pop haalt je opgeslagen wijzigingen terug. Alles staat weer zoals je het achterliet: half af, maar veilig bewaard.
git pull --rebase: een schonere geschiedenisNormaal doet git pull een merge. Dat maakt een extra merge-commit aan. Soms wil je dat niet; je wil een rechte lijn van commits zonder vertakkingen.
git pull --rebaseDit haalt de nieuwste commits op en zet jouw lokale commits erbovenop, alsof je ze ná de remote-commits gemaakt hebt. Het resultaat is een lineaire geschiedenis: geen merge-commits die alleen maar “Merge branch ‘master’” zeggen.
Let op: gebruik --rebase alleen op branches die jij alleen gebruikt. Bij gedeelde branches is gewoon git pull (merge) veiliger.
Voordat je git push doet:
git pullAltijd. Ook al denk je dat niemand anders gepusht heeft. Het kost één seconde en voorkomt dat GitHub je push weigert met “Updates were rejected because the remote contains work that you do not have locally.”
Deze regel geldt vooral als je samenwerkt. Als jij de enige bent die aan een repo werkt, is het risico kleiner, maar de gewoonte is goud waard.
.gitignore die je altijd moet hebbenElk project heeft bestanden die niet in Git horen. Je .gitignore is je eerste verdedigingslinie tegen per ongeluk wachtwoorden committen.
Minimale .gitignore voor een Python-project:
# Python
__pycache__/
*.pyc
*.pyo
# Virtual environment
venv/
.venv/
# Environment variables (bevat vaak wachtwoorden/keys)
.env
# Jouw editor
.vscode/
.idea/
*.swp
*.swo
# OS-bestanden
.DS_Store
Thumbs.dbWaarom __pycache__/ negeren? Dit zijn gecompileerde Python-bestanden die je programma automatisch aanmaakt. Ze zijn verschillend per Python-versie en per computer. Ze in Git stoppen geeft alleen maar ruis.
Waarom .env negeren? .env-bestanden bevatten vaak geheime sleutels, API-keys, database-wachtwoorden. Die mogen nooit, maar dan ook nooit in Git.
Laat aan een coach en een buddy zien:
.gitignore-bestand.“Nu werk je professioneel met Git. Maar er is nog één concept dat élk team gebruikt: de pull request. Je code is klaar, maar voor hij in master komt, moet iemand anders hem goedkeuren. Hoe werkt dat? Volgende keer: pull requests, de review-muur waar élke wijziging doorheen moet.”
feature/-prefix, werk erin, merge hem terug, en verwijder hem. Doe hetzelfde voor een bugfix/-branch.git stash om half werk op te slaan, switch naar master, maak een snelle fix, push, en kom terug naar je feature met git stash pop.git pull faalt (clone je repo in twee mappen, maak in beide een andere commit, push de eerste, en probeer de tweede te pushen). Los het op: git pull, merge conflict fixen, en dan pas pushen.Je hebt een feature gebouwd op een branch. Goeie commit messages, netjes gewerkt. Nu wil je je code in master zetten.
Je zou git merge kunnen doen en klaar. Maar in een team werkt dat niet. Iemand anders moet je code eerst bekijken: checken op fouten, op stijl, op dingen die je gemist hebt. Dát is een pull request.
Een pull request (PR) is een verzoek: “Haal mijn wijzigingen binnen.” Je opent hem op GitHub. Je teamgenoten bekijken je code, geven feedback. Jij past dingen aan. Pas als iedereen tevreden is, gaat de code naar master.
In deze sessie maak je je eerste pull request. Je reviewt die van een buddy. En je ervaart hoe écht teamwerk met Git voelt.
Vandaag werk je samen met een buddy. Spreek af wie de auteur is (die de feature bouwt) en wie de reviewer is (die de PR bekijkt). Halverwege wissel je om.
De auteur heeft een GitHub-repo nodig waar de reviewer toegang toe heeft. De makkelijkste manier:
Nu kunnen jullie allebei pushen naar dezelfde repo.
Alternatief (zonder collaborator-toegang): de reviewer forkt de repo van de auteur en opent een PR vanaf de fork naar het origineel. Maar vandaag houden we het simpel: directe collaborator-toegang.
De auteur cloned de repo (als dat nog niet gebeurd is) en maakt een feature-branch:
git clone https://github.com/AUTEUR_USERNAME/ons-samenwerk-project.git
cd ons-samenwerk-project
git switch -c feature/groet-functieMaak een nieuw bestand:
echo 'def groet(naam):' > groet.py
echo ' return f"Hallo {naam}!"' >> groet.pyCommit en push:
git add groet.py
git commit -m "Add groet functie
Retourneert een begroeting voor de opgegeven naam."
git push -u origin feature/groet-functiebase: master ← compare: feature/groet-functie.)## Wat
Een functie `groet(naam)` die een begroeting retourneert.
## Waarom
We hebben een herbruikbare begroeting nodig voor de
gebruikersinterface. Dit voorkomt dat we op meerdere plekken
dezelfde string moeten schrijven.
## Hoe testen
```python
from groet import groet
print(groet("CoderDojo")) # "Hallo CoderDojo!"5. Klik **Create pull request**.
Je PR staat nu open. Iedereen met toegang tot de repo kan hem zien. GitHub toont de diff: exact welke regels je hebt toegevoegd (groen) en verwijderd (rood).
## Stap 3: Een PR reviewen (reviewer)
De reviewer opent de PR op GitHub. Dit zijn de stappen van een review:
### 1. Lees de beschrijving
Begrijp je wat deze PR doet? Zo niet, vraag om verduidelijking.
### 2. Bekijk de diff
Klik op het **Files changed**-tabblad. GitHub toont elke gewijzigde regel. Kijk naar:
- **Werkt de code?** Zou je het zelf runnen als je het cloned?
- **Is de stijl consistent?** Dezelfde naamgevingsconventies als de rest van het project?
- **Zijn er fouten?** Typo's, ontbrekende imports, logische fouten?
- **Staan er geen geheimen in?** Wachtwoorden, API-keys, tokens?
- **Is het te begrijpen?** Kan iemand die deze code voor het eerst ziet, volgen wat er gebeurt?
### 3. Geef feedback
Klik op een regel om een comment toe te voegen. Wees specifiek:
**Goeie feedback:**
> In `groet.py` regel 2: wat gebeurt er als `naam` leeg is? Misschien een default-waarde toevoegen?
**Slechte feedback:**
> Dit is niet goed.
### 4. Dien je review in
Klik op **Review changes**. Je hebt drie opties:
- **Comment**: gewoon feedback, geen beslissing.
- **Approve**: de code is goed, mag gemerged worden.
- **Request changes**: er moet iets aangepast worden voor de PR gemerged kan worden.
Bij je eerste review: kies **Approve** als alles er goed uitziet, of **Request changes** als je iets wilt laten aanpassen.
## Stap 4: Feedback verwerken (auteur)
De reviewer heeft een comment achtergelaten. De auteur past de code aan:
```bash
# Zorg dat je op je feature-branch zit
git switch feature/groet-functiePas groet.py aan op basis van de feedback. Bijvoorbeeld:
def groet(naam="wereld"):
return f"Hallo {naam}!"Commit en push:
git add groet.py
git commit -m "Add default parameter to groet functie"
git pushDe nieuwe commit verschijnt automatisch in de PR. De reviewer ziet de update en kan opnieuw kijken.
Als de reviewer Approved heeft, is het tijd om te mergen.
Op GitHub, in de PR, klik je op Merge pull request. Kies Create a merge commit (de standaardoptie). Klik Confirm merge.
De feature-branch is nu samengevoegd met master. Op GitHub kun je de branch verwijderen met de Delete branch-knop die verschijnt na het mergen.
Lokaal moet je ook opruimen:
git switch master
git pull # haal de merge op die net op GitHub gebeurd is
git branch -d feature/groet-functie # verwijder de lokale branchJe master is nu up-to-date. Je feature-branch is weg, lokaal én op GitHub. Klaar voor het volgende stuk werk.
1. git switch -c feature/iets ← Maak een feature-branch
2. Werk, commit, werk, commit
3. git push -u origin feature/iets ← Push naar GitHub
4. Open een PR op GitHub ← Vraag om review
5. Reviewer bekijkt, geeft feedback
6. Pas code aan, commit, push ← Feedback verwerken
7. Reviewer approved
8. Merge de PR op GitHub ← Code naar master
9. git switch master && git pull ← Haal master lokaal bij
10. git branch -d feature/iets ← Ruim de branch opEen review is niet: “Ziet er goed uit.” Een goeie review is specifiek, constructief en respectvol.
Vragen die je jezelf stelt tijdens een review:
Hoe geef je feedback:
Begin met wat goed is. Wees dan specifiek over wat beter kan. Eindig met een duidelijke conclusie.
Voorbeeld:
De functie werkt precies zoals beschreven. Twee suggesties:
- In regel 2: een default-waarde voor
naamzou handig zijn.- Overweeg een docstring toe te voegen die uitlegt wat de functie retourneert.
Verder ziet het er goed uit. Als je deze twee dingen aanpast, approve ik hem graag.
Wissel van rol met je buddy en doe de hele workflow nog een keer: nu ben jij de reviewer.
Laat aan een coach zien:
master.Dit was de laatste Git-sessie. Wat je nu kunt:
init, add, commit, log, diff)master kapot te maken (branch, switch, merge)push, pull, clone)Dit is niet “extra”. Dit is hoe developers élke dag werken. Of je nu games maakt, websites bouwt, of AI traint: Git en GitHub zijn de gereedschappen die je project beheersbaar houden. Gebruik ze.
good first issue. Fork de repo, maak een fix, en open een PR.Je kent HTML misschien van het internet: <h1>, <p>, <a>. Maar voor notities en documentatie is HTML veel te veel typwerk. Daar is Markdown voor.
Markdown is een mini-taal die je in gewone tekst schrijft. Het ziet er leesbaar uit zónder dat je het eerst moet omzetten. En met één druk op de knop wordt het nette HTML: koppen, lijsten, links, tabellen.
In deze sessie leer je de hele basis van Markdown. Aan het einde schrijf je notities die er professioneel uitzien, op GitHub, in Obsidian, of in elk ander programma dat Markdown begrijpt.
Markdown is overal:
README.md in Markdown. Issues, pull requests, wiki’s: allemaal Markdown..md-bestanden opslaan.Het grote voordeel: je schrijft gewone tekst. Geen ingewikkelde tags. En het resultaat is altijd leesbaar, ook als platte tekst.
Markdown-bestanden eindigen op .md. Maak er één:
mkdir mijn-notities
cd mijn-notities
echo "# Mijn Eerste Notitie" > test.mdJe kunt .md-bestanden openen in elke teksteditor: Kladblok, VS Code, Thonny, Obsidian. VS Code heeft een ingebouwde preview: klik rechtsboven op het icoontje met het vergrootglas en het boek.
Koppen maak je met #. Hoe meer #, hoe kleiner de kop:
# Dit is een titel (h1)
## Dit is een subtitel (h2)
### Dit is een kleinere kop (h3)
#### Nog kleiner (h4)Een alinea maak je door gewoon tekst te typen. Een lege regel ertussen start een nieuwe alinea:
Dit is de eerste alinea. Die loopt gewoon door.
Dit is de tweede alinea. Omdat er een lege regel tussen zit.Tip: één # gebruik je maar één keer per document: voor de titel. De rest begint bij ##.
**Dit is vetgedrukt**
*Dit is cursief*
~~Dit is doorstreept~~
Je kunt ook **vet en *cursief* combineren** in dezelfde zin.Het resultaat:
**vet** wordt vet*cursief* wordt cursief~~doorstreept~~ wordt Let op: geen spaties tussen de sterretjes en de tekst. ** vet ** werkt niet. **vet** wel.
Sommige editors accepteren ook underscores: __vet__ en _cursief_. Maar sterretjes zijn de standaard: gebruik die.
Een horizontale lijn maak je met drie (of meer) streepjes:
---Of met sterretjes:
***Het resultaat is een lijn over de hele breedte. Gebruik het spaarzaam: één of twee per document is genoeg. Te veel lijnen maken je notities onoverzichtelijk.
Gebruik -, * of +:
- Python
- Git
- Markdown
- GitHubJe kunt lijsten nesten door in te springen (2 of 4 spaties):
- Programmeertalen
- Python
- JavaScript
- Versiebeheer
- Git
- GitHub1. Open Thonny
2. Schrijf je code
3. Klik op RunHet maakt niet uit welke nummers je typt: Markdown nummert automatisch door. Dit:
1. Stap één
1. Stap twee
1. Stap drie…geeft exact hetzelfde resultaat als 1, 2, 3. Handig als je later een stap wilt toevoegen zonder alles te hernummeren.
- [x] Git installeren
- [x] Eerste commit maken
- [ ] Branches leren
- [ ] Pull request openen[x] is afgevinkt, [ ] is open. Werkt in GitHub issues, pull requests, en veel notitie-apps.
[klik hier voor de CoderDojo-site](https://python.coderdojohasselt.be)Het woord tussen [ ] is de klikbare tekst. De URL tussen ( ) is de bestemming.
[Bekijk sessie 11](11-git-intro/)Dit linkt naar het bestand 11-git-intro/_index.md in dezelfde map.
<https://github.com>Dit toont de URL als klikbare link, zonder aparte tekst.
Een afbeelding is bijna hetzelfde als een link, maar met een ! ervoor:
De tekst tussen [ ] is de alt-tekst: die verschijnt als de afbeelding niet laadt, of wordt voorgelezen door screenreaders.
Afbeeldingen en Git: Kleine afbeeldingen (SVG, kleine PNG’s) kun je in Git zetten. Grote afbeeldingen (>1 MB) en video’s beter niet, want die maken je repo traag.
| Commando | Wat het doet |
|----------|-------------|
| `git init` | Nieuwe repository maken |
| `git add` | Bestanden klaarzetten voor commit |
| `git commit` | Wijzigingen vastleggen |
| `git push` | Commits naar GitHub sturen |De | tekens vormen de kolommen. De --- regel scheidt de kop van de data. De : in de scheidingsregel bepaalt uitlijning:
| Links uitgelijnd | Gecentreerd | Rechts uitgelijnd |
|:-----------------|:-----------:|------------------:|
| links | midden | rechts |Gebruik backticks voor korte stukjes code in een zin:
Gebruik `git status` om te zien wat er gewijzigd is.Voor meerdere regels code gebruik je drie backticks:
```python
def groet(naam):
return f"Hallo {naam}!"
```De taal (python) achter de eerste backticks geeft syntax highlighting. Dit werkt voor tientallen talen: bash, html, css, javascript, json, yaml, markdown.
```
Dit is gewoon tekst
zonder syntax highlighting
```Gebruik > voor citaten of belangrijke opmerkingen:
> Git is geen back-up. Git is een tijdmachine.
> Iemand op het internetMeerdere > regels achter elkaar vormen één blok. Een lege > regel start een nieuwe alinea binnen het citaat.
Een goed README.md combineert alles wat je nu kent. Hier is een voorbeeld:
# Mijn Project
Een korte beschrijving van wat dit project doet.
## Installatie
```bash
git clone https://github.com/jouw-naam/mijn-project.git
cd mijn-project
```
## Gebruik
1. Open `main.py` in Thonny.
2. Klik op **Run**.
3. Kies een level en start.
## Wat je leert
- [x] Pygame Zero basis
- [x] Collision detection
- [ ] Highscore systeem
- [ ] Geluidseffecten
## Links
- [CoderDojo Hasselt](https://coderdojohasselt.be)
- [Broncode op GitHub](https://github.com/jouw-naam/mijn-project)| Wat | Markdown |
|---|---|
| Kop niveau 1 | # Titel |
| Kop niveau 2 | ## Subtitel |
| Kop niveau 3 | ### Kleinere kop |
| Vet | **vet** |
| Cursief | *cursief* |
| Doorstreept | ~~doorstreept~~ |
| Horizontale lijn | --- of *** |
| Lijst (ongeordend) | - item |
| Lijst (genummerd) | 1. item |
| Checklist | - [ ] open item |
| Link | [tekst](url) |
| Afbeelding |  |
| Inline code | `code` |
| Codeblok | ```taal |
| Citaat | > citaat |
| Tabel | | kolom | kolom | |
Laat aan een coach en een buddy zien:
Markdown is simpel, maar het is overal. Je README’s op GitHub, je notities in Obsidian, je documentatie: alles wordt leesbaarder met Markdown. Gebruik het. Overdrijf niet met opmaak. Goeie notities zijn helder, niet druk.
README.md voor je favoriete Python-project. Gebruik koppen, een lijst en een codeblok.