Un jeu HTML5 : Animation et interactivité

Maintenant que nous savons créer une boucle pour l’animation, un conteneur pour stocker des textures, des sprites animés ou pas, il est temps de nous intéresser à l’interactivité parce que pour un jeu il est nécessaire que le joueur agisse sur tout cela.

La souris et le doigt

Le principal élément d’interaction est la souris pour un desktop et le doigt pour une tablette ou un smartphone. Il n’est pas judicieux d’utiliser le clavier si on veut créer un jeu susceptible d’être utilisé sur tous supports.

JavaScript est bien équipé concernant les événements de souris (et événements tactiles) mais Pixi simplifie la syntaxe.

Prenons un exemple :

<!DOCTYPE HTML>
<html>
<head>
  <title>Cours pixi</title>
  <meta charset="UTF-8">
  <script src="../js/pixi.js"></script>
  <style>
    canvas {
      margin: 0 auto;
      display: block;
    }
  </style>
</head>
<body>
  <script>
    var renderer = PIXI.autoDetectRenderer();
    document.body.appendChild(renderer.view);
    var stage = new PIXI.Container();

    PIXI.loader
      .add('img/image.png')
      .once('complete', setup)
      .load();

    var sprite; 

    function setup() {
      sprite = new PIXI.Sprite(PIXI.loader.resources['img/image.png'].texture);
      sprite.position.set(50, 50);
      sprite.interactive = true;
      sprite.mousedown = onDown;
      sprite.touchstart = onDown;
      stage.addChild(sprite);
    }

    function onDown (eventData) {
      sprite.position.set(getRandomInt(50, 750), getRandomInt(50, 550))
    } 

    function getRandomInt (min, max) {
      return Math.floor(Math.random() * (max - min)) + min;
    };

    gameLoop();

    function gameLoop(){
      requestAnimationFrame(gameLoop);
      renderer.render(stage);
    }
  </script>
</body>
</html>

img01

La plus grande partie de ce code correspond à des choses que nous avons déjà vues dans le deux précédents chapitres et n’hésitez pas à revenir un peu en arrière si des choses ne vous paraissent pas encore claires.

La nouveauté vient du fait qu’on rend le sprite interactif :

sprite.interactive = true;

 Et qu’on met en place deux événements :

sprite.mousedown = onDown; 
sprite.touchstart = onDown;

 On attend donc un clic de souris ou un appui de doigt. Les deux événements sont gérés par la méthode onDown :

function onDown (eventData) {
    sprite.position.set(getRandomInt(50, 750), getRandomInt(50, 550))
}

 Là on positionne le sprite de façon aléatoire. Donc à chaque clic le sprite se déplace n’importe où dans les limites de la scène :

img02

Déplacer un sprite avec la souris

Il arrive souvent pour des jeux d’avoir besoin de déplacer des sprites avec la souris. Voici un exemple de réalisation :

<script>
  var renderer = PIXI.autoDetectRenderer();
  document.body.appendChild(renderer.view);
  var stage = new PIXI.Container();

  PIXI.loader
    .add('img/image.png')
    .once('complete', setup)
    .load();

  var sprite; 
  var followOn;

  function setup() {
    sprite = new PIXI.Sprite(PIXI.loader.resources['img/image.png'].texture);
    sprite.position.set(50, 50);
    sprite.interactive = true;
    sprite.mousedown = initFollow;
    sprite.mouseup = stopFollow;
    sprite.mousemove = follow;
    stage.addChild(sprite);
  }

  function initFollow() {
    followOn = true;
  }

  function stopFollow() {
    followOn = false;
  }

  function follow(mouseData) {
    if(followOn) {
      sprite.x += mouseData.data.originalEvent.movementX;
      sprite.y += mouseData.data.originalEvent.movementY;
    }
  }

  gameLoop();

  function gameLoop(){
    requestAnimationFrame(gameLoop);
    renderer.render(stage);
  }
</script>

img03

J’ai juste prévu les événements de la souris, mais ça serait identique avec les événements tactiles.

Il suffit de cliquer sur le sprite et tant qu’on garde le bouton appuyé le sprite suit les mouvements de la souris, il arrête de les suivre si on relâche le bouton.

La gravité

Un élément important lorsqu’on anime des objets est de tenir compte de la gravité pour obtenir un effet réaliste. Voici un exemple de sprite rebondissant :

<!DOCTYPE HTML>
<html>
<head>
  <title>Cours pixi</title>
  <meta charset="UTF-8">
  <script src="../js/pixi.js"></script>
  <style>
    canvas {
      margin: 0 auto;
      display: block;
    }
  </style>
</head>
<body>
  <script>
    var renderer = PIXI.autoDetectRenderer(600, 400);
    document.body.appendChild(renderer.view);
    var stage = new PIXI.Container();

    PIXI.loader
      .add('img/image.png')
      .once('complete', setup)
      .load();

    var sprite; 

    function setup() {
      sprite = new PIXI.Sprite(PIXI.loader.resources['img/image.png'].texture);
      sprite.position.set(0, 0);
      sprite.gravity = 0.2;
      sprite.bounceFactor = 0.75;
      sprite.vx = 1;
      sprite.vy = 1;
      stage.addChild(sprite);
      gameLoop();
    }

    function play() {
      if(sprite.x < renderer.width - sprite.width) {
        sprite.x += sprite.vx;
        sprite.y += sprite.vy;
        sprite.vy += sprite.gravity;
        if(sprite.y > renderer.height - sprite.height  - sprite.vy) {
          sprite.vy *= -sprite.bounceFactor;
        }  
      }
    }

    function gameLoop(){
      requestAnimationFrame(gameLoop);
      play();
      renderer.render(stage);
    }
  </script>
</body>
</html>

Avec ce code le sprite apparaît à l’origine puis tombe et rebondit jusqu’à atteindre le coin inférieur droit :

img04

Pour le réaliser on a 3 paramètres :

  • la vélocité :

sprite.vx = 1;
sprite.vy = 1;
  •  l’élasticité :
sprite.bounceFactor = 0.75;
  •  la gravité :
sprite.gravity = 0.2;

 La vélocité donne la vitesse de déplacement, la gravité agit comme une accélération et enfin l’élasticité donne le taux de rebondissement. Faites des essais avec d’autre valeurs pour bien comprendre ces paramètres.

Dans un jeu en général on fait une action pour luter contre la gravité et ainsi maintenir l’objet en l’air. Il suffit alors d’intervenir sur la vélocité.

Les boutons

On a aussi besoin de boutons dans un jeu pour toute l’intendance. Pixi est bien équipé aussi pour en créer. regardez cet exemple :

<!DOCTYPE HTML>
<html>
<head>
  <title>Cours pixi</title>
  <meta charset="UTF-8">
  <script src="../js/pixi.js"></script>
  <style>
    canvas {
      margin: 0 auto;
      display: block;
    }
  </style>
</head>
<body>
  <script>
    var renderer = PIXI.autoDetectRenderer(400, 200);
    document.body.appendChild(renderer.view);
    var stage = new PIXI.Container();

    PIXI.loader
      .add('img/button.png')
      .once('complete', setup)
      .load();

    var button; 

    function setup() {
      button = new PIXI.Sprite(PIXI.loader.resources['img/button.png'].texture);
      button.tint = 0x7777dd;
      button.buttonMode = true;
      button.interactive = true;
      button.anchor.set(0.5, 0.5);
      button.position.set(renderer.width / 2, renderer.height / 2);
      button.mouseover = function() { button.tint = 0x00dd00; };
      button.mouseout =  function() { button.tint = 0x7777dd; };
      button.mousedown =  function() { button.tint = 0xff0000; };
      button.mouseup =  function() { button.tint = 0x00dd00; };
      stage.addChild(button);
      gameLoop();
    }

    function gameLoop(){
      requestAnimationFrame(gameLoop);
      renderer.render(stage);
    }
  </script>
</body>
</html>

Au départ le bouton est bleu :

img05

Lorsqu’on le survole avec la souris il devient vert :

img06

Et quand on clique dessus il devient rouge :

img07

Pour créer le bouton il faut un sprite classique, on le rend interactif et en mode bouton :

button.buttonMode = true;
button.interactive = true;

 Il suffit ensuite de lui adjoindre tous les événements que l’on veut :

button.mouseover = function() { button.tint = 0x00dd00; };
button.mouseout = function() { button.tint = 0x7777dd; };
button.mousedown = function() { button.tint = 0xff0000; };
button.mouseup = function() { button.tint = 0x00dd00; };

 Remarquez au passage la possibilité de teinter un sprite en changeant sa propriété tint .

Agir sur un sprite avec un bouton

Maintenant qu’on sait faire bouger des sprite et qu’on sait agir avec des boutons mettons cela ensemble, regardez cet exemple :

<!DOCTYPE HTML>
<html>
<head>
  <title>Cours pixi</title>
  <meta charset="UTF-8">
  <script src="../js/pixi.js"></script>
  <style>
    canvas {
      margin: 0 auto;
      display: block;
    }
  </style>
</head>
<body>
  <script>
    var renderer = PIXI.autoDetectRenderer(400, 300);
    document.body.appendChild(renderer.view);
    var stage = new PIXI.Container();

    PIXI.loader
      .add(['img/image.png', 'img/button.png'])
      .once('complete', setup)
      .load();

    var sprite; 

    function setup() {
      // Sprite
      sprite = new PIXI.Sprite(PIXI.loader.resources['img/image.png'].texture);
      sprite.position.set(50, 50);
      sprite.vx = 2;
      sprite.vy = 2;
      sprite.interactive = true;
      sprite.mousedown = onDown;
      stage.addChild(sprite);

      // Bouton
      button = new PIXI.Sprite(PIXI.loader.resources['img/button.png'].texture);
      button.tint = 0x7777dd;
      button.buttonMode = true;
      button.interactive = true;
      button.scale.set(0.2, 0.2);
      button.position.set(10, renderer.height - button.height - 10);
      button.mouseover = function() { button.tint = 0x00dd00; };
      button.mouseout =  function() { button.tint = 0x7777dd; };
      button.mousedown =  onDown;
      button.mouseup =  function() { button.tint = 0x00dd00; };
      stage.addChild(button);

      gameLoop();
    }

    function onDown() {
      button.tint = 0xff0000;
      sprite.vx *= 1.1;
      sprite.vy *= 1.1;      
    }

    function play() {
      newX = sprite.x + sprite.vx;
      newY = sprite.y + sprite.vy;
      if(sprite.x > renderer.width - sprite.width - sprite.vx || sprite.x < Math.abs(sprite.vx)) {
        sprite.vx = -sprite.vx;
      } else if(sprite.y > renderer.height - sprite.height  - sprite.vy || sprite.y <  - Math.abs(sprite.vy)) {
        sprite.vy = -sprite.vy;
      }  
      sprite.x += sprite.vx;
      sprite.y += sprite.vy;
    }

    function gameLoop(){
      requestAnimationFrame(gameLoop);
      play();
      renderer.render(stage);
    }
  </script>
</body>
</html>

 

Le sprite se déplace en rebondissant sur les bords et lorsqu’on clique sur le bouton il accélère :

img08

Il n’y a rien de nouveau dans le code si ce n’est la gestion des collisions avec les bords qui se résume à deux tests :

if(sprite.x > renderer.width - sprite.width - sprite.vx || sprite.x < Math.abs(sprite.vx)) {
  sprite.vx = -sprite.vx;
} else if(sprite.y > renderer.height - sprite.height  - sprite.vy || sprite.y <  - Math.abs(sprite.vy)) {
  sprite.vy = -sprite.vy;
}

Pour un jeu on organiserait évidemment cela un peu mieux.

En résumé

Dans ce chapitre on a vu :

  • comment gérer la souris ou les événements tactiles.

  • comment agir sur un sprite.

  • comment simuler l’action de la gravité.

  • comment créer des boutons.

  • comment agir sur un déplacement de sprite avec un bouton

Laisser un commentaire