How to simulate flocking behavior with Boids using HTML5 and Phaser
Talking about Boids game, HTML5, Javascript and Phaser.
Do you like my tutorials?
Then consider supporting me on Ko-fi.
Point
class and Arcade Physics.
At each frame, boids trajectory is adjusted. Obviously a Boid can’t see all the other boids, but only the ones within a given range.
Look at the example – you may need to reload it if you only see a white ball:
Boids converge to the center of the flock, and if you notice some boids wandering like crazy, that’s because they are too far from any other visible boid.
This is the commented source code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 | var game; // number of boids (bird-oid objects) var boidsAmount = 50; // speed of each boid, in pixels per second var boidSpeed = 100; // radius of sight of the boid var boidRadius = 50; // array which will contain all boids var boids = []; window.onload = function () { game = new Phaser.Game(640, 640, Phaser.AUTO, "" ); game.state.add( "Simulate" , simulate); game.state.start( "Simulate" ); } var simulate = function (game){}; simulate.prototype = { preload: function (){ // preloading boid image game.load.image( "boid" , "boid.png" ); }, create: function (){ for ( var i = 0; i < boidsAmount; i++){ // placing the boid at a random point within the canvas var randomPoint = new Phaser.Point(game.rnd.between(0, game.width - 1), game.rnd.between(0, game.height - 1)); boids[i] = { position: randomPoint, asset: game.add.sprite(randomPoint.x, randomPoint.y, "boid" ) } boids[i].asset.anchor.set(0.5); // enabling boid physics game.physics.enable(boids[i].asset, Phaser.Physics.ARCADE); // allowing us to manually rotate the boid boids[i].asset.body.allowRotation = false ; } }, update: function (){ // temp array to calculate centroid var centroidArray = []; // looping through each boid for ( var i = 0; i < boidsAmount; i++){ // for each boid, looping through each boid for ( var j = 0; j < boidsAmount; j++){ // if the boid is not the current boid and the boid is within boid radius... if (i != j && boids[i].position.distance(boids[j].position) < boidRadius){ // pushing the boid into centroid array centroidArray.push(boids[j].position); } } // if centroidArray is populated, that is if there were boids nearby the current boid... if (centroidArray.length > 0){ // calculating the centroid var centroid = Phaser.Point.centroid(centroidArray); } else { // just tossing a random point var centroid = new Phaser.Point(game.rnd.between(0, game.width - 1), game.rnd.between(0, game.height - 1)); } // rotating the boid towards the centroid boids[i].asset.angle = boids[i].position.angle(centroid, true ); // moving the boid towards the centroid game.physics.arcade.moveToXY(boids[i].asset, centroid.x, centroid.y, boidSpeed); // updating boid position boids[i].position.set(boids[i].asset.x, boids[i].asset.y); } } } |
Never miss an update! Subscribe, and I will bother you by email only when a new game or full source code comes out.