Flappy Bird in JavaScript
- Flappy Bird in JavaScript
- Plunker
- De achtergrond instellen
- De vogel op het scherm tekenen
- De vogel laten vallen
- De vogel laten vliegen
- Animatie en geluid toevoegen
- Buizen laten verschijnen
- Botsingen
- Binnen het scherm blijven
- Score toevoegen
- Flappy Bird in JavaScript
- Plunker
- De achtergrond instellen
- De vogel op het scherm tekenen
- De vogel laten vallen
- De vogel laten vliegen
- Animatie en geluid toevoegen
- Buizen laten verschijnen
- Botsingen
- Binnen het scherm blijven
- Score toevoegen
Flappy Bird in JavaScript
We gaan het spelletje Flappy Bird programmeren in JavaScript.
In Flappy Bird moet je het vogeltje tussen de buizen door laten vliegen, zonder er tegenaan te botsen.
Dat klinkt eenvoudig, maar is lastiger dan je denkt!
Plunker
We gaan werken in Plunker. Dit is een online editor waarin we onze JavaScript code gaan schrijven.
Als het goed is zie je nu dit scherm:
We gaan onze code schrijven in het bestand flappybird.js
, open het bestand meer eens door er op te klikken
Je ziet nu deze code in het code venster:
var state = {
preload: function () {
// Hier laad je alle plaatjes en geluiden in het geheugen van de computer
},
create: function () {
// Hier zet je code neer die 1 keer uitgevoerd moet worden, wanneer je spel
// opstart
},
update: function () {
// Hier zet je code neer die steeds opnieuw uitgevoerd wordt. Je kunt
// bijvoorbeeld controleren of 2 dingen met elkaar botsen.
}
}
var game = new Phaser.Game(640, 480, Phaser.CANVAS);
game.state.add('main', state);
game.state.start('main');
Je ziet hierboven computer code staan, maar ook ‘gewone’ Nederlandse zinnen.
We noemen dit commentaar en gebruiken het om uit te leggen wat de code doet.
Je kunt zelf ook commentaar toevoegen door een regel te beginnen met //
.
De achtergrond instellen
🚨 BELANGRIJK! 🚨
Druk voor je verder gaat op de Fork knop (links boven in het scherm).
Dit zorgt er voor dat er een kopie gemaakt wordt van de code, waarin jouw wijzigingen bewaard blijven.
Er gebeurt nog niet zo veel in ons spel, je ziet alleen maar een zwart vlak.
We gaan eerst maar eens een mooie achtergrond instellen.
Dat doen we door het plaatje achtergrond.png
in het geheugen van de computer te laden.
Voeg deze regel toe aan de preload
functie, op regel 4
.
game.load.image('achtergrond', 'achtergrond.png');
De preload
functie ziet er als het goed is nu zo uit:
var state = {
preload: function () {
// Hier laad je alle plaatjes en geluiden in het geheugen van de computer
game.load.image('achtergrond', 'achtergrond.png');
},
...
}
Voeg in de create
functie het achtergrondplaatje als sprite toe. Maak de sprite net zo groot als het scherm van ons spel:
this.background = game.add.sprite(0, 0, 'achtergrond');
this.background.width = game.width;
this.background.height = game.height;
Als het goed is zie je nu de achtergrond verschijnen.
Een sprite is een plaatje dat in een game gebruikt wordt.
Controlepunt
Als het goed is ziet je code er nu zo uit:
var state = {
preload: function () {
// Hier laad je alle plaatjes en geluiden in het geheugen van de computer
game.load.image('achtergrond', 'achtergrond.png');
},
create: function () {
// Hier zet je code neer die 1 keer uitgevoerd moet worden, wanneer je spel
// opstart
this.background = game.add.sprite(0, 0, 'achtergrond');
this.background.width = game.width;
this.background.height = game.height;
},
update: function () {
// Hier zet je code neer die steeds opnieuw uitgevoerd wordt. Je kunt
// bijvoorbeeld controleren of 2 dingen met elkaar botsen.
}
}
var game = new Phaser.Game(640, 480, Phaser.CANVAS);
game.state.add('main', state);
game.state.start('main');
De vogel op het scherm tekenen
Alleen naar een achtergrond kijken is ook maar saai. Laten we Flappy zelf eens in het spel zetten.
Laad in de preload
functie het plaatje van Flappy Bird in het geheugen van de computer.
game.load.spritesheet('vogel', 'vogel.png', 68, 48, 3);
En zet nu de Flappy sprite in het spel in de create
functie:
this.flappy = game.add.sprite(100, 245, 'vogel');
Als het goed is ie je Flappy nu in het spel verschijnen!
Een
spritesheet
is een afbeelding waarin meerdere uiterlijken van een sprite staan. Open het bestandvogel.png
maar eens. Je ziet drie vogeltjes die allemaal net ietsje anders zijn. Elke vogel is68
pixels hoog en48
pixels breed. We gaan dit straks nodig hebben om de vogel te laten vliegen.
Controlepunt
Als het goed is ziet je code er nu zo uit:
var state = {
preload: function () {
// Hier laad je alle plaatjes en geluiden in het geheugen van de computer
game.load.image('achtergrond', 'achtergrond.png');
game.load.spritesheet('vogel', 'vogel.png', 68, 48, 3);
},
create: function () {
// Hier zet je code neer die 1 keer uitgevoerd moet worden, wanneer je spel
// opstart
this.background = game.add.sprite(0, 0, 'achtergrond');
this.background.width = game.width;
this.background.height = game.height;
this.flappy = game.add.sprite(100, 245, 'vogel');
},
update: function () {
// Hier zet je code neer die steeds opnieuw uitgevoerd wordt. Je kunt
// bijvoorbeeld controleren of 2 dingen met elkaar botsen.
}
}
var game = new Phaser.Game(640, 480, Phaser.CANVAS);
game.state.add('main', state);
game.state.start('main');
De vogel laten vallen
Er gebeurt nog weinig in ons spel. We gaan straks Flappy leren vliegen, maar eerst gaan we haar laten vallen.
We doen dit door physics aan ons spel toe te voegen.
Voeg deze regel toe in de create
functie :
game.physics.startSystem(Phaser.Physics.ARCADE);
We gaan nu met deze physics de zwaartekracht instellen op Flappy.
Hiervoor voeg je nog 2 regels code aan je programma toe in de create
functie:
game.physics.arcade.enable(this.flappy);
this.flappy.body.gravity.y = 1000;
En meteen valt Flappy van het scherm! 😱
Controlepunt
Als het goed is ziet je code er nu zo uit:
var state = {
preload: function () {
// Hier laad je alle plaatjes en geluiden in het geheugen van de computer
game.load.image('achtergrond', 'achtergrond.png');
game.load.spritesheet('vogel', 'vogel.png', 68, 48, 3);
},
create: function () {
// Hier zet je code neer die 1 keer uitgevoerd moet worden, wanneer je spel
// opstart
this.background = game.add.sprite(0, 0, 'achtergrond');
this.background.width = game.width;
this.background.height = game.height;
this.flappy = game.add.sprite(100, 245, 'vogel');
game.physics.startSystem(Phaser.Physics.ARCADE);
game.physics.arcade.enable(this.flappy);
this.flappy.body.gravity.y = 1000;
},
update: function () {
// Hier zet je code neer die steeds opnieuw uitgevoerd wordt. Je kunt
// bijvoorbeeld controleren of 2 dingen met elkaar botsen.
}
}
var game = new Phaser.Game(640, 480, Phaser.CANVAS);
game.state.add('main', state);
game.state.start('main');
De vogel laten vliegen
Als je het spel nu start, zal de vogel als een baksteen naar beneden vallen. Laten we er voor zorgen dat ze kan vliegen.
Voeg in de create
functie de volgende regels toe:
var spaceKey = game.input.keyboard.addKey(Phaser.Keyboard.SPACEBAR);
spaceKey.onDown.add(this.flap, this);
Met de regels hierboven zorgen we er voor dat wanneer de spatiebalk
ingedrukt wordt, het spel de functie flap
van ons state
object uitvoert.
Deze funtie bestaat nog niet, dus die moeten we toevoegen aan het state
object. Voeg deze code onder de update
functie toe, na een komma:
flap: function() {
this.flappy.body.velocity.y = -350;
}
Zodat de code van het state
object er zo uitziet:
var state = {
preload: function() {
...
},
create: function() {
...
},
update: function() {
...
}, // <-- Let op dat je deze komma niet vergeet!
flap: function() {
this.flappy.body.velocity.y = -350;
}
}
Doordat we in de flap
functie de vogel een y-snelheid meegeven, vliegt ze eventjes omhoog wanneer je de spatiebalk
indrukt.
Maar door de zwaartekracht die we ingesteld hebben, zal ze snel weer naar beneden vallen 😇
Controlepunt
Als het goed is ziet je code er nu zo uit:
var state = {
preload: function () {
// Hier laad je alle plaatjes en geluiden in het geheugen van de computer
game.load.image('achtergrond', 'achtergrond.png');
game.load.spritesheet('vogel', 'vogel.png', 68, 48, 3);
},
create: function () {
// Hier zet je code neer die 1 keer uitgevoerd moet worden, wanneer je spel
// opstart
this.background = game.add.sprite(0, 0, 'achtergrond');
this.background.width = game.width;
this.background.height = game.height;
this.flappy = game.add.sprite(100, 245, 'vogel');
game.physics.startSystem(Phaser.Physics.ARCADE);
game.physics.arcade.enable(this.flappy);
this.flappy.body.gravity.y = 1000;
var spaceKey = game.input.keyboard.addKey(Phaser.Keyboard.SPACEBAR);
spaceKey.onDown.add(this.flap, this);
},
update: function () {
// Hier zet je code neer die steeds opnieuw uitgevoerd wordt. Je kunt
// bijvoorbeeld controleren of 2 dingen met elkaar botsen.
},
flap: function() {
this.flappy.body.velocity.y = -350;
}
}
var game = new Phaser.Game(640, 480, Phaser.CANVAS);
game.state.add('main', state);
game.state.start('main');
Animatie en geluid toevoegen
Onze vogel kan nu wel vliegen, maar het ziet er een beetje saai uit.
Eens kijken of het ons lukt flappy
met haar vleugels te laten wapperen.
Voeg een animatie toe aan flappy
door deze code in de create
functie te zetten:
this.flappy.animations.add('vlieg');
En start de animatie iedere keer dat de flap
functie uitgevoerd wordt, door deze code aan de flap
functie toe te voegen:
this.flappy.animations.play('vlieg', 10, false);
Deze code speelt de drie plaatjes in de spritesheet van de vogel een-voor-een af.
10
keer per seconde wordt het volgende plaatje getoond, waardoor het lijkt alsof de vleugels van de vogel wapperen.
Laad nu het flap
geluidsbestand in het geheugen van de computer door in de preload
functie deze code toe te voegen:
game.load.audio('flap', 'flap.mp3');
Maak het flap geluid bekend in het spel door deze code in de create
functie te zetten:
this.flapGeluid = game.add.audio('flap');
Speel het geluid af iedere keer wanneer de flap
functie uitgevoerd wordt:
this.flapGeluid.play();
Controlepunt
Als het goed is ziet je code er nu zo uit:
var state = {
preload: function () {
// Hier laad je alle plaatjes en geluiden in het geheugen van de computer
game.load.image('achtergrond', 'achtergrond.png');
game.load.spritesheet('vogel', 'vogel.png', 68, 48, 3);
game.load.audio('flap', 'flap.mp3');
},
create: function () {
// Hier zet je code neer die 1 keer uitgevoerd moet worden, wanneer je spel
// opstart
this.background = game.add.sprite(0, 0, 'achtergrond');
this.background.width = game.width;
this.background.height = game.height;
this.flappy = game.add.sprite(100, 245, 'vogel');
game.physics.startSystem(Phaser.Physics.ARCADE);
game.physics.arcade.enable(this.flappy);
this.flappy.body.gravity.y = 1000;
var spaceKey = game.input.keyboard.addKey(Phaser.Keyboard.SPACEBAR);
spaceKey.onDown.add(this.flap, this);
this.flappy.animations.add('vlieg');
this.flapGeluid = game.add.audio('flap');
},
update: function () {
// Hier zet je code neer die steeds opnieuw uitgevoerd wordt. Je kunt
// bijvoorbeeld controleren of 2 dingen met elkaar botsen.
},
flap: function() {
this.flappy.body.velocity.y = -350;
this.flappy.animations.play('vlieg', 10, false);
this.flapGeluid.play();
}
}
var game = new Phaser.Game(640, 480, Phaser.CANVAS);
game.state.add('main', state);
game.state.start('main');
Buizen laten verschijnen
Nu de vogel kan vliegen, gaan we het wat spannender maken.
We gaan iedere 3 seconden rij met buizen laten verschijnen.
Hiervoor voegen we een timer
toe in de create
functie.
this.timer = game.time.events.loop(3000, this.maakBuizen, this);
Deze timer
zorgt er voor dat iedere 3 secoden (= 3000 milliseconden) de functie maakBuizen
uitgevoerd wordt.
De code voor het aanmaken van de buizen is wat lastiger, dus die krijg je cadeau! We moeten de code alleen nog even actief maken.
Dit doe je door deze regel helemaal onderaan je programma toe te voegen:
laadBuizen(state);
Controlepunt
Als het goed is ziet je code er nu zo uit:
var state = {
preload: function () {
// Hier laad je alle plaatjes en geluiden in het geheugen van de computer
game.load.image('achtergrond', 'achtergrond.png');
game.load.spritesheet('vogel', 'vogel.png', 68, 48, 3);
game.load.audio('flap', 'flap.mp3');
},
create: function () {
// Hier zet je code neer die 1 keer uitgevoerd moet worden, wanneer je spel
// opstart
this.background = game.add.sprite(0, 0, 'achtergrond');
this.background.width = game.width;
this.background.height = game.height;
this.flappy = game.add.sprite(100, 245, 'vogel');
game.physics.startSystem(Phaser.Physics.ARCADE);
game.physics.arcade.enable(this.flappy);
this.flappy.body.gravity.y = 1000;
var spaceKey = game.input.keyboard.addKey(Phaser.Keyboard.SPACEBAR);
spaceKey.onDown.add(this.flap, this);
this.flappy.animations.add('vlieg');
this.flapGeluid = game.add.audio('flap');
this.timer = game.time.events.loop(3000, this.maakBuizen, this);
},
update: function () {
// Hier zet je code neer die steeds opnieuw uitgevoerd wordt. Je kunt
// bijvoorbeeld controleren of 2 dingen met elkaar botsen.
},
flap: function() {
this.flappy.body.velocity.y = -350;
this.flappy.animations.play('vlieg', 10, false);
this.flapGeluid.play();
}
}
var game = new Phaser.Game(640, 480, Phaser.CANVAS);
game.state.add('main', state);
game.state.start('main');
laadBuizen(state);
Botsingen
Dit begint al aardig op Flappy Bird te lijken zeg, goed bezig!
Flappy vliegt nu nog wel dwars door alle buizen heen.
Zo is het wel een heel eenvoudig spelletje, daar gaan we iets aan doen!.
We gaan nu steeds controleren of flappy botst met een buis.
We doen dit in de update
functie, omdat die steeds opnieuw uitgevoerd wordt.
Voeg deze code daarom aan de update
functie toen:
game.physics.arcade.overlap(this.flappy, this.buizen, this.botsing, null, this);
Als flappy
met een van de buizen
botst, wordt de functie botsing
uitgevoerd.
Die functie bestaat nog niet, dus die voegen we toe aan het state
object, net zoals we dat eerder met de flap
functie gedaan hebben:
var state = {
preload: function() {
...
},
create: function() {
...
},
update: function() {
...
},
flap: function() {
...
}, // <-- Let op dat je de komma weer niet vergeet :-)
botsing: function() {
game.state.start('main');
}
}
De code die in de botsing
functie uitgevoerd wordt, zorgt er voor dat het spel opnieuw start.
Dus iedere keer dat flappy
een botsing
heeft met een van de buizen
wordt het spel opnieuw gestart.
Geluid toevoegen
Laten we er nu nog even een echt botsing van maken door een geluidje af te spelen.
Laad het botsing
geluidsbestand in het geheugen van de computer door in de preload
functie deze code toe te voegen:
game.load.audio('botsing', 'botsing.mp3');
Maak het botsing geluid bekend in het spel door deze code in de create
functie te zetten:
this.botsingGeluid = game.add.audio('botsing');
Speel het geluid af iedere keer wanneer de botsing
functie uitgevoerd wordt:
this.botsingGeluid.play();
Controlepunt
Als het goed is ziet je code er nu zo uit:
var state = {
preload: function () {
// Hier laad je alle plaatjes en geluiden in het geheugen van de computer
game.load.image('achtergrond', 'achtergrond.png');
game.load.spritesheet('vogel', 'vogel.png', 68, 48, 3);
game.load.audio('flap', 'flap.mp3');
game.load.audio('botsing', 'botsing.mp3');
},
create: function () {
// Hier zet je code neer die 1 keer uitgevoerd moet worden, wanneer je spel
// opstart
this.background = game.add.sprite(0, 0, 'achtergrond');
this.background.width = game.width;
this.background.height = game.height;
this.flappy = game.add.sprite(100, 245, 'vogel');
game.physics.startSystem(Phaser.Physics.ARCADE);
game.physics.arcade.enable(this.flappy);
this.flappy.body.gravity.y = 1000;
var spaceKey = game.input.keyboard.addKey(Phaser.Keyboard.SPACEBAR);
spaceKey.onDown.add(this.flap, this);
this.flappy.animations.add('vlieg');
this.flapGeluid = game.add.audio('flap');
this.timer = game.time.events.loop(3000, this.maakBuizen, this);
this.botsingGeluid = game.add.audio('botsing');
},
update: function () {
// Hier zet je code neer die steeds opnieuw uitgevoerd wordt. Je kunt
// bijvoorbeeld controleren of 2 dingen met elkaar botsen.
game.physics.arcade.overlap(this.flappy, this.buizen, this.botsing, null, this);
},
flap: function() {
this.flappy.body.velocity.y = -350;
this.flappy.animations.play('vlieg', 10, false);
this.flapGeluid.play();
},
botsing: function() {
game.state.start('main');
this.botsingGeluid.play();
}
}
var game = new Phaser.Game(640, 480, Phaser.CANVAS);
game.state.add('main', state);
game.state.start('main');
laadBuizen(state);
Binnen het scherm blijven
We zijn al een heel eind, het begint al een echt spel te worden!
Laten we nu programmeren dat het ook game over is wanneer flappy
de rand van het scherm raakt.
Als flappy
de rand raakt, zorgen we dat de botsing
functie uitgevoerd wordt. Daardoor zal het spel opnieuw starten.
Voeg deze code toe aan de create
functie:
this.flappy.checkWorldBounds = true;
this.flappy.events.onOutOfBounds.add(this.botsing, this);
Controlepunt
Als het goed is ziet je code er nu zo uit:
var state = {
preload: function () {
// Hier laad je alle plaatjes en geluiden in het geheugen van de computer
game.load.image('achtergrond', 'achtergrond.png');
game.load.spritesheet('vogel', 'vogel.png', 68, 48, 3);
game.load.audio('flap', 'flap.mp3');
game.load.audio('botsing', 'botsing.mp3');
},
create: function () {
// Hier zet je code neer die 1 keer uitgevoerd moet worden, wanneer je spel
// opstart
this.background = game.add.sprite(0, 0, 'achtergrond');
this.background.width = game.width;
this.background.height = game.height;
this.flappy = game.add.sprite(100, 245, 'vogel');
game.physics.startSystem(Phaser.Physics.ARCADE);
game.physics.arcade.enable(this.flappy);
this.flappy.body.gravity.y = 1000;
var spaceKey = game.input.keyboard.addKey(Phaser.Keyboard.SPACEBAR);
spaceKey.onDown.add(this.flap, this);
this.flappy.animations.add('vlieg');
this.flapGeluid = game.add.audio('flap');
this.timer = game.time.events.loop(3000, this.maakBuizen, this);
this.botsingGeluid = game.add.audio('botsing');
this.flappy.checkWorldBounds = true;
this.flappy.events.onOutOfBounds.add(this.botsing, this);
},
update: function () {
// Hier zet je code neer die steeds opnieuw uitgevoerd wordt. Je kunt
// bijvoorbeeld controleren of 2 dingen met elkaar botsen.
game.physics.arcade.overlap(this.flappy, this.buizen, this.botsing, null, this);
},
flap: function() {
this.flappy.body.velocity.y = -350;
this.flappy.animations.play('vlieg', 10, false);
this.flapGeluid.play();
},
botsing: function() {
game.state.start('main');
this.botsingGeluid.play();
}
}
var game = new Phaser.Game(640, 480, Phaser.CANVAS);
game.state.add('main', state);
game.state.start('main');
laadBuizen(state);
Score toevoegen
Nu de laatste stap van deze uitleg: we gaan punten toevoegen!
We laten de speler iedere seconde een punt verdienen.
Dit doen we door in de create
functie een variabele punten
toe te voegen. We maken ook een label aan waarmee we score
op het scherm tekenen:
this.punten = 0;
this.puntenLabel = game.add.text(20, 20, "0", {
font: "30px Arial",
fill: "#ffffff"
});
We gaan een timer toevoegen, waarmee we elke seconde een nieuwe functie score
aanroepen.
Dit is de code om de timer te maken, die moet je in de create
functie toe voegen:
this.timer = game.time.events.loop(1000, this.score, this);
En hier is de score
functie:
score: function() {
this.punten += 1;
this.puntenLabel.text = this.punten;
}
Als je goed alle eerdere stappen doorlopen hebt, weet je waarschijnlijk hoe je deze score
functie toe moet voegen aan het state
object.
Als je er niet uitkomt, kun je in het laatste controlepunt onderaan de pagina kijken.
Gefeliciteerd!
Het is je gelukt helemaal zelf het spelletje Flappy Bird te maken!
Misschien heb je zelf wel ideeën hoe je het spel nóg leuker kan maken?
Om dit spel te maken hebben we Phaser gebruikt.
Op de site van Phaser vind je nog veel meer voorbeelden met code.
Hier kun je dus eens rondneuzen om te kijken hoe anderen spellen gemaakt hebben.
Controlepunt
Als het goed is ziet je code er nu zo uit:
var state = {
preload: function () {
// Hier laad je alle plaatjes en geluiden in het geheugen van de computer
game.load.image('achtergrond', 'achtergrond.png');
game.load.spritesheet('vogel', 'vogel.png', 68, 48, 3);
game.load.audio('flap', 'flap.mp3');
game.load.audio('botsing', 'botsing.mp3');
},
create: function () {
// Hier zet je code neer die 1 keer uitgevoerd moet worden, wanneer je spel
// opstart
this.background = game.add.sprite(0, 0, 'achtergrond');
this.background.width = game.width;
this.background.height = game.height;
this.flappy = game.add.sprite(100, 245, 'vogel');
game.physics.startSystem(Phaser.Physics.ARCADE);
game.physics.arcade.enable(this.flappy);
this.flappy.body.gravity.y = 1000;
var spaceKey = game.input.keyboard.addKey(Phaser.Keyboard.SPACEBAR);
spaceKey.onDown.add(this.flap, this);
this.flappy.animations.add('vlieg');
this.flapGeluid = game.add.audio('flap');
this.timer = game.time.events.loop(3000, this.maakBuizen, this);
this.botsingGeluid = game.add.audio('botsing');
this.flappy.checkWorldBounds = true;
this.flappy.events.onOutOfBounds.add(this.botsing, this);
this.punten = 0;
this.puntenLabel = game.add.text(20, 20, "0", {
font: "30px Arial",
fill: "#ffffff"
});
this.timer = game.time.events.loop(1000, this.score, this);
},
update: function () {
// Hier zet je code neer die steeds opnieuw uitgevoerd wordt. Je kunt
// bijvoorbeeld controleren of 2 dingen met elkaar botsen.
game.physics.arcade.overlap(this.flappy, this.buizen, this.botsing, null, this);
},
flap: function() {
this.flappy.body.velocity.y = -350;
this.flappy.animations.play('vlieg', 10, false);
this.flapGeluid.play();
},
botsing: function() {
game.state.start('main');
this.botsingGeluid.play();
},
score: function() {
this.punten += 1;
this.puntenLabel.text = this.punten;
}
}
var game = new Phaser.Game(640, 480, Phaser.CANVAS);
game.state.add('main', state);
game.state.start('main');
laadBuizen(state);