├── LICENSE ├── README.md ├── screenshots ├── flappy_01.png ├── flappy_02.png ├── flappy_03.png ├── flappy_04.png ├── flappy_05.png ├── flappy_06.png ├── flappy_07.png ├── flappy_08.png ├── flappy_09.png └── flappy_10.png └── source ├── assets ├── fnt_chars_black.fnt ├── fnt_chars_black.png ├── fnt_digits_blue.fnt ├── fnt_digits_blue.png ├── fnt_digits_green.fnt ├── fnt_digits_green.png ├── fnt_digits_red.fnt ├── fnt_digits_red.png ├── img_bird.png ├── img_buttons.png ├── img_ground.png ├── img_logo.png ├── img_pause.png ├── img_target.png └── img_tree.png ├── gameplay.js ├── genetic.js ├── index.html ├── phaser.min.js └── synaptic.min.js /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Srdjan Susnic 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Machine Learning for Flappy Bird using Neural Network and Genetic Algorithm 2 | 3 | Here is the source code for a HTML5 project that implements a machine learning algorithm in the Flappy Bird video game using neural networks and a genetic algorithm. The program teaches a little bird how to flap optimally in order to fly safely through barriers as long as possible. 4 | 5 | The complete tutorial with much more details and demo you can find here: 6 | [http://www.askforgametask.com/tutorial/machine-learning-algorithm-flappy-bird](http://www.askforgametask.com/tutorial/machine-learning-algorithm-flappy-bird) 7 | 8 | Here you can also watch a short video with a simple presentation of the algorithm: 9 | [https://www.youtube.com/watch?v=aeWmdojEJf0](https://www.youtube.com/watch?v=aeWmdojEJf0) 10 | 11 | All code is written in HTML5 using [Phaser framework](http://phaser.io/) and [Synaptic Neural Network library](https://synaptic.juancazala.com) for neural network implementation. 12 | 13 | ![Flappy Bird Screenshot](https://raw.githubusercontent.com/ssusnic/Machine-Learning-Flappy-Bird/master/screenshots/flappy_10.png "Flappy Bird Screenshot") 14 | 15 | ## Neural Network Architecture 16 | 17 | To play the game, each unit (bird) has its own neural network consisted of the next 3 layers: 18 | 1. an input layer with 2 neurons presenting what a bird sees: 19 | 20 | ``` 21 | 1) horizontal distance between the bird and the closest gap 22 | 2) height difference between the bird and the closest gap 23 | ``` 24 | 25 | 2. a hidden layer with 6 neurons 26 | 3. an output layer with 1 neuron used to provide an action as follows: 27 | 28 | ``` 29 | if output > 0.5 then flap else do nothing 30 | ``` 31 | 32 | ![Flappy Bird Neural Network](https://raw.githubusercontent.com/ssusnic/Machine-Learning-Flappy-Bird/master/screenshots/flappy_06.png "Flappy Bird Neural Network") 33 | 34 | 35 | There is used [Synaptic Neural Network library](https://synaptic.juancazala.com) to implement entire artificial neural network instead of making a new one from the scratch. 36 | 37 | ## The Main Concept of Machine Learning 38 | 39 | The main concept of machine learning implemented in this program is based on the neuro-evolution form. It uses evolutionary algorithms such as a genetic algorithm to train artificial neural networks. Here are the main steps: 40 | 41 | 1. create a new population of 10 units (birds) with a **random neural network** 42 | 2. let all units play the game simultaneously by using their own neural networks 43 | 3. for each unit calculate its **fitness** function to measure its quality as: 44 | 45 | ``` 46 | fitness = total travelled distance - distance to the closest gap 47 | ``` 48 | 49 | ![Flappy Bird Fitness](https://raw.githubusercontent.com/ssusnic/Machine-Learning-Flappy-Bird/master/screenshots/flappy_08.png "Flappy Bird Fitness") 50 | 51 | 52 | 4. when all units are killed, evaluate the current population to the next one using **genetic algorithm operators** (selection, crossover and mutation) as follows: 53 | 54 | ``` 55 | 1. sort the units of the current population in decreasing order by their fitness ranking 56 | 2. select the top 4 units and mark them as the winners of the current population 57 | 3. the 4 winners are directly passed on to the next population 58 | 4. to fill the rest of the next population, create 6 offsprings as follows: 59 | - 1 offspring is made by a crossover of two best winners 60 | - 3 offsprings are made by a crossover of two random winners 61 | - 2 offsprings are direct copy of two random winners 62 | 5. to add some variations, apply random mutations on each offspring. 63 | ``` 64 | 65 | 5. go back to the step 2 66 | 67 | ## Implementation 68 | 69 | ### Requirements 70 | 71 | Since the program is written in HTML5 using [Phaser framework](http://phaser.io/) and [Synaptic Neural Network library](https://synaptic.juancazala.com) you need these files: 72 | 73 | - **phaser.min.js** 74 | - **synaptic.min.js** 75 | 76 | ### gameplay.js 77 | The entire game logic is implemented in **gameplay.js** file. It consists of the following classes: 78 | 79 | - `App.Main`, the main routine with the following essential functions: 80 | - _preload()_ to preload all assets 81 | - _create()_ to create all objects and initialize a new genetic algorithm object 82 | - _update()_ to run the main loop in which the Flappy Bird game is played by using AI neural networks and the population is evolved by using genetic algorithm 83 | - _drawStatus()_ to display information of all units 84 | 85 | - `TreeGroup Class`, extended Phaser Group class to represent a moving barrier. This group contains a top and a bottom Tree sprite. 86 | 87 | - `Tree Class`, extended Phaser Sprite class to represent a Tree sprite. 88 | 89 | - `Bird Class`, extended Phaser Sprite class to represent a Bird sprite. 90 | 91 | - `Text Class`, extended Phaser BitmapText class used for drawing text. 92 | 93 | ### genetic.js 94 | 95 | The genetic algorithm is implemented in **genetic.js** file which consists of the following class: 96 | 97 | - `GeneticAlgorithm Class`, the main class to handle all genetic algorithm operations. It needs two parameters: **_max_units_** to set a total number of units in population and **_top_units_** to set a number of top units (winners) used for evolving population. Here are its essential functions: 98 | 99 | - _reset()_ to reset genetic algorithm parameters 100 | - _createPopulation()_ to create a new population 101 | - _activateBrain()_ to activate the AI neural network of an unit and get its output action according to the inputs 102 | - _evolvePopulation()_ to evolve the population by using genetic operators (selection, crossover and mutations) 103 | - _selection()_ to select the best units from the current population 104 | - _crossOver()_ to perform a single point crossover between two parents 105 | - _mutation()_ to perform random mutations on an offspring 106 | -------------------------------------------------------------------------------- /screenshots/flappy_01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssusnic/Machine-Learning-Flappy-Bird/2b03276ea25f2ea508ca6917197be4017f31eda2/screenshots/flappy_01.png -------------------------------------------------------------------------------- /screenshots/flappy_02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssusnic/Machine-Learning-Flappy-Bird/2b03276ea25f2ea508ca6917197be4017f31eda2/screenshots/flappy_02.png -------------------------------------------------------------------------------- /screenshots/flappy_03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssusnic/Machine-Learning-Flappy-Bird/2b03276ea25f2ea508ca6917197be4017f31eda2/screenshots/flappy_03.png -------------------------------------------------------------------------------- /screenshots/flappy_04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssusnic/Machine-Learning-Flappy-Bird/2b03276ea25f2ea508ca6917197be4017f31eda2/screenshots/flappy_04.png -------------------------------------------------------------------------------- /screenshots/flappy_05.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssusnic/Machine-Learning-Flappy-Bird/2b03276ea25f2ea508ca6917197be4017f31eda2/screenshots/flappy_05.png -------------------------------------------------------------------------------- /screenshots/flappy_06.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssusnic/Machine-Learning-Flappy-Bird/2b03276ea25f2ea508ca6917197be4017f31eda2/screenshots/flappy_06.png -------------------------------------------------------------------------------- /screenshots/flappy_07.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssusnic/Machine-Learning-Flappy-Bird/2b03276ea25f2ea508ca6917197be4017f31eda2/screenshots/flappy_07.png -------------------------------------------------------------------------------- /screenshots/flappy_08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssusnic/Machine-Learning-Flappy-Bird/2b03276ea25f2ea508ca6917197be4017f31eda2/screenshots/flappy_08.png -------------------------------------------------------------------------------- /screenshots/flappy_09.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssusnic/Machine-Learning-Flappy-Bird/2b03276ea25f2ea508ca6917197be4017f31eda2/screenshots/flappy_09.png -------------------------------------------------------------------------------- /screenshots/flappy_10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssusnic/Machine-Learning-Flappy-Bird/2b03276ea25f2ea508ca6917197be4017f31eda2/screenshots/flappy_10.png -------------------------------------------------------------------------------- /source/assets/fnt_chars_black.fnt: -------------------------------------------------------------------------------- 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 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | -------------------------------------------------------------------------------- /source/assets/fnt_chars_black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssusnic/Machine-Learning-Flappy-Bird/2b03276ea25f2ea508ca6917197be4017f31eda2/source/assets/fnt_chars_black.png -------------------------------------------------------------------------------- /source/assets/fnt_digits_blue.fnt: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /source/assets/fnt_digits_blue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssusnic/Machine-Learning-Flappy-Bird/2b03276ea25f2ea508ca6917197be4017f31eda2/source/assets/fnt_digits_blue.png -------------------------------------------------------------------------------- /source/assets/fnt_digits_green.fnt: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /source/assets/fnt_digits_green.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssusnic/Machine-Learning-Flappy-Bird/2b03276ea25f2ea508ca6917197be4017f31eda2/source/assets/fnt_digits_green.png -------------------------------------------------------------------------------- /source/assets/fnt_digits_red.fnt: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /source/assets/fnt_digits_red.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssusnic/Machine-Learning-Flappy-Bird/2b03276ea25f2ea508ca6917197be4017f31eda2/source/assets/fnt_digits_red.png -------------------------------------------------------------------------------- /source/assets/img_bird.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssusnic/Machine-Learning-Flappy-Bird/2b03276ea25f2ea508ca6917197be4017f31eda2/source/assets/img_bird.png -------------------------------------------------------------------------------- /source/assets/img_buttons.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssusnic/Machine-Learning-Flappy-Bird/2b03276ea25f2ea508ca6917197be4017f31eda2/source/assets/img_buttons.png -------------------------------------------------------------------------------- /source/assets/img_ground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssusnic/Machine-Learning-Flappy-Bird/2b03276ea25f2ea508ca6917197be4017f31eda2/source/assets/img_ground.png -------------------------------------------------------------------------------- /source/assets/img_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssusnic/Machine-Learning-Flappy-Bird/2b03276ea25f2ea508ca6917197be4017f31eda2/source/assets/img_logo.png -------------------------------------------------------------------------------- /source/assets/img_pause.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssusnic/Machine-Learning-Flappy-Bird/2b03276ea25f2ea508ca6917197be4017f31eda2/source/assets/img_pause.png -------------------------------------------------------------------------------- /source/assets/img_target.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssusnic/Machine-Learning-Flappy-Bird/2b03276ea25f2ea508ca6917197be4017f31eda2/source/assets/img_target.png -------------------------------------------------------------------------------- /source/assets/img_tree.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssusnic/Machine-Learning-Flappy-Bird/2b03276ea25f2ea508ca6917197be4017f31eda2/source/assets/img_tree.png -------------------------------------------------------------------------------- /source/gameplay.js: -------------------------------------------------------------------------------- 1 | /*********************************************************************************** 2 | /* Create a new Phaser Game on window load 3 | /***********************************************************************************/ 4 | 5 | window.onload = function () { 6 | var game = new Phaser.Game(1280, 720, Phaser.CANVAS, 'game'); 7 | 8 | game.state.add('Main', App.Main); 9 | game.state.start('Main'); 10 | }; 11 | 12 | /*********************************************************************************** 13 | /* Main program 14 | /***********************************************************************************/ 15 | 16 | var App = {}; 17 | 18 | App.Main = function(game){ 19 | this.STATE_INIT = 1; 20 | this.STATE_START = 2; 21 | this.STATE_PLAY = 3; 22 | this.STATE_GAMEOVER = 4; 23 | 24 | this.BARRIER_DISTANCE = 300; 25 | } 26 | 27 | App.Main.prototype = { 28 | preload : function(){ 29 | this.game.load.spritesheet('imgBird', 'assets/img_bird.png', 36, 36, 20); 30 | this.game.load.spritesheet('imgTree', 'assets/img_tree.png', 90, 400, 2); 31 | this.game.load.spritesheet('imgButtons', 'assets/img_buttons.png', 110, 40, 3); 32 | 33 | this.game.load.image('imgTarget', 'assets/img_target.png'); 34 | this.game.load.image('imgGround', 'assets/img_ground.png'); 35 | this.game.load.image('imgPause', 'assets/img_pause.png'); 36 | this.game.load.image('imgLogo', 'assets/img_logo.png'); 37 | 38 | this.load.bitmapFont('fnt_chars_black', 'assets/fnt_chars_black.png', 'assets/fnt_chars_black.fnt'); 39 | this.load.bitmapFont('fnt_digits_blue', 'assets/fnt_digits_blue.png', 'assets/fnt_digits_blue.fnt'); 40 | this.load.bitmapFont('fnt_digits_green', 'assets/fnt_digits_green.png', 'assets/fnt_digits_green.fnt'); 41 | this.load.bitmapFont('fnt_digits_red', 'assets/fnt_digits_red.png', 'assets/fnt_digits_red.fnt'); 42 | }, 43 | 44 | create : function(){ 45 | // set scale mode to cover the entire screen 46 | this.scale.scaleMode = Phaser.ScaleManager.SHOW_ALL; 47 | this.scale.pageAlignVertically = true; 48 | this.scale.pageAlignHorizontally = true; 49 | 50 | // set a blue color for the background of the stage 51 | this.game.stage.backgroundColor = "#89bfdc"; 52 | 53 | // keep game running if it loses the focus 54 | this.game.stage.disableVisibilityChange = true; 55 | 56 | // start the Phaser arcade physics engine 57 | this.game.physics.startSystem(Phaser.Physics.ARCADE); 58 | 59 | // set the gravity of the world 60 | this.game.physics.arcade.gravity.y = 1300; 61 | 62 | // create a new Genetic Algorithm with a population of 10 units which will be evolving by using 4 top units 63 | this.GA = new GeneticAlgorithm(10, 4); 64 | 65 | // create a BirdGroup which contains a number of Bird objects 66 | this.BirdGroup = this.game.add.group(); 67 | for (var i = 0; i < this.GA.max_units; i++){ 68 | this.BirdGroup.add(new Bird(this.game, 0, 0, i)); 69 | } 70 | 71 | // create a BarrierGroup which contains a number of Tree Groups 72 | // (each Tree Group contains a top and bottom Tree object) 73 | this.BarrierGroup = this.game.add.group(); 74 | for (var i = 0; i < 4; i++){ 75 | new TreeGroup(this.game, this.BarrierGroup, i); 76 | } 77 | 78 | // create a Target Point sprite 79 | this.TargetPoint = this.game.add.sprite(0, 0, 'imgTarget'); 80 | this.TargetPoint.anchor.setTo(0.5); 81 | 82 | // create a scrolling Ground object 83 | this.Ground = this.game.add.tileSprite(0, this.game.height-100, this.game.width-370, 100, 'imgGround'); 84 | this.Ground.autoScroll(-200, 0); 85 | 86 | // create a BitmapData image for drawing head-up display (HUD) on it 87 | this.bmdStatus = this.game.make.bitmapData(370, this.game.height); 88 | this.bmdStatus.addToWorld(this.game.width - this.bmdStatus.width, 0); 89 | 90 | // create text objects displayed in the HUD header 91 | new Text(this.game, 1047, 10, "In1 In2 Out", "right", "fnt_chars_black"); // Input 1 | Input 2 | Output 92 | this.txtPopulationPrev = new Text(this.game, 1190, 10, "", "right", "fnt_chars_black"); // No. of the previous population 93 | this.txtPopulationCurr = new Text(this.game, 1270, 10, "", "right", "fnt_chars_black"); // No. of the current population 94 | 95 | // create text objects for each bird to show their info on the HUD 96 | this.txtStatusPrevGreen = []; // array of green text objects to show info of top units from the previous population 97 | this.txtStatusPrevRed = []; // array of red text objects to show info of weak units from the previous population 98 | this.txtStatusCurr = []; // array of blue text objects to show info of all units from the current population 99 | 100 | for (var i=0; i this.TargetPoint.x) isNextTarget = true; 200 | 201 | // check if a bird flies out of vertical bounds 202 | if (bird.y<0 || bird.y>610) this.onDeath(bird); 203 | 204 | // perform a proper action (flap yes/no) for this bird by activating its neural network 205 | this.GA.activateBrain(bird, this.TargetPoint); 206 | } 207 | }, this); 208 | 209 | // if any bird passed through the current target barrier then set the next target barrier 210 | if (isNextTarget){ 211 | this.score++; 212 | this.targetBarrier = this.getNextBarrier(this.targetBarrier.index); 213 | } 214 | 215 | // if the first barrier went out of the left bound then restart it on the right side 216 | if (this.firstBarrier.getWorldX() < -this.firstBarrier.width){ 217 | this.firstBarrier.restart(this.lastBarrier.getWorldX() + this.BARRIER_DISTANCE); 218 | 219 | this.firstBarrier = this.getNextBarrier(this.firstBarrier.index); 220 | this.lastBarrier = this.getNextBarrier(this.lastBarrier.index); 221 | } 222 | 223 | // increase the travelled distance 224 | this.distance += Math.abs(this.firstBarrier.topTree.deltaX); 225 | 226 | this.drawStatus(); 227 | break; 228 | 229 | case this.STATE_GAMEOVER: // when all birds are killed evolve the population 230 | this.GA.evolvePopulation(); 231 | this.GA.iteration++; 232 | 233 | this.state = this.STATE_START; 234 | break; 235 | } 236 | }, 237 | 238 | drawStatus : function(){ 239 | this.bmdStatus.fill(180, 180, 180); // clear bitmap data by filling it with a gray color 240 | this.bmdStatus.rect(0, 0, this.bmdStatus.width, 35, "#8e8e8e"); // draw the HUD header rect 241 | 242 | this.BirdGroup.forEach(function(bird){ 243 | var y = 85 + bird.index*50; 244 | 245 | this.bmdStatus.draw(bird, 25, y-25); // draw bird's image 246 | this.bmdStatus.rect(0, y, this.bmdStatus.width, 2, "#888"); // draw line separator 247 | 248 | if (bird.alive){ 249 | var brain = this.GA.Population[bird.index].toJSON(); 250 | var scale = this.GA.SCALE_FACTOR*0.02; 251 | 252 | this.bmdStatus.rect(62, y, 9, -(50 - brain.neurons[0].activation/scale), "#000088"); // input 1 253 | this.bmdStatus.rect(90, y, 9, brain.neurons[1].activation/scale, "#000088"); // input 2 254 | 255 | if (brain.neurons[brain.neurons.length-1].activation<0.5) this.bmdStatus.rect(118, y, 9, -20, "#880000"); // output: flap = no 256 | else this.bmdStatus.rect(118, y, 9, -40, "#008800"); // output: flap = yes 257 | } 258 | 259 | // draw bird's fitness and score 260 | this.txtStatusCurr[bird.index].setText(bird.fitness_curr.toFixed(2)+"\n" + bird.score_curr); 261 | }, this); 262 | }, 263 | 264 | getNextBarrier : function(index){ 265 | return this.BarrierGroup.getAt((index + 1) % this.BarrierGroup.length); 266 | }, 267 | 268 | onDeath : function(bird){ 269 | this.GA.Population[bird.index].fitness = bird.fitness_curr; 270 | this.GA.Population[bird.index].score = bird.score_curr; 271 | 272 | bird.death(); 273 | if (this.BirdGroup.countLiving() == 0) this.state = this.STATE_GAMEOVER; 274 | }, 275 | 276 | onRestartClick : function(){ 277 | this.state = this.STATE_INIT; 278 | }, 279 | 280 | onMoreGamesClick : function(){ 281 | window.open("http://www.askforgametask.com", "_blank"); 282 | }, 283 | 284 | onPauseClick : function(){ 285 | this.game.paused = true; 286 | this.btnPause.input.reset(); 287 | this.sprPause.revive(); 288 | }, 289 | 290 | onResumeClick : function(){ 291 | if (this.game.paused){ 292 | this.game.paused = false; 293 | this.btnPause.input.enabled = true; 294 | this.sprPause.kill(); 295 | } 296 | } 297 | } 298 | 299 | /*********************************************************************************** 300 | /* TreeGroup Class extends Phaser.Group 301 | /***********************************************************************************/ 302 | 303 | var TreeGroup = function(game, parent, index){ 304 | Phaser.Group.call(this, game, parent); 305 | 306 | this.index = index; 307 | 308 | this.topTree = new Tree(this.game, 0); // create a top Tree object 309 | this.bottomTree = new Tree(this.game, 1); // create a bottom Tree object 310 | 311 | this.add(this.topTree); // add the top Tree to this group 312 | this.add(this.bottomTree); // add the bottom Tree to this group 313 | }; 314 | 315 | TreeGroup.prototype = Object.create(Phaser.Group.prototype); 316 | TreeGroup.prototype.constructor = TreeGroup; 317 | 318 | TreeGroup.prototype.restart = function(x) { 319 | this.topTree.reset(0, 0); 320 | this.bottomTree.reset(0, this.topTree.height + 130); 321 | 322 | this.x = x; 323 | this.y = this.game.rnd.integerInRange(110-this.topTree.height, -20); 324 | 325 | this.setAll('body.velocity.x', -200); 326 | }; 327 | 328 | TreeGroup.prototype.getWorldX = function() { 329 | return this.topTree.world.x; 330 | }; 331 | 332 | TreeGroup.prototype.getGapX = function() { 333 | return this.bottomTree.world.x + this.bottomTree.width; 334 | }; 335 | 336 | TreeGroup.prototype.getGapY = function() { 337 | return this.bottomTree.world.y - 65; 338 | }; 339 | 340 | /*********************************************************************************** 341 | /* Tree Class extends Phaser.Sprite 342 | /***********************************************************************************/ 343 | 344 | var Tree = function(game, frame) { 345 | Phaser.Sprite.call(this, game, 0, 0, 'imgTree', frame); 346 | 347 | this.game.physics.arcade.enableBody(this); 348 | 349 | this.body.allowGravity = false; 350 | this.body.immovable = true; 351 | }; 352 | 353 | Tree.prototype = Object.create(Phaser.Sprite.prototype); 354 | Tree.prototype.constructor = Tree; 355 | 356 | /*********************************************************************************** 357 | /* Bird Class extends Phaser.Sprite 358 | /***********************************************************************************/ 359 | 360 | var Bird = function(game, x, y, index) { 361 | Phaser.Sprite.call(this, game, x, y, 'imgBird'); 362 | 363 | this.index = index; 364 | this.anchor.setTo(0.5); 365 | 366 | // add flap animation and start to play it 367 | var i=index*2; 368 | this.animations.add('flap', [i, i+1]); 369 | this.animations.play('flap', 8, true); 370 | 371 | // enable physics on the bird 372 | this.game.physics.arcade.enableBody(this); 373 | }; 374 | 375 | Bird.prototype = Object.create(Phaser.Sprite.prototype); 376 | Bird.prototype.constructor = Bird; 377 | 378 | Bird.prototype.restart = function(iteration){ 379 | this.fitness_prev = (iteration == 1) ? 0 : this.fitness_curr; 380 | this.fitness_curr = 0; 381 | 382 | this.score_prev = (iteration == 1) ? 0: this.score_curr; 383 | this.score_curr = 0; 384 | 385 | this.alpha = 1; 386 | this.reset(150, 300 + this.index * 20); 387 | }; 388 | 389 | Bird.prototype.flap = function(){ 390 | this.body.velocity.y = -400; 391 | }; 392 | 393 | Bird.prototype.death = function(){ 394 | this.alpha = 0.5; 395 | this.kill(); 396 | }; 397 | 398 | /*********************************************************************************** 399 | /* Text Class extends Phaser.BitmapText 400 | /***********************************************************************************/ 401 | 402 | var Text = function(game, x, y, text, align, font){ 403 | Phaser.BitmapText.call(this, game, x, y, font, text, 16); 404 | 405 | this.align = align; 406 | 407 | if (align == "right") this.anchor.setTo(1, 0); 408 | else this.anchor.setTo(0.5); 409 | 410 | this.game.add.existing(this); 411 | }; 412 | 413 | Text.prototype = Object.create(Phaser.BitmapText.prototype); 414 | Text.prototype.constructor = Text; 415 | 416 | -------------------------------------------------------------------------------- /source/genetic.js: -------------------------------------------------------------------------------- 1 | /*********************************************************************************** 2 | /* Genetic Algorithm implementation 3 | /***********************************************************************************/ 4 | 5 | var GeneticAlgorithm = function(max_units, top_units){ 6 | this.max_units = max_units; // max number of units in population 7 | this.top_units = top_units; // number of top units (winners) used for evolving population 8 | 9 | if (this.max_units < this.top_units) this.top_units = this.max_units; 10 | 11 | this.Population = []; // array of all units in current population 12 | 13 | this.SCALE_FACTOR = 200; // the factor used to scale normalized input values 14 | } 15 | 16 | GeneticAlgorithm.prototype = { 17 | // resets genetic algorithm parameters 18 | reset : function(){ 19 | this.iteration = 1; // current iteration number (it is equal to the current population number) 20 | this.mutateRate = 1; // initial mutation rate 21 | 22 | this.best_population = 0; // the population number of the best unit 23 | this.best_fitness = 0; // the fitness of the best unit 24 | this.best_score = 0; // the score of the best unit ever 25 | }, 26 | 27 | // creates a new population 28 | createPopulation : function(){ 29 | // clear any existing population 30 | this.Population.splice(0, this.Population.length); 31 | 32 | for (var i=0; i