Skip to content

Sprite, niveau et collision

Objectifs

  • Créer un sprite
  • Créer un niveau
  • Gérer les collisions
  • Utiliser la documentation
  • Formater et organiser le code

Théorie

Sprite

Un sprite est une image qui représente un objet dans un jeu vidéo. Par exemple, dans un jeu de plateforme, les personnages, les ennemis, les pièces, etc. sont des sprites.

Ils peuvent être statiques ou animés. Dans le cas d'un sprite animé, il s'agit d'une succession d'images qui donne l'illusion du mouvement.

Kaboom

Initialisation

Pour utiliser la bibliothèque Kaboom, il faut d'abord commencer par l'initialiser avec la fonction kaboom().

js
kaboom({
  background: [227, 242, 253], 
  width: 640,
  height: 480,
});

// Supprimez la ligne suivante dans votre code,
// déplacez le code couleur dans le kaboom()
add(["background", rect(width(), height()), color(227, 242, 253)]); 

Le code ci-dessus initialise une scène de 640x480 pixels avec un fond bleu clair.

Add

Pour ajouter un objet dans la scène, on utilise la fonction add() qui prend un tableau de composants en paramètre :

js
const player = add([
  "player", // les chaines de caractères sont des tags pour identifier l'objet
  "friendly", // on peut ajouter plusieurs tags
  rect(40, 40), // c'est un rectangle de 40x40 pixels
  color(244, 67, 54), // la couleur rgb du rectangle
  pos(128, 256), // la position du rectangle dans la scène
  area(), // défini le masque de collision (hitbox)
  body(), // applique la physique à l'objet

  rotate(0), // rotation en degrés
  opacity(1), // opacité entre 0 et 1
  anchor("center"), // point d'ancrage (l'origine de l'objet)
  // et bien d'autres...
]);

Documentation

Toutes les fonctions et composants sont documentés sur le site de Kaboom, par exemple pour body() :

  • La liste des paramètres possibles : options?: BodyCompOpt
    js
    body({
      isStatic: true, // objet statique (ne bouge pas)
      jumpForce: 128, // vitesse des sauts
      // ...
    });
  • La liste des fonctions disponibles une fois ajouté à l'objet : BodyComp
    • body() ajoute les fonctions .move(), .jump(), .isGrounded(), etc.

Javascript

Fonction

Dans le code suivant qui permet de faire sauter un personnage, nous utilisons une fonction :

js
onKeyPress("space", () => {
  player.jump();
});

onKeyPress est une fonction qui permet de définir une action lorsqu'une touche est pressée. Elle prend deux paramètres :

  • le nom de la touche
  • une fonction qui sera exécutée lorsque la touche est pressée

La syntaxe () => { ... } permet de définir une fonction anonyme qu'on peut passer en paramètre.

Pratique

Sprite

  • Créez un dossier sprites dans le dossier projet-jeu

  • Créez un sprite sur Piskel (ou un autre logiciel de dessin) et exportez-le en GIF dans le dossier sprites

    • Commencez par choisir la taille de votre sprite : 40x40 pixels
    • Dessinez votre sprite (pour votre personnage principal)
    • Exportez-le en GIF et mettez le dans le dossier sprites en le renommant player.gif
  • Pour charger le sprite dans votre code (mettez-le juste après le kaboom())

    js
    kaboom({
      background: [0, 0, 0],
      width: 640,
      height: 480,
    });
    
    loadSprite("player", "sprites/player.gif"); 
    • player est l'identifiant du sprite (le nom que vous lui donnez)
    • sprites/player.gif est le chemin vers le fichier GIF
    • Vous allez utiliser l'identifiant à chaque fois que vous souhaitez utiliser ce sprite dans votre code
  • Vous pouvez désormais l'utiliser dans votre code (remplacez les lignes en rouge par les lignes en vert)

    js
    const player = add([
      "player",
      circle(32), 
      color(244, 67, 54), 
      sprite("player", { width: 40, height: 40 }), 
      pos(128, 256),
      area(),
      body(),
    ]);

Formater le code

Formater le code permet de le rendre plus lisible et plus facile à comprendre en étant régulier dans la mise en forme.

Vous pouvez formatter votre code directement dans Visual Studio Code en utilisant le raccourci Alt+Shift+F.

Vous pouvez utiliser Prettier pour formater votre code.

  • Coller votre code dans la fenêtre de gauche
  • Le code formaté apparaît dans la fenêtre de droite

Niveau

Au lieu de positioner chaque élément du niveau avec des coordonnées, on peut aussi utiliser une "grille" pour définir le niveau.

On va choisir une taille de case de 40x40 pixels, ce qui vous fait 16x12 cases. On va ensuite définir le niveau avec des symboles.

Rajoutez les lignes suivantes dans votre code à la suite :

js
const level = addLevel(
  [
    "                ",
    "                ",
    "                ",
    "                ",
    "                ",
    "                ",
    "                ",
    "     ^          ",
    "    ===         ",
    "                ",
    " @     ^  $ $ $ ",
    "================",
  ],
  {
    tileWidth: 40,
    tileHeight: 40,
    tiles: {
      "@": () => [
        "player",
        circle(20),
        color(33, 150, 243),
        area(),
        body(),
        anchor("topleft"),
      ],
      "=": () => [
        "grass",
        rect(40, 40),
        color(27, 94, 32),
        outline(),
        area(),
        body({ isStatic: true }),
        anchor("topleft"),
      ],
      $: () => [
        "coin",
        circle(20),
        color(253, 216, 53),
        area(),
        anchor("topleft"),
      ],
      "^": () => [
        "danger",
        rect(40, 40),
        color(244, 67, 54),
        area(),
        anchor("topleft"),
      ],
    },
  }
);

Supprimez (ou commentez avec /* ... */) vos précédents objets ajoutés avec add().

Pour récupérer notre personnage afin de lui ajouter des actions (par exemple le saut), nous pouvons utiliser la fonction .get() sur notre variable level :

js
const player = add([ 
  "player", 
  sprite("player", { width: 40, height: 40 }), 
  pos(128, 256), 
  area(), 
  body(), 
]); 

const level = addLevel(
  ...
);

const player = level.get("player")[0]; 

La fonction .get() renvoie un tableau avec tous les éléments qui ont "player" comme tag. Dans notre cas, il n'y a qu'un seul élément qui correspond à la recherche, donc nous pouvons récupérer le premier élément du tableau avec [0].

Migrer tout votre précédent code dans le niveau (plus aucun add() dans votre code).

Organisation du code

Prenez le temps de réorganiser votre code pour le rendre plus lisible. Notamment pour l'ordre des déclarations :

  • Initialisation de Kaboom
  • Chargement des sprites
  • Définition des paramètres globaux (par exemple la gravité)
  • Définition des niveaux
  • Définition des actions (doit être après les niveaux car besoin de récupérer les éléments du niveau, p. ex. player)

Exemple organisation

Collision

Pour détecter les collisions entre deux éléments, nous pouvons utiliser la fonction .onCollide(). Pour définir ce qu'on fait lorsque un élément avec le tag "player" entre en collision avec un élément avec le tag "danger", nous pouvons écrire :

js
onCollide("player", "danger", (player, danger) => {
  addKaboom(player.pos);
});

Faites en sorte que votre personnage meurt lorsqu'il entre en collision avec un élément avec le tag "danger". Vous pouvez utiliser la fonction destroy() pour supprimer un élément.

Solution
js
onCollide("player", "danger", (player, danger) => {
  addKaboom(player.pos);
  player.destroy();
});

Faites en sorte que votre personnage ramasse les pièces lorsqu'il entre en collision avec un élément avec le tag "coin".

Indice

La pièce est détruite lorsqu'elle entre en collision avec le personnage.

Exemple avec collision

Saut simple

Pour faire sauter le personnage, nous avons utilisé la fonction .jump() :

js
onKeyPress("space", () => {
  player.jump();
});

Faites en sorte que le personnage puisse sauter qu'une seule fois.
Vous pouvez utiliser la fonction .isGrounded() pour savoir si le personnage touche le sol.

Indice

L'idée est de pouvoir sauter uniquement si le personnage touche le sol.

Solution
js
onKeyPress("space", () => {
  if (player.isGrounded()) {
    player.jump();
  }
});

Checkpoint

Exemple
js
kaboom({
  background: [227, 242, 253],
  width: 640,
  height: 480,
});

setGravity(1600);

const level = addLevel(
  [
    "                ",
    "                ",
    "                ",
    "                ",
    "                ",
    "                ",
    "                ",
    "     ^          ",
    "    ===         ",
    "                ",
    " @     ^  $ $ $ ",
    "================",
  ],
  {
    tileWidth: 40,
    tileHeight: 40,
    tiles: {
      "@": () => [
        "player",
        circle(20),
        color(33, 150, 243),
        area(),
        body(),
        anchor("topleft"),
      ],
      "=": () => [
        "grass",
        rect(40, 40),
        color(27, 94, 32),
        outline(),
        area(),
        body({ isStatic: true }),
        anchor("topleft"),
      ],
      $: () => [
        "coin",
        circle(20),
        color(253, 216, 53),
        area(),
        anchor("topleft"),
      ],
      "^": () => [
        "danger",
        rect(40, 40),
        color(244, 67, 54),
        area(),
        anchor("topleft"),
      ],
    },
  }
);

onCollide("player", "danger", (player, danger) => {
  addKaboom(player.pos);
});

onCollide("player", "coin", (player, coin) => {
  coin.destroy();
});

const player = level.get("player")[0];

onKeyPress("space", () => {
  player.jump();
});

onKeyDown("right", () => {
  player.move(256, 0);
});

onKeyDown("left", () => {
  player.move(-256, 0);
});
html
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width" />
    <title>Kaboom</title>
    <script src="https://unpkg.com/kaboom@3000.1/dist/kaboom.js"></script>
  </head>
  <body>
    <script src="game.js"></script>
  </body>
</html>

Références