Game in canvas !

f

Rebond : class

Class : Gravity


L'idée est de simuler la chute d'un objet.

La chute ne doit pas être linéaire mais accélérée.

Physique




Équation

A chaque itération, il suffit d'appliquer les équations suivantes :

    gravitySpeed += gravity;

    y += gravitySpeed;


Avec les valeurs de simulation suivantes, on voit clairement que durant :

  •  les dix premières itérations l'objet passe de la position 1 à 6 
  •  les dix itérations suivantes l'objet passe de la position 6  à 22
  •  de l'itération 60 à 70 l'objet passe de la position de 183 à 249


                    Frame 1 : y = 1 (valeur tronquée)
(index):186 Frame 2 : y = 1
(index):186 Frame 3 : y = 1
(index):186 Frame 4 : y = 1
(index):186 Frame 5 : y = 2
(index):186 Frame 6 : y = 3
(index):186 Frame 7 : y = 3
(index):186 Frame 8 : y = 4
(index):186 Frame 9 : y = 5
(index):186 Frame 10 : y = 6
(index):186 Frame 11 : y = 7
(index):186 Frame 12 : y = 8
(index):186 Frame 13 : y = 10
(index):186 Frame 14 : y = 11
(index):186 Frame 15 : y = 12
(index):186 Frame 16 : y = 14
(index):186 Frame 17 : y = 16
(index):186 Frame 18 : y = 18
(index):186 Frame 19 : y = 20
(index):186 Frame 20 : y = 22
...
(index): 186Frame 60 : y = 183
(index):186 Frame 61 : y = 190
(index):186 Frame 62 : y = 196
(index):186 Frame 63 : y = 202
(index):186 Frame 64 : y = 208
(index):186 Frame 65 : y = 215
(index):186 Frame 66 : y = 222
(index):186 Frame 67 : y = 228
(index):186 Frame 68 : y = 235
(index):186 Frame 69 : y = 242
(index):186 Frame 70 : y = 249

L'objet chute :

  • durant les dix premières itérations l'objet chute de ( 6 - 1) 5px, 
  • de l'itération 60, la chute sera de (249 - 183 ) 66px 
  • et à partir de l'itération 1000, l'objet chute à une très grande vitesse (or, nous savons qu'il existe une vitesse limite de chute qui est du au freinage des frottement)


Code


class GravityBloc extends AnimatedBloc {

  constructor(elt, {
    speed
  }) {
    super(elt, {
      speed
    });

    this.gravity = 0.1;
    this.gravitySpeed = 0;
  }

  static construct(elt, {
    speed = 0
  } = {}) {

    return new GravityBloc( elt, speed );
  }


  update() {

    super.update();
    
    this.gravitySpeed +=this.gravity;
    this.y += this.gravitySpeed;

  }

}


Animation : class

Pour obtenir un temps écoulé :

let startTime = new Date().getTime();
function main() {

 //pour avoir un temps de simu depuis le départ
   let currTime = new Date().getTime(),
       dt = ((currTime - startTime)/1000);
       
  update(dt);
  render();

  requestId = window.requestAnimationFrame(main);
}

temps quasi constant


function main() {

  let now = Date.now(),
    dt = (now - lastTime) / 1000.0;
       
  update(dt);
  render();
  lastTime = now;
  requestId = window.requestAnimationFrame(main);

}

on pourra écrire la classe suivante :

class Oxilo extends AnimatedBloc {

  constructor(elt, { speed }) {
    
    super(elt, {
      speed
    });
  }

  static construct(elt, { speed = 1 } = {}) {
    return new Oxilo(elt, { speed });
  }

  update(dt) {   
   this.x = Math.cos(2*Math.PI*(dt))*50;
   this.y = Math.sin(Math.PI*(dt))*50;
  }

}


animation : class

Élément de base

class AnimatedBloc {

  constructor(elt, {speed = 1} = {} ) {

    this.elt = elt;

    // initial CSS
    this.initPosition( speed );
  }

  initPosition( speed ) {

    if (this.elt) {
      const {
        left,
        top
      } = this.elt.getBoundingClientRect();

      // CSS
      this.cssX = left;
      this.cssY = top;

      this.x = 0;
      this.y = 0;
      
      this.speed = speed;
    }
  }

  render() {
    this.elt.style.cssText = `left:${this.x+this.cssX}px`;
    //ctx.drawImage(Resources.get(this.sprite), this.x, this.y);
  }
  
  update() {
    this.x = this.x + this.speed;
  }

}

Héritage

class BouncingBloc extends AnimatedBloc {

  constructor(elt, {speed = 3, at = 300 } = {} ) {
    super(elt, {speed});

    this.boundary = at;
  }


  update() {
    
    super.update();

    if (this.x >= this.boundary || this.x == 0) {
      this.speed *= -1;
      this.elt.classList.toggle("bouncing");
    }


  }

}

heritage : class

Passage par défault

class Player {

 constructor({
    keysMap = new Map([
      ["up", "ArrowUp"],
      ["right", "ArrowRight"],
      ["down", "ArrowDown"],
      ["left", "ArrowLeft"],
    ]),
    x = 20,
    y = 20,
    speed = 0.5,
  } = {}) {

    Object.assign(this, { touches, x, y, speed });
    ...
    this.moveX = 0;
    this.moveY = 0;
    

  }
  ...
}


https://es6console.com/jpcwjhve/

------------ Amélioration du code

Méthode static !

class Player {

  constructor( {keysMap, x, y, speed} ) {

    Object.assign(this, {
      keysMap,
      x,
      y,
      speed
    });

    this.moveX = 0;
    this.moveY = 0;

    ...

  }
  static create({
    keysMap = new Map([
      ["ArrowUp", "up"],
      ["ArrowRight", "right"],
      ["ArrowDown", "down"],
      ["ArrowLeft", "left"],
    ]),
    x = 100,
    y = 100,
    speed = 0.5,
  } = {}) {

    return new Player({keysMap, x, y, speed})

  }
...
}

appel

Player.create();

Player.create({
    keysMap: new Map([
      ["z", "up"],
      ["d", "right"],
      ["x", "down"],
      ["q", "left"],
    ]),
    speed: 2
  });
  
https://es6console.com/jpdtv6zx/

Game

itérator

Ne marche pas si appellé deux fois

const dateRange = {
  from: new Date(2018, 0, 23),
  to: new Date(2018, 3, 28),
  [Symbol.iterator]() {
    this.current = this.from

    return this
  },
  next() {
    if (this.current <= this.to) {
      this.current.setDate(this.current.getDate() + 1)

      return {
        done: false,
        value: new Date(this.current)
      }
    }

    return {
      done: true
    }
  }
}

const dateList = Array.from(dateRange);

dateList.forEach(date => {
    console.log(date.toString())
})


Getter et Setter d'une classe

La syntaxe set permet de lier une propriété d'un objet à une fonction qui sera appelée à chaque tentative de modification de cette propriété.

Exemple : 

class CodeSecret {

  constructor(num) {
    // invokes the setter
    this.code = num;

  }

  set code(num) {
   
    if ( !/^ISBN/.test(num)) {
      console.log("votre code doit commencer par ISBN");
      return;
    }
    this._code = num;

  }


  get code() {
    return this._code;
  }

}

let t = new CodeSecret("dD1");

https://es6console.com/jpbn7x38/