Créer un objet javascript Sprite html5 – refactoring du code du jeu Pong




 

Cet article est la suite de Refactoring du code du jeu Pong et de Les namespaces et les objets javascript. Le remaniement du code va consister ici de créer un objet javascript dédiée à la gestion des sprites html5, notamment l’initialisation, le mouvement et la gestion des collisions pour ensuite être intégré au refactoring du code du jeu Pong.

 

Préalablement

Un petit rappel sur l’affichage d’un canvas html5 Afficher des images dans un canvas html5.

 

Que peut on faire avec un sprite html5 ?

L’exercice consiste à énumérer pour un sprite html5 :
– ses caractéristiques qui deviendront ses propriétés;
– les actions que l’ont peut lui appliquer qui deviendront ses méthodes.

Les caractéristiques d’un sprite html5

Un sprite html5 étant un objet graphique que l’on peut mouvoir à l’écran, sa caractéristique la plus évidente semble être l’image qui lui est associée.

Des sprites html5 peuvent aussi avoir des dimensions différentes : deux autres caractéristiques pourraient être sa largeur et sa hauteur.

Un sprite html5 a vocation à bouger à l’écran, il a donc des coordonnées variables matérialisées par sa position dans le référentiel de l’écran : position sur l’axe des X (abscisses) et position sur l’axe des Y (ordonnées).

Les actions d’un sprite html5

Les actions qui dérivent des caractéristiques précédentes et qui permettent de spécifier :
– l’image qui lui est associée;
– ses dimensions;
– sa position sur l’écran.

On peut ajouter la détection d’une collision avec un autre sprite html5.

Bien que non utile dans le cadre du jeu Pong html5, on pourrait ajouter :
– donner un mouvement horizontal;
– donner un mouvement vertical.

 

Le code javascript de l’objet sprite html5

Pourquoi je parle d’objet et non pas de classe ?

Cela résulte de la nature même de javascript qui est un langage objet par prototype et non par classe.

Javascript utilise des objets javascript prototype à partir desquels de objets identiques sont créés.

L’intérêt du prototypage en javascript est de pouvoir modifier un objet issu d’un prototype javascript (modifier ses propriétés et méthodes) sans que cela n’impacte le prototype ou encore les autres objets issus de ce prototype javascript.

La création du prototype

L’idée est de construire un objet prototype sprite utilisable dans tout jeu utilisant des objets graphiques animés.

L’idéal est de créer, en première approche, un namespace dédié au game.sprite. Ce namespace intégrant l’objet javascript sprite et une factory permettant de créer un objet javascript à partir du prototype.

Dans le dossier js du projet, créez un nouveau fichier nommé game.sprite.js qui encapsulera tout le code relatif à la classe sprite :

Le namespace :

var game.sprite = {
}

dans lequel vous intègrez l’objet prototype javascript sprite :

var game.sprite = {
 sprite : {
 },
}

auquel vous ajoutez la factory createSprite :

var game.sprite = {
 sprite : {
 },

 createSprite : function() {
  var sprite = Object.create(this.sprite);
  return sprite;
 }
}

Dans le prototype javascript, vous allez créer et initialiser les propriétés énumérées dans le paragraphe précédent : l’image, la taille et la position.

var game.sprite = {
 sprite : {
  image : null,
  width : null,
  height : null,
  posX : null,
  posY : null
 },

 createSprite : function() {
  var sprite = Object.create(this.sprite);
  return sprite;
 }
}

Il ne reste plus qu’à implémenter les méthodes énumérées aussi dans le paragraphe précédent : spécifier l’image, la taille, afficher le sprite html5, tester les collisions et mouvoir horizontalement et verticalement.

Il suffit d’intégrer ces méthodes dans l’objet sprite du namespace.

Par exemple, ajoutez au constructeur d’objets un paramètre chemin path et instancier l’objet Image à partir de ce chemin :

var game.sprite = {
....

 createSprite : function(imagePath) {
  var sprite = Object.create(this.sprite);
  sprite.image = new Image();
  sprite.image.src = imagePath;
  return sprite;
 }
}

Pour spécifier la taille, rien de complexe :

var game.sprite = {
 sprite : {
  image : null,
  width : null,
  height : null,
  posX : null,
  posY : null,

  setSize : function(width, height) {
   this.width = width;
   this.height = height;
  }
 },

 createSprite : function() {
  var sprite = Object.create(this.sprite);
  return sprite;
 }
}

Pour l’affichage, n’oubliez pas que vous êtes dans un cadre html5 et donc que l’affichage d’un objet graphique se fait par le biais d’un canvas, notamment un html5 canvas context 2d.

C’est le html5 canvas context qui affiche le sprite html5 par le biais de sa méthode drawImage.

La méthode d’affichage (que vous appelerez displayOnCanvasContext) de la classe sprite doit donc utiliser un html5 canvas context pour afficher le sprite.

Donner en paramètre à la méthode displayOnCanvasContext un html5 canvas context parait donc indispensable.

Pourquoi ne pas intégrer le html5 canvas context en propriété de la classe et ainsi éviter ce paramètre dans la méthode displayOnCanvasContext ?

Cela évite le couplage entre le sprite html5 et le canvas : passer le html5 canvas context permet d’afficher le sprite dans tout canvas.

Au sein d’un même jeu, si vous deviez afficher un même sprite html5 dans des canvas différents obligerait à recréer un sprite (une ligne de code supplémentaire) ou bien à ajouter une méthode dans la classe permettant de modifier le html5 canvas context rattaché au sprite html5 (aussi une ligne de code supplémentaire).

La manière de faire que je préconise me semble plus conforme à une bonne pratique et générera un code plus court.

Le code :

var game.sprite = {
 sprite : {
  image : null,
  width : null,
  height : null,
  posX : null,
  posY : null,

  setSize : function(width, height) {
   this.width = width;
   this.height = height;
  },

  showOnCanvasContext = function (canvasContext, x, y) {
   this.posX = x;
   this.posY = y;
   canvasContext.drawImage(this.image, this.posX, this.posY);
  }
 },

 createSprite : function() {
  var sprite = Object.create(this.sprite);
  return sprite;
 }
}

En ce qui concerne les collisions, il suffit de reprendre le code existant dans le jeu Pong et de l’encapsuler dans la méthode strike en adaptant les références.

Souvenez vous du code très spécifique du jeu Pong :

var testerCollisionBalleRaquette = function(positionRaquetteAxeX, positionRaquetteAxeY,
                                                largeurRaquette, hauteurRaquette,
                                                positionBalleAxeX, positionBalleAxeY,
                                                tailleBalle) {
  if ( !( positionRaquetteAxeX >= positionBalleAxeX + tailleBalle 
          || positionRaquetteAxeX <= positionBalleAxeX - largeurRaquette
          || positionRaquetteAxeY >= positionBalleAxeY + tailleBalle 
          || positionRaquetteAxeY <= positionBalleAxeY - hauteurRaquette ) ) {
            // Collision
            return true;
  }
  return false;
}

Plutôt que de mettre tous les paramètres qui correspondent à des propriétés du sprite, mettez en paramètre un objet sprite.
Ensuite faites un copier coller du corps de la fonction dans le corps de la méthode strike, puis remplacez les noms des variables utilisées par les propriétés de la classe :

var game.sprite = {
 sprite : {
  ...

  showOnCanvasContext = function (canvasContext, x, y) {
   this.posX = x;
   this.posY = y;
   canvasContext.drawImage(this.image, this.posX, this.posY);
  },

  strike : function (sprite) {
    if (!(sprite.posX> this.posX + this.width
        || sprite.posX + sprite.width < this.posX
        || sprite.posY > this.posY + this.height
        || sprite.posY + sprite.height < this.posY )) {
        // Collision
        return true;
    }
    return false;
  }

 },

 ...
}

Pour les 2 dernières méthodes, vous n’en avez pas besoin pour le moment. Gardez les sous le coude en les créant sans les implémenter. Le développement itératif fera le reste : vous les implémenterez lorsque vous en aurez besoin :

var game.sprite = {
 sprite : {
  ...

  strike : function (sprite) {
    if (!(sprite.posX> this.posX + this.width
        || sprite.posX + sprite.width < this.posX
        || sprite.posY > this.posY + this.height
        || sprite.posY + sprite.height < this.posY )) {
        // Collision
        return true;
    }
    return false;
  },

  horizontalMove : function () {
  },

  verticalMove = function () {
  }
 },

 ...
}

Le code source de la classe est téléchargeable ici : game.sprite.js.zip.

 

Comment utiliser la classe sprite html5 ?

Dans le contexte du jeu Pong, le sprite html5 de la balle s’initialiserait de la manière suivante en ayant préalablement initialiser un canvas html5 context :

// creation et initialisation
var ball = game.sprite.createSprite("./img/spriteBallSmall.png");
ball.setSize(10, 10);

// affichage
ball.displayOnCanvasContext(canvasRaquettesContext, 300, 300);

Remarquez que l’usage devient plus simple, et plus lisible.

Faites vos remarques ou propositions d’améliorations. Si cet article vous a plu ou aidé, faites le savoir par un commentaire ou sur les réseaux sociaux.

 

Posté dans html5Taggé HTML5, html5 javascript, javascript, refactoring pong html5, refactoring pong javascript, sprites, sprites html5 js  |  2 commentaires

2 réponses à "Créer un objet javascript Sprite html5 – refactoring du code du jeu Pong"

Répondre

*