Apprendre comment créer un moteur d'affichage 2D en TypeScript

Partie 2 : charger une texture

Pour réagir au contenu de ce tutoriel, un espace de dialogue vous est proposé sur le forum. 14 commentaires Donner une note  l'article (5)

Article lu   fois.

L'auteur

Profil Pro

Liens sociaux

Viadeo Twitter Facebook Share on Google+   

I. Barista part II

I-A. Charger une texture

Voir le code : GitHub


Cliquez pour lire la vidéo


En JavaScript (et donc en Typescript), il est très simple de charger une image, aussi appelée texture dans le domaine du jeu vidéo, d’ailleurs nous utiliserons ce terme dorénavant. Il y a plusieurs façons de faire, pour le besoin de ce chapitre, nous utiliserons la plus simple qui est d’inclure les images directement dans la structure HTML. Il nous suffira alors de démarrer le script au chargement complet de la page et pour ça, nous utiliserons l’événement natif de l’objet « window » à savoir « load ».

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
function init(){
    const canvas = getCanvas();
    const context  = getContext(); 

    // on détermine les dimensions du canvas
    canvas.width = 640;
    canvas.height = 480;

    // on sauvegarde le contexte
    context.save();

    // on va incorporer nos opérations de dessin ici


    // on restaure le contexte
    context.restore();
}

function getContext(){
    return getCanvas().getContext("2d");
}

function getCanvas(){
    return document.querySelector("canvas");    
}

window.addEventListener("load", init);
 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Barista</title>
    <script src="./dist/main.js"></script>
</head>
<body>
    <canvas id="barista"></canvas>
    <img src="kirby.png" />
</body>
</html>

I-B. Dessiner une texture

Pour dessiner une texture, l’API de dessin de canvas embarque une méthode dont voici la première signature possible :

context.drawImage(image,dx,dy)

  • le paramètre image représente la texture que l’on souhaite dessiner ;
  • les paramètres dx et dy représentent les coordonnées auxquelles on souhaite dessiner l’image.

Cette méthode vous permettra de dessiner directement la texture sur le canvas, sans aucune transformation.

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
function init(){
    const canvas = getCanvas();
    const context  = getContext(); 

    // on détermine les dimensions du canvas
    canvas.width = 640;
    canvas.height = 480;

    // on sauvegarde le contexte
    context.save();

    // on récupère l'élément html de type image qui nous sert de texture (ici kirby)
    const kirby = document.querySelector("img"); 

    // puis on le dessine à l'aide de la méthode drawImage de l'objet de type context
    context.drawImage(kirby, 0, 0);


    // on restaure le contexte
    context.restore();
}

function getContext(){
    return getCanvas().getContext("2d");
}

function getCanvas(){
    return document.querySelector("canvas"); 
}

window.addEventListener("load", init);

I-C. Méthodes de dessin avancées

Jusqu’ici, nous avons vu la méthode classique pour dessiner une texture, nous allons à présent faire un tour du côté des méthodes de dessin avancées en commençant par dessiner une texture à la taille que l’on souhaite obtenir. Pour ce faire, nous allons voir la deuxième manière d'appeler la méthode context.drawImage() :

context.drawImage(texture, dx, dy, dw, dh)

  • le paramètre texture représente la texture que l’on souhaite dessiner ;
  • les paramètres dx, dy, dw et dh représentent un rectangle de largeur dw et de hauteur dh dont le coin en haut à gauche est situé en dx et dy. Ce rectangle représente les nouvelles dimensions de la texture au sein du canvas.
 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
function init(){
    const canvas = getCanvas();
    const context  = getContext(); 

    // on détermine les dimensions du canvas
    canvas.width = 640;
    canvas.height = 480;

    // on sauvegarde le contexte
    context.save();

    // on récupère l'élément html de type image qui nous sert de texture (ici kirby)
    const kirby = document.querySelector("img"); 

    // puis on réalise le dessin à l'aide de la méthode drawImage de l'objet de type context
    // on dessine cette texture à partir des coordonnées x = 10 et y = 35
    // la nouvelle largeur de la texture est de 200px et la nouvelle hauteur vaut 20px
    context.drawImage(kirby, 10, 35, 200,20);

    // on restaure le contexte
    context.restore();
}

function getContext(){
    return getCanvas().getContext("2d");
}

function getCanvas(){
    return document.querySelector("canvas"); 
}

window.addEventListener("load", init);

Ici, on dessine notre texture aux coordonnées x = 10px, y = 35px et on applique une transformation à cette texture afin qu’elle soit dessinée avec 200px de largeur et 20px de hauteur. Nous allons maintenant voir comment dessiner une portion de notre texture et pour cela, nous allons étudier la troisième et dernière signature possible de la méthode context.drawImage() :

context.drawImage(texture, sx, sy, sw, sh, dx, dy, dw, dh)

  • le paramètre texture représente la texture que l’on souhaite dessiner ;
  • les paramètres sx, sy, sw et sh représentent un rectangle dont les dimensions correspondent à une portion de la texture originelle ;

    Image non disponible
  • les paramètres dx, dy, dw et dh représentent les nouvelles dimensions de la portion de texture originelle au sein du canvas.
 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
function init(){
    const canvas = getCanvas();
    const context  = getContext(); 

    // on détermine les dimensions du canvas
    canvas.width = 640;
    canvas.height = 480;

    // on sauvegarde le contexte
    context.save();

    // on récupère l'élément html de type image qui nous sert de texture (ici kirby)
    const kirby = document.querySelector("img"); 

    // puis on le dessine à l'aide de la méthode drawImage de l'objet de type context
    // on dessine la portion de l'image originelle comprise entre les coordonnées x = 0, y = 0, x = 100, y = 100
    // on dessine cette portion de façon un peu déformée
    context.drawImage(kirby, 0,0, 100, 100, 30,30,250,250);

    // on restaure le contexte
    context.restore();
}

function getContext(){
    return getCanvas().getContext("2d");
}

function getCanvas(){
    return document.querySelector("canvas"); 
}

window.addEventListener("load", init);

Cette portion correspond à un carré de 100px de côté et dont le coin en haut à gauche est situé aux coordonnées x = 0px et y = 0px.

Cette portion d’image sera dessinée sur le canvas dans un carré de 250px de côté et dont le coin en haut à gauche est situé aux coordonnées x = 30px et y = 30px.

I-D. Ombres portées

Maintenant, nous allons pouvoir passer au dessin avec des ombres, nous allons donc nous intéresser aux propriétés : shadowColor, shadowBlur, shadowOffsetX et shadowOffsetY de l’objet context. Ces propriétés peuvent être utilisées avec les méthodes de dessin classiques, avec ou sans texture.

  • La propriété shadowOffsetX sert à définir le décalage en x que l’ombre aura par rapport au dessin, le type de cette propriété est un entier.
  • La propriété shadowOffsetY sert à définir le décalage en y que l’ombre aura par rapport au dessin, le type de cette propriété est un entier.
  • La propriété shadowColor, comme son nom l’indique, définit la couleur de l’ombre, le type de cette propriété est une chaîne.
  • La propriété shadowBlur, elle, sert à spécifier la netteté (ou plus spécifiquement le flou) que l’on souhaite appliquer à cette ombre, le type de cette propriété est un entier.
 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
function init(){
    const canvas = getCanvas();
    const context  = getContext(); 

    // on détermine les dimensions du canvas
    canvas.width = 640;
    canvas.height = 480;

    // on sauvegarde le contexte
    context.save();

    // on récupère l'élément html de type image qui nous sert de texture (ici kirby)
    const kirby = document.querySelector("img"); 

    // on définit les propriétés de l'ombre portée pour tous les dessins 
    // qui vont suivre. 

    context.shadowBlur = 10; 
    context.shadowColor = "#ff0000"; // l'ombre sera rouge
    context.shadowOffsetX = 10; // ombre décalée de 10px vers la droite 
    context.shadowOffsetY = 10; // ombre décalée de 10px vers le bas 


    // puis on le dessine à l'aide de la méthode drawImage de l'objet de type context
    // on dessine la portion de l'image originelle comprise entre les coordonnées x = 0, y = 0, x = 100, y = 100
    // on dessine cette portion de façon un peu déformée
    context.drawImage(kirby, 0,0, 100, 100, 30,30,250,250);

    // on restaure le contexte
    context.restore();
}

function getContext(){
    return getCanvas().getContext("2d");
}

function getCanvas(){
    return document.querySelector("canvas"); 
}

window.addEventListener("load", init);

I-E. Dessiner à travers un masque

Nous allons à présent apprendre à dessiner à travers un masque. Pour cela, nous allons avoir besoin de la propriété globalCompositeOperation de l’objet context. Cette propriété peut prendre plusieurs valeurs dont les résultats sont illustrés à l’aide du graphique ci-dessous :

[ALT-PASTOUCHE]

Canvas autorise plusieurs modes de fusion. Le mode de fusion correspond à la façon dont la source interagit avec la destination. Ici, le carré bleu est ce qui a déjà été dessiné, il s'agit de la source. Le cercle rouge, quant à lui, correspond à la destination.

Comment interpréter ce graphique ? En premier lieu, il faut que je vous donne le code source qui va avec :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
function init(){
    const canvas = getCanvas();
    const context  = getContext(); 

    // on détermine les dimensions du canvas
    canvas.width = 640;
    canvas.height = 480;

    // on sauvegarde le contexte
    context.save();

    // on récupère l'élément html de type image qui nous sert de texture (ici kirby)
    const kirby = document.querySelector("img"); 

    // on définit les propriétés de l'ombre portée pour tous les dessins 
    // qui vont suivre. 

    context.shadowBlur = 10; 
    context.shadowColor = "#ff0000"; // l'ombre sera rouge
    context.shadowOffsetX = 10; // ombre décalée de 10px vers la droite 
    context.shadowOffsetY = 10; // ombre décalée de 10px vers le bas 

    // on va dessiner notre kirby à travers un masque circulaire
    // commençons par dessiner le cercle en question 

    context.beginPath();
    context.fillStyle = "red"; // ici peu importe la couleur du moment que le cercle est plein
    context.moveTo(225,225); 
    context.arc(225,255,125, 0, 360 * Math.PI / 180); 
    context.fill();

    // une fois notre cercle dessiné, on change le mode de fusion
    // de la balise canvas pour le définir à source-in. 
    // tous les dessins qui vont suivre seront dessinés à travers un masque

    context.globalCompositeOperation = "source-in";


    // puis on le dessine à l'aide de la méthode drawImage de l'objet de type context
    context.drawImage(kirby, 0,0);

    // on restaure le contexte
    context.restore();
}

function getContext(){
    return getCanvas().getContext("2d");
}

function getCanvas(){
    return document.querySelector("canvas"); 
}

window.addEventListener("load", init);

Il s’agit d’une opération en deux étapes :

  • tout d’abord, on dessine le masque sur l’objet context (ici le cercle) ;
  • ensuite, on spécifie la valeur de la propriété globalCompositeOperation de l’objet context (ici source-in) ;
  • puis, on dessine le contenu que l’on souhaite voir apparaître à travers le masque (kirby).

Il suffit de changer la valeur de la propriété globalCompositeOperation pour pouvoir obtenir tous les résultats retranscrits sur le graphique. Pour dessiner un objet à travers un masque, la valeur qui nous intéresse est source-in. Voilà, les bases du dessin de texture ont été passées en revue !

Image non disponible

II. Remerciements Developpez.com

Nous tenons à remercier Nicolas Legrand qui nous a aimablement autorisés à publier son tutoriel. Nos remerciements également à Yahiko pour la relecture technique, Malick pour la mise au gabarit et Escartefigue pour la relecture orthographique.

Vous avez aimé ce tutoriel ? Alors partagez-le en cliquant sur les boutons suivants : Viadeo Twitter Facebook Share on Google+   

En complément sur Developpez.com

  

Copyright © 2020 Nicolas Legrand. Aucune reproduction, même partielle, ne peut être faite de ce site ni de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.