# Flappy bird p5.js

**URL:** <https://discourse.processing.org/t/flappy-bird-p5-js/40521>\
**Category:** Coding Questions\
**Created:** [January 9, 2023, 11:05am UTC](https://discourse.processing.org/t/flappy-bird-p5-js/40521 "2023-01-09T11:05:58Z")\
**Posts on this page:** 18\
**Page:** 1

<div class="post-metadata">

**Author:** ![ctremblay](https://avatars.discourse-cdn.com/v4/letter/c/e495f1/32.png) [@ctremblay](https://discourse.processing.org/u/ctremblay)\
**Post date:** [January 9, 2023, 11:05am UTC](https://discourse.processing.org/t/flappy-bird-p5-js/40521/1 "2023-01-09T11:05:58Z")

</div>

i’m trying to make an ai version of flappy birds, but when i go to save the bird it cant find the saved score. it keeps saying undefined when i console.log.

sketch.js

```auto
var bird = [];
var saved = [];
var paused = false;
var space = 200;
var moveSpeed = 1;
var pipe = [];
var pipeX = 100;
var total = 500;
var highScore = 0;

function setup() {
  createCanvas(400, 400);
}

function draw() {
  background(220);
  if (bird.length == 0){
    nextGen();
  }
  if (paused == false){
    for (var i = bird.length-1; i >= 0; i--){
      bird[i].move();
      bird[i].hit();
      bird[i].think();
      if (bird[i].alive == false){
        saved.push(bird.splice(i,1),[0]);
      }
    }
    for (var i = pipe.length-1; i >= 0; i--){
      pipe[i].move();
      if (pipe[i].destroy){
        for (var j = bird.length-1; j >= 0; j--){
          bird[j].score += 1;
        }
        pipe.splice(i,1);
      }
    }
  }
  for (var p of pipe){
    p.show();
  }
  for (var b of bird){
    b.show();
  }
  fill(0);
  textSize(20);
  text(highScore,5,20);
  if (bird.length > 0){
    text(bird[0].score,5,40);
  }
}

function keyPressed(){
  if (key == 'p'){
    if (paused == true){paused = false;}
    else if (paused == false){paused = true;}
  }
}

```

bird.js

```auto
class Bird{
  
  constructor(brain){
    this.x = 32;
    this.y = height/2;
    
    this.grav = 0.7;
    this.lift = -12;
    this.vel = 0;
    this.alive = true;
    this.score = 0;
    this.r = 8;
    if (brain){
      this.brain = brain.copy();
    } else {
      this.brain = new NeuralNetwork(4, 6, 2);
    }
  }
  
  mutate(){
    this.brain.mutate(0.1);
  }
  
  think(){
    
    let closest = null;
    let closestD = Infinity;
    for (let i = 0; i < pipe.length; i++){
      let d = pipe[i].x - this.x;
      if (d < closestD && d > 0){
        closest = pipe[i];
        closestD = d;
      }
    }
    
    let input = [];
    input[0] = this.y/height;
    input[1] = this.x/width;
    input[2] = closest.x/width;
    input[3] = (closest.top + (space/2))/height;
    let output = this.brain.predict(input);
    if (output[0] > output[1]){
      this.up();
    }
  }
  
  show(){
    if (this.alive == false){fill(255,0,0);}
    if(this.alive){fill(255,255,0);}
    ellipse(this.x,this.y,this.r*2,this.r*2);
  }
  
  hit(){
    this.alive = true;
    for (var i = pipe.length-1; i >= 0; i--){
      if (this.x > pipe[i].x && this.x < pipe[i].x + pipe[i].w){
        if (this.y < pipe[i].top || this.y > height - pipe[i].bottom){
          this.alive = false;
        }
      }
    }
  }
  
  up(){
    if (this.vel >= 0){
      this.vel += this.lift;
    }
  }
  
  move(){
    this.vel += this.grav;
    this.y += this.vel;
    if (this.y > height || this.y < 0){
      this.alive = false;
    }
  }
}

```

pipe.js

```auto
class Pipe{
  
  constructor(){
    this.x = 410;
    this.w = 50;
    this.top = random(25,height - 25 - space);
    this.bottom = height - this.top - space;
    this.destroy = false;
    this.create = false;
  }
  
  show(){
    fill(0,255,0);
    rect(this.x,0,this.w,this.top);
    rect(this.x,height - this.bottom,this.w,this.bottom);
  }
  
  move(){
    this.x -= moveSpeed;
    if (this.create == false && this.x < pipeX){
      pipe.push(new Pipe());
      this.create = true;
    }
    if (this.x < -this.w){
      this.destroy = true;
    }
  }
}

```

nn.js

```auto
class ActivationFunction {
  constructor(func, dfunc) {
    this.func = func;
    this.dfunc = dfunc;
  }
}

let sigmoid = new ActivationFunction(
  x => 1 / (1 + Math.exp(-x)),
  y => y * (1 - y)
);

let tanh = new ActivationFunction(
  x => Math.tanh(x),
  y => 1 - (y * y)
);

class NeuralNetwork {
  // TODO: document what a, b, c are
  constructor(a, b, c) {
    if (a instanceof NeuralNetwork) {
      this.input_nodes = a.input_nodes;
      this.hidden_nodes = a.hidden_nodes;
      this.output_nodes = a.output_nodes;

      this.weights_ih = a.weights_ih.copy();
      this.weights_ho = a.weights_ho.copy();

      this.bias_h = a.bias_h.copy();
      this.bias_o = a.bias_o.copy();
    } else {
      this.input_nodes = a;
      this.hidden_nodes = b;
      this.output_nodes = c;

      this.weights_ih = new Matrix(this.hidden_nodes, this.input_nodes);
      this.weights_ho = new Matrix(this.output_nodes, this.hidden_nodes);
      this.weights_ih.randomize();
      this.weights_ho.randomize();

      this.bias_h = new Matrix(this.hidden_nodes, 1);
      this.bias_o = new Matrix(this.output_nodes, 1);
      this.bias_h.randomize();
      this.bias_o.randomize();
    }

    // TODO: copy these as well
    this.setLearningRate();
    this.setActivationFunction();

  }

  predict(input_array) {

    // Generating the Hidden Outputs
    let inputs = Matrix.fromArray(input_array);
    let hidden = Matrix.multiply(this.weights_ih, inputs);
    hidden.add(this.bias_h);
    // activation function!
    hidden.map(this.activation_function.func);

    // Generating the output's output!
    let output = Matrix.multiply(this.weights_ho, hidden);
    output.add(this.bias_o);
    output.map(this.activation_function.func);

    // Sending back to the caller!
    return output.toArray();
  }

  setLearningRate(learning_rate = 0.1) {
    this.learning_rate = learning_rate;
  }

  setActivationFunction(func = sigmoid) {
    this.activation_function = func;
  }

  train(input_array, target_array) {
    // Generating the Hidden Outputs
    let inputs = Matrix.fromArray(input_array);
    let hidden = Matrix.multiply(this.weights_ih, inputs);
    hidden.add(this.bias_h);
    // activation function!
    hidden.map(this.activation_function.func);

    // Generating the output's output!
    let outputs = Matrix.multiply(this.weights_ho, hidden);
    outputs.add(this.bias_o);
    outputs.map(this.activation_function.func);

    // Convert array to matrix object
    let targets = Matrix.fromArray(target_array);

    // Calculate the error
    // ERROR = TARGETS - OUTPUTS
    let output_errors = Matrix.subtract(targets, outputs);

    // let gradient = outputs * (1 - outputs);
    // Calculate gradient
    let gradients = Matrix.map(outputs, this.activation_function.dfunc);
    gradients.multiply(output_errors);
    gradients.multiply(this.learning_rate);

    // Calculate deltas
    let hidden_T = Matrix.transpose(hidden);
    let weight_ho_deltas = Matrix.multiply(gradients, hidden_T);

    // Adjust the weights by deltas
    this.weights_ho.add(weight_ho_deltas);
    // Adjust the bias by its deltas (which is just the gradients)
    this.bias_o.add(gradients);

    // Calculate the hidden layer errors
    let who_t = Matrix.transpose(this.weights_ho);
    let hidden_errors = Matrix.multiply(who_t, output_errors);

    // Calculate hidden gradient
    let hidden_gradient = Matrix.map(hidden, this.activation_function.dfunc);
    hidden_gradient.multiply(hidden_errors);
    hidden_gradient.multiply(this.learning_rate);

    // Calcuate input->hidden deltas
    let inputs_T = Matrix.transpose(inputs);
    let weight_ih_deltas = Matrix.multiply(hidden_gradient, inputs_T);

    this.weights_ih.add(weight_ih_deltas);
    // Adjust the bias by its deltas (which is just the gradients)
    this.bias_h.add(hidden_gradient);

    // outputs.print();
    // targets.print();
    // error.print();
  }

  serialize() {
    return JSON.stringify(this);
  }

  static deserialize(data) {
    if (typeof data == 'string') {
      data = JSON.parse(data);
    }
    let nn = new NeuralNetwork(data.input_nodes, data.hidden_nodes, data.output_nodes);
    nn.weights_ih = Matrix.deserialize(data.weights_ih);
    nn.weights_ho = Matrix.deserialize(data.weights_ho);
    nn.bias_h = Matrix.deserialize(data.bias_h);
    nn.bias_o = Matrix.deserialize(data.bias_o);
    nn.learning_rate = data.learning_rate;
    return nn;
  }

  // Adding function for neuro-evolution
  copy() {
    return new NeuralNetwork(this);
  }

  mutate(rate) {
    function mutate(val) {
      if (Math.random() < rate) {
        // return 2 * Math.random() - 1;
        return val + randomGaussian(0, 0.1);
      } else {
        return val;
      }
    }
    this.weights_ih.map(mutate);
    this.weights_ho.map(mutate);
    this.bias_h.map(mutate);
    this.bias_o.map(mutate);
  }

}

```

matrix.js

```auto
class Matrix {
  constructor(rows, cols) {
    this.rows = rows;
    this.cols = cols;
    this.data = Array(this.rows).fill().map(() => Array(this.cols).fill(0));
  }

  copy() {
    let m = new Matrix(this.rows, this.cols);
    for (let i = 0; i < this.rows; i++) {
      for (let j = 0; j < this.cols; j++) {
        m.data[i][j] = this.data[i][j];
      }
    }
    return m;
  }

  static fromArray(arr) {
    return new Matrix(arr.length, 1).map((e, i) => arr[i]);
  }

  static subtract(a, b) {
    if (a.rows !== b.rows || a.cols !== b.cols) {
      console.log('Columns and Rows of A must match Columns and Rows of B.');
      return;
    }

    // Return a new Matrix a-b
    return new Matrix(a.rows, a.cols)
      .map((_, i, j) => a.data[i][j] - b.data[i][j]);
  }

  toArray() {
    let arr = [];
    for (let i = 0; i < this.rows; i++) {
      for (let j = 0; j < this.cols; j++) {
        arr.push(this.data[i][j]);
      }
    }
    return arr;
  }

  randomize() {
    return this.map(e => Math.random() * 2 - 1);
  }

  add(n) {
    if (n instanceof Matrix) {
      if (this.rows !== n.rows || this.cols !== n.cols) {
        console.log('Columns and Rows of A must match Columns and Rows of B.');
        return;
      }
      return this.map((e, i, j) => e + n.data[i][j]);
    } else {
      return this.map(e => e + n);
    }
  }

  static transpose(matrix) {
    return new Matrix(matrix.cols, matrix.rows)
      .map((_, i, j) => matrix.data[j][i]);
  }

  static multiply(a, b) {
    // Matrix product
    if (a.cols !== b.rows) {
      console.log('Columns of A must match rows of B.')
      return;
    }

    return new Matrix(a.rows, b.cols)
      .map((e, i, j) => {
        // Dot product of values in col
        let sum = 0;
        for (let k = 0; k < a.cols; k++) {
          sum += a.data[i][k] * b.data[k][j];
        }
        return sum;
      });
  }

  multiply(n) {
    if (n instanceof Matrix) {
      if (this.rows !== n.rows || this.cols !== n.cols) {
        console.log('Columns and Rows of A must match Columns and Rows of B.');
        return;
      }

      // hadamard product
      return this.map((e, i, j) => e * n.data[i][j]);
    } else {
      // Scalar product
      return this.map(e => e * n);
    }
  }

  map(func) {
    // Apply a function to every element of matrix
    for (let i = 0; i < this.rows; i++) {
      for (let j = 0; j < this.cols; j++) {
        let val = this.data[i][j];
        this.data[i][j] = func(val, i, j);
      }
    }
    return this;
  }

  static map(matrix, func) {
    // Apply a function to every element of matrix
    return new Matrix(matrix.rows, matrix.cols)
      .map((e, i, j) => func(matrix.data[i][j], i, j));
  }

  print() {
    console.table(this.data);
    return this;
  }

  serialize() {
    return JSON.stringify(this);
  }

  static deserialize(data) {
    if (typeof data == 'string') {
      data = JSON.parse(data);
    }
    let matrix = new Matrix(data.rows, data.cols);
    matrix.data = data.data;
    return matrix;
  }
}

if (typeof module !== 'undefined') {
  module.exports = Matrix;
}

```

ga.js

```auto
function nextGen(){
  var bb = [5];// 5 best saved birds
  var bs = [5];// 5 best scores
  for (let i = 0; i < bb.length; i++){// reset all score and birds to 0
    bb[i] = 0;
    bs[i] = 0;
  }
  pipe = [];// clear all pipes
  findBest();// find the top best 5
  for (let i = 0; i < total; i++){
    bird[i] = PickOne();// pick a bird surprisely works fine
  }
  pipe.push(new Pipe());// add pipe
  saved = [];// clear saved
}

function PickOne(){
  let index = random(4);// pick random from best
  let bird = saved[index];// get saved bird
  let child = new Bird(bird.brain);// new bird with that bird brain
  child.mutate();// mutate the new bird
  return child;// return the bird
}

function findBest(){
  for (var i = 0; i < saved.length; i++){// loop through all saved bird
    var sc = saved[i].score;// get score from saved
    console.log(sc);// console log score
    if (sc > bs[0]){// check if score > 0
      bb[4] = bb[3];
      bb[3] = bb[2];
      bb[2] = bb[1];
      bb[1] = bb[0];
      bb[0] = i;
      bs[4] = bs[3];
      bs[3] = bs[2];
      bs[2] = bs[1];
      bs[1] = bs[0];
      bs[0] = sc;
      if (bs[0] > highScore){highScore = bs[0];}// set highScore
    }
    else if (sc > bs[1]){
      bb[4] = bb[3];
      bb[3] = bb[2];
      bb[2] = bb[1];
      bb[1] = i;
      bs[4] = bs[3];
      bs[3] = bs[2];
      bs[2] = bs[1];
      bs[1] = sc;
    }
    else if (sc > bs[2]){
      bb[4] = bb[3];
      bb[3] = bb[2];
      bb[2] = i;
      bs[4] = bs[3];
      bs[3] = bs[2];
      bs[2] = sc;
    }
    else if (sc > bs[3]){
      bb[4] = bb[3];
      bb[3] = i;
      bs[4] = bs[3];
      bs[3] = sc;
    }
    else if (sc > bs[4]){
      bb[4] = i;
      bs[4] = sc;
    }
  }
}

```

---

<div class="post-metadata">

**Author:** ![javagar](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/javagar/32/11434_2.png) [@javagar](https://discourse.processing.org/u/javagar)\
**Post date:** [January 11, 2023, 2:42pm UTC](https://discourse.processing.org/t/flappy-bird-p5-js/40521/2 "2023-01-11T14:42:50Z")

</div>

In the _nn.js file_, you have a definition for `class NeuralNetwork`. Within that definition, you define a `static deserialize(data)` method that includes this statement:

```auto
    let nn = new NeuralNetwork(data.input_nodes, data.hidden_nodes, data.output_nodes);

```

So, whenever you call that method from a `NeuralNetwork` instance, you are creating an additional `NeuralNetwork` instance. Is that what you are intending to do? If so, please explain the purpose of doing this.

---

<div class="post-metadata">

**Author:** ![ctremblay](https://avatars.discourse-cdn.com/v4/letter/c/e495f1/32.png) [@ctremblay](https://discourse.processing.org/u/ctremblay)\
**Post date:** [January 11, 2023, 3:41pm UTC](https://discourse.processing.org/t/flappy-bird-p5-js/40521/3 "2023-01-11T15:41:19Z")

</div>

I pulled the nn and matrix from a tutorial.  
here the video I copied the code from

[![](https://img.youtube.com/vi/c6y21FkaUqw/maxresdefault.jpg "Coding Challenge #100: Neuroevolution Flappy Bird - Part 1") ](https://www.youtube.com/watch?v=c6y21FkaUqw)

---

<div class="post-metadata">

**Author:** ![javagar](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/javagar/32/11434_2.png) [@javagar](https://discourse.processing.org/u/javagar)\
**Post date:** [January 11, 2023, 10:34pm UTC](https://discourse.processing.org/t/flappy-bird-p5-js/40521/4 "2023-01-11T22:34:19Z")

</div>

Thanks for the link to the videos. There’s a lot of content there, and I was unable to find an explanation regarding the `deserialize` method. However, because the method is `static`, and therefore is independent of any particular instance of `NeuralNetwork`, there isn’t a problem of a proliferation of multiple new instances of `NeuralNetwork` being created when deserialization is performed.

Unfortunately, the above does not help with your original issue of an undefined saved score.

---

<div class="post-metadata">

**Author:** ![javagar](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/javagar/32/11434_2.png) [@javagar](https://discourse.processing.org/u/javagar)\
**Post date:** [January 12, 2023, 1:29am UTC](https://discourse.processing.org/t/flappy-bird-p5-js/40521/5 "2023-01-12T01:29:25Z")

</div>

> [@ctremblay](#):
>
> … when i go to save the bird it cant find the saved score. it keeps saying undefined when i console.log.

Is the error occurring with this statement in the _ga.js_ file?:

```auto
    console.log(sc);// console log score

```

If so, then the reason why `sc` is undefined might be here in the `pickOne` function:

```auto
  let index = random(4);// pick random from best
  let bird = saved[index];// get saved bird

```

The `random` function is returning a floating point number that is not suitable as an index. You will need to truncate it to an integer, like this

```auto
  let index = floor(random(5));// pick random from best

```

---

<div class="post-metadata">

**Author:** ![GoToLoop](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/gotoloop/32/86_2.png) [@GoToLoop](https://discourse.processing.org/u/GoToLoop)\
**Post date:** [January 12, 2023, 1:33am UTC](https://discourse.processing.org/t/flappy-bird-p5-js/40521/6 "2023-01-12T01:33:23Z")

</div>

There are many other truncate options in JS btW. Check these 2 examples using JS operators:

1. `const index = ~~random(4);`
2. `const index = random(4) | 0;`

---

<div class="post-metadata">

**Author:** ![javagar](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/javagar/32/11434_2.png) [@javagar](https://discourse.processing.org/u/javagar)\
**Post date:** [January 12, 2023, 1:42am UTC](https://discourse.processing.org/t/flappy-bird-p5-js/40521/7 "2023-01-12T01:42:02Z")

</div>

Be sure to take into account that if there are 5 saved birds, you need to choose among indexes 0, 1, 2, 3, and 4. So in that case, you need to pass `5` to `random`, because the argument is exclusive. Then truncate the result however you choose to do it.

See [random()](https://p5js.org/reference/#/p5/random).

---

<div class="post-metadata">

**Author:** ![GoToLoop](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/gotoloop/32/86_2.png) [@GoToLoop](https://discourse.processing.org/u/GoToLoop)\
**Post date:** [January 12, 2023, 2:10am UTC](https://discourse.processing.org/t/flappy-bird-p5-js/40521/8 "2023-01-12T02:10:01Z")

</div>

And given _saved[]_ is an array, it’s shorter & safer to simply use it as **random()**'s argument:  
`const bird = random(saved);`

---

<div class="post-metadata">

**Author:** ![GoToLoop](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/gotoloop/32/86_2.png) [@GoToLoop](https://discourse.processing.org/u/GoToLoop)\
**Post date:** [January 12, 2023, 2:35am UTC](https://discourse.processing.org/t/flappy-bird-p5-js/40521/9 "2023-01-12T02:35:00Z")

</div>

Some very old Flappy Bird minimalist code: 🐤  
[Flappy Bird](https://forum.processing.org/two/discussion/3580/flappy-code)

There’s also this game sketch. Not Flappy Bird but some concepts are similar: 🦫  
[Hoppy Beaver](https://forum.processing.org/two/discussion/8997/hoppy-beaver#Item_2)

---

<div class="post-metadata">

**Author:** ![ctremblay](https://avatars.discourse-cdn.com/v4/letter/c/e495f1/32.png) [@ctremblay](https://discourse.processing.org/u/ctremblay)\
**Post date:** [January 12, 2023, 2:41am UTC](https://discourse.processing.org/t/flappy-bird-p5-js/40521/10 "2023-01-12T02:41:12Z")

</div>

Thanks ill try all your advice out and report back

---

<div class="post-metadata">

**Author:** ![ctremblay](https://avatars.discourse-cdn.com/v4/letter/c/e495f1/32.png) [@ctremblay](https://discourse.processing.org/u/ctremblay)\
**Post date:** [January 12, 2023, 3:21pm UTC](https://discourse.processing.org/t/flappy-bird-p5-js/40521/11 "2023-01-12T15:21:56Z")

</div>

it says cant find property of undefined brain

```auto
function nextGen(){
  var bb = [5];// 5 best saved birds
  var bs = [5];// 5 best scores
  for (let i = 0; i < bb.length; i++){// reset all score and birds to 0
    bb[i] = 0;
    bs[i] = 0;
  }
  pipe = [];// clear all pipes
  findBest();// find the top best 5
  for (let i = 0; i < total; i++){
    bird[i] = PickOne();// pick a bird surprisely works fine
  }
  pipe.push(new Pipe());// add pipe
  saved = [];// clear saved
}

function PickOne(){
  let index = floor(random(bb.length));// pick random from best
  let bird = saved[index];// get saved bird
  let child = new Bird(bird.brain);// new bird with that bird brain
  child.mutate();// mutate the new bird
  return child;// return the bird
}

function findBest(){
  for (var i = 0; i < saved.length; i++){// loop through all saved bird
    var sc = saved[i].score;// get score from saved
    console.log(sc);// console log score
    if (sc > bs[0]){// check if score > 0
      bb[4] = bb[3];
      bb[3] = bb[2];
      bb[2] = bb[1];
      bb[1] = bb[0];
      bb[0] = i;
      bs[4] = bs[3];
      bs[3] = bs[2];
      bs[2] = bs[1];
      bs[1] = bs[0];
      bs[0] = sc;
      if (bs[0] > highScore){highScore = bs[0];}// set highScore
    }
    else if (sc > bs[1]){
      bb[4] = bb[3];
      bb[3] = bb[2];
      bb[2] = bb[1];
      bb[1] = i;
      bs[4] = bs[3];
      bs[3] = bs[2];
      bs[2] = bs[1];
      bs[1] = sc;
    }
    else if (sc > bs[2]){
      bb[4] = bb[3];
      bb[3] = bb[2];
      bb[2] = i;
      bs[4] = bs[3];
      bs[3] = bs[2];
      bs[2] = sc;
    }
    else if (sc > bs[3]){
      bb[4] = bb[3];
      bb[3] = i;
      bs[4] = bs[3];
      bs[3] = sc;
    }
    else if (sc > bs[4]){
      bb[4] = i;
      bs[4] = sc;
    }
  }
}

```

---

<div class="post-metadata">

**Author:** ![javagar](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/javagar/32/11434_2.png) [@javagar](https://discourse.processing.org/u/javagar)\
**Post date:** [January 12, 2023, 5:04pm UTC](https://discourse.processing.org/t/flappy-bird-p5-js/40521/12 "2023-01-12T17:04:51Z")

</div>

> [@ctremblay](#):
>
> ```auto
> var bb = [5];// 5 best saved birds
> var bs = [5];// 5 best scores
> 
> ```

These statements leave `bb` and `bs` with only one element each, namely the number `5`.

You could do this:

```auto
  var bb = Array(5); // 5 best saved birds
  var bs = Array(5); // 5 best scores

```

---

<div class="post-metadata">

**Author:** ![ctremblay](https://avatars.discourse-cdn.com/v4/letter/c/e495f1/32.png) [@ctremblay](https://discourse.processing.org/u/ctremblay)\
**Post date:** [January 12, 2023, 5:34pm UTC](https://discourse.processing.org/t/flappy-bird-p5-js/40521/13 "2023-01-12T17:34:56Z")

</div>

so var bb = Array(5);  
gives me 5 things?  
on the video later on he used to get 5 items and he give them each numbers  
bb[0], bb[1] ect.

---

<div class="post-metadata">

**Author:** ![GoToLoop](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/gotoloop/32/86_2.png) [@GoToLoop](https://discourse.processing.org/u/GoToLoop)\
**Post date:** [January 12, 2023, 5:55pm UTC](https://discourse.processing.org/t/flappy-bird-p5-js/40521/14 "2023-01-12T17:55:27Z")

</div>

> [@javagar](#):
>
> ```auto
> var bb = Array(5); // 5 best saved birds
> var bs = Array(5); // 5 best scores
> 
> ```

After instantiating an array via its constructor Array(), immediately invoke its method **fill()**:

```auto
const bb = Array(5).fill(), bs = Array(5).fill();

```

The reason to do so is b/c arrays created via Array() are sparse, w/ 100% empty slots:

> **[Indexed collections - JavaScript | MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Indexed_collections#sparse_arrays)**
>
> This chapter introduces collections of data which are ordered by an index value. This includes arrays and array-like constructs such as Array objects and TypedArray objects.

Method **fill()** will populate the whole array, eliminating any empty slots there:

> **[Array.prototype.fill() - JavaScript | MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/fill#using_fill_to_populate_an_empty_array)**
>
> The fill() method of Array instances changes all elements within a range of indices in an array to a static value. It returns the modified array.

And depending on the browser’s engine, it might even internally upgrade a sparse array to its solid version, which is slightly more performant!

And btW, if we know an array will store number values only and it won’t change its _length_ later, it’s preferred to make it a typed array instead:

```auto
const bb = new Uint16Array(5), bs = new Uint16Array(5);

```

> **[TypedArray - JavaScript | MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray)**
>
> A TypedArray object describes an array-like view of an
> underlying binary data buffer.
> There is no global property named TypedArray, nor is there a
> directly visible TypedArray constructor. Instead, there are a number of
> different global...

---

<div class="post-metadata">

**Author:** ![ctremblay](https://avatars.discourse-cdn.com/v4/letter/c/e495f1/32.png) [@ctremblay](https://discourse.processing.org/u/ctremblay)\
**Post date:** [January 12, 2023, 6:30pm UTC](https://discourse.processing.org/t/flappy-bird-p5-js/40521/15 "2023-01-12T18:30:56Z")

</div>

if int bb = is wrong. why did it work in bird under think?

---

<div class="post-metadata">

**Author:** ![GoToLoop](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/gotoloop/32/86_2.png) [@GoToLoop](https://discourse.processing.org/u/GoToLoop)\
**Post date:** [January 12, 2023, 6:55pm UTC](https://discourse.processing.org/t/flappy-bird-p5-js/40521/16 "2023-01-12T18:55:50Z")

</div>

> [@ctremblay](#):
>
> if _int bb = []_ is wrong.

I guess you’ve meant `const`, `let` or `var` instead of `int`, right?

Apart from that, creating an array via `[]` is the most common way to do it in JS.

However, keep in mind that just `[]` is initially an empty array w/ `length = 0`.

---

<div class="post-metadata">

**Author:** ![ctremblay](https://avatars.discourse-cdn.com/v4/letter/c/e495f1/32.png) [@ctremblay](https://discourse.processing.org/u/ctremblay)\
**Post date:** [January 12, 2023, 7:27pm UTC](https://discourse.processing.org/t/flappy-bird-p5-js/40521/17 "2023-01-12T19:27:04Z")

</div>

yes i meant let or var. sry i do js and java and confuse them when in hurry. but still i’m confused why it worked in bird but not in ga

---

<div class="post-metadata">

**Author:** ![GoToLoop](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/gotoloop/32/86_2.png) [@GoToLoop](https://discourse.processing.org/u/GoToLoop)\
**Post date:** [January 12, 2023, 7:47pm UTC](https://discourse.processing.org/t/flappy-bird-p5-js/40521/18 "2023-01-12T19:47:02Z")

</div>

Array creation style like `const arr = [];` is more appropriate for **push()** populate.

While `const NUM = 10, arr = Array(NUM).fill();` style is for _length_ fixed arrays  
and populate using this `for (var i = 0; i < NUM; ++i) arr[i] = new ...;` template.
