Les TP de JavaScript se déroulent sur ce logiciel appelé « Moodle ».
Vous devez travailler connectés (lien « Connexion » en haut à droite
de la page). Sinon, vous rencontrerez des problèmes d'avancement et
vous risquez d'être comptés absent. En étant connectés vous retrouverez
l'endroit où vous en
étiez à la séance suivante.
Dans ces TP, vous trouverez des explications à lire, des questions à répondre et des exercices plus libres.
Prenez le temps de réfléchir par vous même avant de répondre à une question. Le but n'est pas de trouver la bonne réponse, mais de comprendre et apprendre. Ne vous contentez pas de recopier les réponses de vos voisins.
Ces TP ne sont PAS notés. Les notes affichées par le logiciel ne comptent pas dans votre évaluation.
N'hésitez pas à appeler votre enseignant. Il est là pour vous aider.
Moodle permet à chacun d'évoluer à son propre rythme. Certains avanceront plus ou moins rapidement. Finissez chaque sujet avant de passer au suivant. Si vous sautez des questions, vous risquez de ne plus comprendre.
A gauche, en haut de la page vous trouverez un menu qui vous permet d’accéder aux différentes parties de chaque sujet.
Ces TP sont prévus pour Firefox sous Linux, pas pour Windows.
Ce sujet revoit les notions vues en S2.
L'aide mémoire du S2 se trouve ici:
https://moodle.iutv.univ-paris13.fr/mcustom/course-selected-pages.php?courseId=23
C'est une très bonne idée de le garder toujours ouvert dans un onglet. Vous en aurez souvent besoin!
Dans cette partie on va rapidement se rafraîchir la mémoire.
Le HTML est juste du texte. Le navigateur lit ce texte et le construit un arbre DOM.
En JS, on manipule cet arbre DOM.
<body>
<p>
Un exemple de page en html.<br/>
<img src="photo.jpg" alt="photo"/>
</p>
<ul>
<li>pomme</li>
<li>fraise</li>
</ul>
</body>
Remarque: dans ces schémas, on ne tient pas compte du texte.
<!DOCTYPE html>(<!DOCTYPE> n'est pas dans l'arbre)
<html>
<head>
<meta charset="utf-8"/>
<title>Exemple</title>
</head>
<body>
<h1>Bonjour!</h1>
</body>
</html>
Écrivez le HTML correspondant à cet arbre.
(n'oubliez pas de fermer les balises)
Les balises <span> et <div> servent à regrouper du texte et des balises.
<span> est "inline" et <div> est "block" (on verra ces notions bientôt)
Pour simplifier:
<span> est utilisé lorsqu'on veut regrouper des petits bouts de texte (à l'intérieur d'une même ligne).
<div> est utilisé lorsqu'on veut regrouper de plus grands blocks, qui s'affichent sur plusieurs lignes.
Par exemple :
L'utilisateur <span class="utilisateur">Wang</span> est connecté depuis 3h.
<div id="presentation">
<h2>Pingouins</h2>
<p>Les pingouins cherchant leur nourriture dans les eaux maritimes et océaniques froides</p>
</div>
Certains éléments HTML prennent au moins une ligne entière. On les appelle des éléments "block". Si vous mettez plusieurs éléments block d'affilé, ils seront affichés sur des lignes différentes.
D'autres éléments HTML s'affichent à l'intérieur d'un ligne, de gauche à droite (inline), comme du texte.
Parmi les éléments suivants, lesquels prennent au moins toute une ligne (block) ?
HTML:
<p>
La souris se trouve à la position
x=<AAA class="coord">123</AAA>,
y=<AAA class="coord">432</AAA>
</p>
On peut aussi spécifier directement du CSS à l’intérieur du HTML en utilisant l'attribut style:
<h1 style="background-color: blue">Bonjour!</h1>
Ceci n'est pas très utilisé quand on écrit du HTML, mais est très utilisé quand on manipule le DOM en JS.
<p>Que faut-il écrire dans le fichier CSS pour afficher "Voiture" en rouge ?
<span id="velo">Vélo</span>,
<span id="voiture">Voiture</span>,
<span id="avion">Avion</span>
</p>
En CSS, il ne doit pas y avoir de « ; » à la fin, après la déclaration.
Ce que vous avez indiqué veut bien dire "afficher en rouge", mais il manque quelque chose.
Vous n'avez pas dit au navigateur qu'est-ce qu'il doit afficher en rouge.
Presque. Souvenez vous qu'un "." dans un sélecteur CSS veut dire "Tous les éléments ayant class=(...)"
Presque! La réponse commence bien par:
#voiture{color ...
Le problème est après.
<p>CSS:
<span AAA="aliment">Chocolat</span>,
<span AAA="vehicule">Vélo</span>,
<span AAA="aliment">Fraise</span>,
<span AAA="vehicule">Voiture</span>,
<span AAA="vehicule">Avion</span>
<span AAA="aliment">Poire</span>
</p>
.aliment
{
color: red;
}
Pas tout à fait. Indice: que veut dire le "." dans ".aliment" ?
Pas tout à fait. Ca voudrait dire que vous vous retrouveriez avec le HTML suivant:
<p>
<span aliment="aliment">Chocolat</span>,
<span aliment="vehicule">Vélo</span>,
<span aliment="aliment">Fraise</span>,
<span aliment="vehicule">Voiture</span>,
<span aliment="vehicule">Avion</span>
<span aliment="aliment">Poire</span>
</p>
Ca n'a pas l'air bon.
<h2>Choisir</h2>Que faut-il écrire dans le fichier CSS pour afficher "Choisir" en rouge ?
<p>
<span>Chocolat</span>, <span>Fraise</span>
</p>
Il y-a un problème avec votre sélecteur
Il ne doit pas y avoir de « ; » à la fin.
<h2>Joueurs</h2>Que faut-il écrire dans le fichier CSS pour afficher "Saidi" en rouge ? (uniquement "Saidi")
<p id="gagnant">
<span class="nom">Saidi</span>, <span class="prenom">Ahmed</span>
</p>
<p>
<span class="nom">Dubois</span>, <span class="prenom">Stéphane</span>
</p>
Pas tout à fait. Tout le paragraphe ayant id="gagnant" sera en rouge. Mais, ici, on veut uniquement "Saidi" en rouge, pas "Ahmed".
"Saidi" sera bien en rouge, mais "Dubois" le sera aussi. Ils ont tous les deux class="nom".
Presque! Le sélecteur « #gagnant.nom » veut dire « un élément dont le id est « gagnant » et qui a aussi class = nom. Par exemple:
<div id="gagnant" class="nom">...</div>
Ce n'est pas ce qu'on veut ici.
Il ne doit pas y avoir de « ; » à la fin.
<h2>Ingrédients</h2>Que faut-il écrire à la place de "AAA" pour afficher "Fraise" en rouge ?
<p>
<span>Chocolat</span>, <span AAA>Fraise</span>
</p>
Vous êtes sur la bonne voie.
Il vous manque le nom de l'attribut et quelques détails.
Non. Indice: en HTML, il y a un attribut qui permet de spécifier du CSS directement dans la balise HTML.
Presque!
Il y a bien style, color et red. Vérifiez la syntaxe sur le reste.
Vous êtes sur la bonne voie. La réponse commence bien par « style ». Le problème est après.
Les variables en JS ne sont pas déclarées avec un type. On utilise const, let et var pour les déclarer:
const a="bonjour";
let b=123;
var c=456;
Boucle numérique:
for(let i=0; i < 10 ; i++) {
...
}
Boucle tableau:
const joueurs=['Ahmed','Dubois', 'Chen' ];
for(let joueur of joueurs) {
console.log(joueur);
}
Les accolades { ... } définissent des blocs. La portée des variables s'étend aux sous-blocs.
function xyz() {
let a=abc();
if(a>5) {
let b=456;
console.log(a); // OK
console.log(b); // OK
}
console.log(b); // Erreur !
}
La portée des variables définies par let et const ne "monte" pas aux blocs contenants.
Déclarez une variable appelée pi contenant le nombre 3.141592
La valeur de cette variable ne changera pas.
Vous êtes sur la bonne voie.
Vous n'avez pas tenu compte de la consigne suivante:
«La valeur de cette variable ne changera pas. »
Écrivez, en une seule ligne, une boucle for sur la variable n qui affiche dans la console les nombres de 18 à 35 (35 compris) .
Pas tout à fait. On vous demande une boucle sur "n" pas sur "i"
Presque! Vous avez oublié de déclarer la variable n!
Vous êtes sur la bonne voie. On vous demande d'afficher n sur la console.
System.out.print... est du Java, pas du JavaScript.
En JS, on affiche dans la console...
Vous êtes sur la bonne voie. La première partie de votre boucle for(...) est correcte.
int est une déclaration d'entier en JAVA, C ou autre langage.
En JS, la déclaration se fait autrement...
Vous avez écrit "i++". La boucle est sur « n » pas sur « i »
Vous avez mis une virgule dans votre boucle. Les boucles en JS n'utilisent pas la virgule.
Vous avez écrit « n < 35 », l'énoncé indique :
« les nombres de 18 à 35 (35 compris) »
{
let x=1;
if(x>0){
let x=2;
}
console.log(x);
}
Qu'est-ce qui est affiché dans la console ?
1
2
Une erreur
0
Les fonctions en JS ont des particularités très utilisées.
Fonction simple:
function exemple(x,y){
...
}
Fonctions anonymes:
Les fonctions en JS sont des objets qui peuvent être mis dans des variables ou passés à d'autres fonctions.
C'est très utilisé pour définir des actions qu'il faudra exécuter plus tard. Par exemple, on veut donner au navigateur une fonction qu'il faudra appeler, plus tard, quand l'utilisateur clique sur quelque-chose.
const f=function () { ... };
x.addEventListener('click',function(e){console.log('coucou',e);});
Les fonctions anonymes sont tellement utilisées, que le JS fournit un raccourci: Les fonctions fléchées.
(Elles ont aussi une gestion de "this" différente)
const f=()=>{...};
x.addEventListener('click',e=>console.log('coucou',e));
Écrivez, en une seule ligne, une fonction appelée « ok » qui ne prend pas de paramètres et qui affiche « ok » dans la console.
(n'utilisez pas de fonction anonyme)
Vous êtes sur la bonne voie. La première partie est correcte:
function ok() { ...
Le problème est après.
La consigne indique:
« n'utilisez pas de fonction anonyme »
let compteur=0;
document.querySelector('#augmenter').addEventListener('click',XYZ);
Quand l'utilisateur clique sur #augmenter, on veut augmenter compteur de 1.
Que faut-il écrire à la place de XYZ ?
N'utilisez pas de fonction fléchée.
Avec « let » vous avez déclaré une nouvelle variable « compteur » qui n'existe que dans votre fonction. Vous n’incrémentez pas la bonne variable compteur.
Vous avez utilisé une fonction fléchée =>
La consigne indique « N'utilisez pas de fonction fléchée. »
Vous avez écrit :
function(compteur){...
Vous êtes en train de déclarer que compteur est un paramètre de la fonction anonyme.
addEventListener se contente d'enregistrer la fonction anonyme sur l'élément qui a id="augmenter"
Plus tard, quand l'utilisateur clique sur cet élément, le *navigateur* appelle cette fonction.
Ce n'est pas vous qui décidez quels paramètres seront passés à cette fonction.
Par ailleurs, en JS, on peut utiliser dans une fonction des variables définies en-dehors de la fonction.
Vous avez utilisé une fonction nommée (non anonyme).
Dans ce contexte, on utilise une fonction anonyme.
Traduisez ceci en fonction fléchée
function(e){return e.target.id;}
(Rappel des règles simplification, plus de détails)
Presque. Vous pouvez encore simplifier quelque-chose.
Le return est implicite. Vous ne devez pas le mettre.
Vous ne devez pas mettre de point-virgule ; à la fin.
Vous pouvez simplifier les accolades.
Voici les grandes lignes suivies par la plupart de nos programmes JS vus au S2:
1) Ils s’exécutent au chargement de la page pour:
a) chercher des éléments DOM (par exemple: document.querySelector)
b) enregistrer des fonctions ("gestionnaires d'événements") sur ces éléments DOM (par exemple: titre.addEventListener(...)).
Ces fonctions ne sont pas appelées tout de suite.
c) Notre programme a fini et rend la main au navigateur qui continue le chargement de la page.
2) Plus tard, l'utilisateur déclenche un événement (par exemple en cliquant) sur un élément (par exemple le <h1>)
La fonction enregistrée est appelée.
Elle modifie l'affichage en manipulant le DOM (par exemple paragraphe.style.color='green')
<!DOCTYPE html>(plus de détails)
<html lang="fr">
<head>
<meta charset="utf-8"/>
<title>Exemple</title>
</head>
<body>
<h1>Cliquez-moi!</h1>
<p>Bonjour!</p>
<script>
let titre=document.querySelector('h1');
titre.addEventListener('click',fonction_a_appeler);
function fonction_a_appeler()
{
let paragraphe=document.querySelector('p');
paragraphe.style.color='green';
}
</script>
</body>
</html>
Que faut-il écrire à la place de XYZ pour créer une variable "abc" et y mettre une référence vers le paragraphe "Bonjour!" ?
<body>
<p>Bienvenue</p>
<p class="b">Bonjour!</p>
<p>Au revoir!</p>
<script>
XYZ;
</script>
</body>
Presque! Il y a uniquement une erreur dans le paramètre passé à querySelector
Vous avez oublié de créer la variable abc.
On pourrait utiliser « getElementsByClassName » mais celle-ci retourne une liste.
Il y a une manière plus simple de faire. Indice: la fonction commence par un « q ».
Pas tout à fait. Comme son nom l'indique « getElementById » cherche un élément par son « id ». Ici, le paragraphe a « class » pas « id ».
Utilisez une autre fonction. Indice: la fonction commence par un « q ».
Attention à l'orthographe de querySelector
Que faut-il écrire à la place de XYZ pour qu'une fonction appelée « exemple » soit appelée lorsque l'utilisateur clique sur "Bonjour!".
(Utilisez la variable abc)
<body>
<p>Bienvenue</p>
<p class="b">Bonjour!</p>
<p>Au revoir!</p>
<script>
const abc=document.querySelector('.b');
XYZ;
function exemple()
{
console.log('Ca marche!');
}
</script>
</body>
Pas tout à fait.
Vous appelez la fonction exemple avant d'appeler addEventListener et vous passez la valeur de retour de la fonction exemple à addEventListener.
Ce n'est pas ce que addEventListener attend. addEventListener veut la fonction exemple elle même (pas le resultat de son appel). Ensuite addEventListener pour donnera la fonction au navigateur qui ne l’appellera que bien plus tard.
Il y a un problème avec le premier paramètre de addEventListener
Vous êtes sur la bonne voie. La réponse commence bien par:
abc.addEventListener('click', ...
Le problème est après.
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="utf-8"/>
<title>Jeu poissons</title>
<link rel="stylesheet" href="jeu.css"/>
</head>
<body>
<h1>Jeu poissons</h1>
<script src="jeu.js"></script>
</body>
</html>
/* vide pour l'instant */
// vide pour l'instant
jeu.html
<h1>Jeu poissons</h1>
<div id="eau">
</div>
<script src="jeu2.js"></script>
jeu.css
#eau {
position: relative;
width: 800px;
height: 450px;
background-image: url(eau.svg);
overflow: hidden;
}
Dans le HTML, ajoutez l'image pingouin.svg à l'intérieur du <div id="eau"> et donnez lui le id "pingouin".
Dans le CSS, ajoutez:
#pingouin {
top: 20px;
}
Normalement, ça ne marche pas.
Que faut-il ajouter pour que "top: 20px" puisse fonctionner ?
Oui. La propriété "top" ne fonctionne pas tant que l'élément a "position: static" (la valeur par défaut).
Presque! « position: relative » permet d'utiliser top, mes les coordonnées (top,left) seront relatives à la position initiale du pingouin. On voudrait des coordonnées relatives au « bloc englobant ». Donc il faut bien utiliser « position: », mais avec une autre valeur.
Indice: lisez ceci
Presque! Vérifiez l'orthographe.
Indice: lisez ceci
On voudrait déplacer le pingouin avec le clavier.
Pour ça, on doit enregistrer une fonction que le navigateur appellera plus tard quand une touche sera appuyée. Cette fonction, qu'on va écrire, est appelée "gestionnaire d'événements".
Habituellement, on enregistre cette fonction sur un élément précis, mais, ici, on veut obtenir les événements clavier où qu'ils surviennent sur la page. On va donc écouter directement sur "document", l'objet qui se trouve tout en haut de l'arbre DOM. Les événements y remontent par bubbling.
Écrivez le code nécessaire pour faire en sorte que "Touche appuyée" soit affiché sur la console chaque fois l'utilisateur enfonce une touche, où que ce soit sur la page.
Indications:
Vous êtes sur la bonne voie. La première partie de votre réponse est correcte:
document.addEventListener('keydown',
Vous êtes sur la bonne voie. La fonction anonyme est correcte:
function(){console.log('Touche appuyée');}
Vous êtes sur la bonne voie. La première partie de votre réponse est correcte:
document.addEventListener(
Pas tout à fait. On veut installer le gestionnaire d'événement directement sur « document ».
Vous n'avez pas besoin d'aller chercher un élément avec querySelector ou getElementById ...
Rappel:
Habituellement, on enregistre cette fonction sur un élément précis,
mais, ici, on veut obtenir les événements clavier où qu'ils surviennent
sur la page. On va donc écouter directement sur "document", l'objet qui
se trouve tout en haut de l'arbre DOM. Les événements y remontent par bubbling.
Il y-a un problème avant "addEventListener" et un problème après aussi
document.addEventListener('keydown',function(){console.log('Touche appuyée')})
On voudrait changer la position du pingouin quand l'utilisateur appuie sur les flèches.
La fonction anonyme ci-dessus est appelée par le navigateur quelque soit la touche enfoncée.
Le navigateur l'appelle avec un paramètre. On le nomme souvent "event".
event.code va nous indiquer quelle touche a été enfoncée.
Dans jeu.js, affichez event.code dans la console et regardez le résultat.
En regardant la console, que vaut event.code quand l'utilisateur appuie sur la flèche vers le bas ?
Presque! La question demande flèche vers le bas
Vous avez écrit « addEventListener ».
L'énoncé ne demande pas d'écrire du JS. Vous devez juste copier une valeur qui est affichée sur la console.
Presque! Vérifiez l'orthographe.
On va gérer la propriété CSS "top", dans le DOM, plutôt que dans le fichier CSS.
Dans le CSS enlevez "top: 20px" au pingouin et ajoutez style="top: 0px" dans le HTML:
<img id="pingouin" style="top: 0px" src="pingouin.svg"/>
En début de votre programme JS, ajoutez les lignes suivantes.
const pingouin =document.getElementById('pingouin');
const eau =document.getElementById('eau' );
Elles permettront d’accéder simplement à "pingouin" et "eau".
La variable "pingouin" contient un élément DOM. Il permet d’accéder à la propriété style, qui elle même a une propriété top:
pingouin.style.top
const pingouin =document.getElementById('pingouin');
const eau =document.getElementById('eau' );
document.addEventListener('keydown',function(event){
console.log('Touche appuyée',event.code);
console.log('pingouin.style.top:',pingouin.style.top);
let top=parseInt(pingouin.style.top);
if(event.code ==="ArrowUp" ){top-=30;}
if(event.code ==="ArrowDown"){top+=30;}
pingouin.style.top=top+'px';
});
Faites en sorte que le le pingouin ne puisse pas dépasser le haut, ni le bas.
Tenez compte du fait que l'eau fait 450px de haut et le pingouin fait 60px de haut.
Dans le CSS, pour rendre le mouvement plus fluide, ajoutez au pingouin:
transition: top 1s;
Écrivez le code, vérifiez qu'il fonctionne dans votre navigateur, puis copiez-le ici pour que votre enseignant puisse le relire plus tard:
const pingouin =document.getElementById('pingouin');
const eau =document.getElementById('eau' );
document.addEventListener('keydown',function(event){
let top=parseInt(pingouin.style.top);
if(event.code ==="ArrowUp" ){top-=30;}
if(event.code ==="ArrowDown"){top+=30;}
if(top<0 ){top=0;}
if(top>450-60){top=450-60;}
pingouin.style.top=top+'px';
});
On veut ajouter un poisson qui défile de droite à gauche. Le poisson est une image.
Pour ça, il faudra:
Que faut-il écrire pour créer, en JS, une image et la mettre dans une variable appelée "poisson" ?
(Pour l'instant on ne l'insère pas encore dans le document)
Presque ! Indice: createElement est une méthode qui s'applique sur quelque-chose...
Presque! La première partie de votre réponse est correcte:
let poisson=document.createElement ...
Le problème est après.
Vous indiquez « src= ». Ca c'est la deuxième étape.
Pour l'instant on veut juste créer l'image.
const poisson=document.createElement('img')
Dans "poisson" on a un objet DOM img, mais on n'a pas encore spécifié de fichier.
Comment indiquer qu'on veut utiliser poisson.svg ?
const poisson=document.createElement('img');Pour l'instant le poisson est hors de l'eau. Il n'aime pas ça.
poisson.src='poisson.svg';
Vous êtes sur la bonne voie. La fin est correcte:
.append(poisson);
Le problème est avant
Vous êtes sur la bonne voie. Le début est correct:
eau.append(
Le problème est après
On veut ajouter la classe "poisson" au poisson. Utilisez la propriété className.
Pour l'instant votre code JS doit ressembler à ceci:
const pingouin =document.getElementById('pingouin');Vous devriez voir un poisson affiché en haut à gauche de l'eau.
const eau =document.getElementById('eau' );
document.addEventListener('keydown',function(event){
// La position verticale du haut du pingouin.
// On utilisez parseInt pour passer de la chaîne "123px" au nombre 123.
let top=parseInt(pingouin.style.top);
if(event.code ==="ArrowUp" ){top-=30;}
if(event.code ==="ArrowDown"){top+=30;}
// Éviter que le pingouin ne sorte de l'eau
if(top<0 ){top=0;}
if(top>450-60){top=450-60;}
// Mettre à jour la position
pingouin.style.top=top+'px';
});
// Création d'une image. Elle n'est pas encore dans l'arbre DOM.
const poisson=document.createElement('img');
poisson.src='poisson.svg';
poisson.className='poisson';
// On insère l'image dans l'arbre DOM, dans l'élément eau (c'est ce que les poissons aiment).
eau.append(poisson);
En vous inspirant de ce qui a été fait pour le pingouin, placez le poisson en haut à droite de l'eau.
Remarquez que le poisson à la class "poisson". En effet, plus tard, on ajoutera d'autres poissons.
L'eau fait 800px de large et le poisson 40px.
Utilisez la propriété CSS left et pas la propriété right.
On voudrait animer la propriété "left", pour que le poisson défile de la droite vers la gauche.
Les transitions CSS permettent de dire qu'un changement doit être fait lentement.
Normalement, si on fait:
poisson.style.left='0px';
le poisson se colle à gauche de l'eau immédiatement.
Avec une transition, on peux dire que le passage de "left: 760px" à "left: 0px" doit se faire en 2 secondes.
Ajoutez donc les deux lignes suivantes :
transition: left 2s;
transition-timing-function: linear;
Maintenant, dans votre code JS. Ajoutez les lignes suivantes:
window.getComputedStyle(poisson).top;
poisson.style.left=0;
L'utilité de la première ligne est un peu compliquée à comprendre. En gros, elle force le navigateur à prendre en compte la position actuelle (left: 760px), avant de changer à "left: 0px". Ceci lui permet de voir qu'il faut déclencher la transition.
Recopiez ce code et vérifiez que le poisson défile bien.
Le pingouin a faim. Il va lui falloir plus de poissons.
Avec la fonction window.setInterval, on peut appeler une fonction toutes les 500 millisecondes:
window.setInterval(function(){
console.log('Coucou',Date.now());
},500);
Essayez ce code.
En vous en inspirant, créez un poisson qui défile toutes les 500 ms.
window.setInterval(function(){
const poisson=document.createElement('img');
poisson.src='poisson.svg';
poisson.className='poisson';
eau.append(poisson);
window.getComputedStyle(poisson).top;
poisson.style.left=0;
},500);
Les poissons sont tous crées en haut.
La fonction Math.random() fournit un nombre aléatoire entre 0 et 1.
L'eau fait 450px de haut et le poisson en fait 18.
Faites en sorte que le poisson apparaisse à une hauteur aléatoire.
Écrivez le code, vérifiez qu'il fonctionne dans votre navigateur, puis copiez-le ici pour que votre enseignant puisse le relire plus tard:
window.setInterval(function(){
const poisson=document.createElement('img');
poisson.src='poisson.svg';
poisson.className='poisson';
eau.append(poisson);
poisson.style.top=(Math.random()*(450-18))+'px';
window.getComputedStyle(poisson).top;
poisson.style.left=0;
},500);
Quand le poisson arrive à gauche de l'eau, il y reste.
On voudrait le supprimer.
On sait que le défilement (la transition) dure deux secondes.
On doit donc supprimer le poisson deux secondes après sa création.
La fonction window.setTimeout permet d’exécuter une fonction dans n millisecondes.
Pour supprimer un élément il suffit d'utiliser .remove() :
poisson.remove();
Faites en sorte que les poissons soient supprimés.
window.setInterval(function(){
const poisson=document.createElement('img');
poisson.src='poisson.svg';
poisson.className='poisson';
eau.append(poisson);
poisson.style.top=(Math.random()*(450-18))+'px';
window.getComputedStyle(poisson).top;
poisson.style.left=0;
window.setTimeout(function(){
poisson.remove();
},2000);
},500);
Le pingouin ne peut pas encore manger. Il a toujours faim !
Dans le HTML, ajoutez un affichage du score:
<p>Score:<span id="score">-</span>
Vers le haut du fichier JS créez:
let score=0;
La variable "score" permettra de compter les poissons mangés.
On va déterminer si le pingouin touche le poisson, quand le poisson arrive à gauche de l'eau.
La fonction getBoundingClientRect() permet de connaître le rectangle qu'occupent le poisson et le pingouin.
const rectPingouin=pingouin.getBoundingClientRect();
const rectPoisson =poisson.getBoundingClientRect();
Ces rectangles ont des propriétés top et bottom. A l'aide de top et bottom, affichez "miam" dans la console, quand le pingouin touche un poisson.
Écrivez le code, vérifiez qu'il fonctionne dans votre navigateur, puis copiez-le ici pour que votre enseignant puisse le relire plus tard:window.setInterval(function(){
console.log('Création poisson');
const poisson=document.createElement('img');
poisson.src='poisson.svg';
poisson.className='poisson';
eau.append(poisson);
poisson.style.top=(Math.random()*(450-18))+'px';
window.getComputedStyle(poisson).top;
poisson.style.left=0;
window.setTimeout(function(){
const rectPingouin=pingouin.getBoundingClientRect();
const rectPoisson =poisson.getBoundingClientRect();
if(rectPingouin.bottom>rectPoisson.top && rectPingouin.top<rectPoisson.bottom)
{
console.log('miam');
}
poisson.remove();
},2000);
},500);
Quand le pingouin a touché le poisson on peut augmenter le score:
score++;
Ensuite, on veut l'afficher. Que faut-il écrire pour afficher score dans le span prévu ?
Essayez dans votre code avant de répondre.
(n'utilisez pas de variable intermédiaire)
Utilisez « textContent » plutôt que innerHTML.
innerHTML peut poser des problèmes de sécurité.
N'utilisez innerHTML que si vous avez réellement besoin de HTML et que vous êtes certain que ce HTML est sur.
Vous êtes sur la bonne voie. Le début est correct:
document.getElementById('score')
Le problème vient après.
Vous êtes sur la bonne voie. La fin est correcte:
textContent=score:
Le problème est avant.
Vous ne devez pas utiliser de variable intermédiaire (pas de let, const ou var) .
L'animation est n'est pas fluide parce que le poisson apparaît dans eau entièrement visible et qu'il disparaît alors qu'il est entièrement visible.
Faites en sorte que le poisson
JS
window.setInterval(function(){
console.log('Création poisson');
const poisson=document.createElement('img');
poisson.src='poisson.svg';
poisson.className='poisson';
eau.append(poisson);
poisson.style.top=(Math.random()*(450-18))+'px';
window.getComputedStyle(poisson).top;
poisson.style.left='-40px';
window.setTimeout(function(){
const rectPingouin=pingouin.getBoundingClientRect();
const rectPoisson =poisson.getBoundingClientRect();
if(rectPingouin.bottom>rectPoisson.top && rectPingouin.top<rectPoisson.bottom)
{
console.log('miam');
score++;
document.getElementById('score').textContent=score;
}
poisson.remove();
},2000);
},500);
CSS
.poisson {
position: absolute;
left: 840px;
transition: left 2s;
transition-timing-function: linear;
}
On supprime le poisson au bout de 2 secondes.
Avec nos changements, à 2 secondes, le poisson se trouve derrière les pieds du pingouin.
Un pingouin mange avec son bec ... pas avec ses pieds !
Le poisson se trouve près du bec vers 1650 millisecondes.
On doit donc utiliser deux window.setTimeout différents.
const pingouin=document.getElementById('pingouin');
const eau =document.getElementById('eau' );
let score=0;
document.addEventListener('keydown',function(event){
let top=parseInt(pingouin.style.top);
if(event.code ==="ArrowUp" ){top-=30;}
if(event.code ==="ArrowDown"){top+=30;}
if(top<0 ){top=0;}
if(top>450-60){top=450-60;}
pingouin.style.top=top+'px';
});
window.setInterval(function(){
console.log('Création poisson');
const poisson=document.createElement('img');
poisson.src='poisson.svg';
poisson.className='poisson';
eau.append(poisson);
poisson.style.top=(Math.random()*(450-18))+'px';
poisson.style.left='840px';
window.getComputedStyle(poisson).top;
poisson.style.left='-40px';
// On sait que le poisson atteindra la gauche de l'écran dans 2 secondes.
window.setTimeout(function(){
poisson.remove();
},2000);
// On sait que le poisson atteindra le bec du pingouin dans 1650 millisecondes.
window.setTimeout(function(){
// Voir si le pingouin touche le poisson.
const rectPingouin=pingouin.getBoundingClientRect();
const rectPoisson =poisson.getBoundingClientRect();
// Si oui, on augmente le score.
if(rectPingouin.bottom>rectPoisson.top && rectPingouin.top<rectPoisson.bottom)
{
score++;
document.getElementById('score').textContent=score;
poisson.remove();
}
},1650);
},500);
Comme vous pouvez le voir, le phoque est un terrifiant prédateur du pingouin.
Créez le fichier phoque.svg
En vous inspirant de ce qui est fait pour les poissons, créez, toutes les 4 secondes un phoque qui défile de droite à gauche en 2s.
Le phoque est gros (et a faim aussi) ... il fait 121 px de large et 117 px de haut.
Si le phoque touche le pingouin affichez:
alert('Mangé par le phoque!');
jeu.js (commenté)
const pingouin=document.getElementById('pingouin');
const eau =document.getElementById('eau' );
let score=0;
// Réagir quand l'utilisateur appuie sur une touche.
// Tous les évènements remontent (bubbling) jusqu'à document.
// Donc, quand on veut attraper un événement où qu'il survienne sur la page, on peut écouter sur document.
document.addEventListener('keydown',function(event){
// La position verticale du haut du pingouin.
// On utilisez parseInt pour passer de la chaîne "123px" au nombre 123.
let top=parseInt(pingouin.style.top);
if(event.code ==="ArrowUp" ){top-=30;}
if(event.code ==="ArrowDown"){top+=30;}
// Éviter que le pingouin ne sorte de l'eau
if(top<0 ){top=0;}
if(top>450-60){top=450-60;}
// Mettre à jour la position
pingouin.style.top=top+'px';
});
// On crée un poisson à intervalles réguliers. C'est à dire tous les ? millisecondes.
window.setInterval(function(){
console.log('Création poisson');
// Création d'une image. Elle n'est pas encore dans l'arbre DOM.
const poisson=document.createElement('img');
poisson.src='poisson.svg';
poisson.className='poisson';
// On insère l'image dans l'arbre DOM, dans l'élément eau (c'est que les poissons aiment).
eau.append(poisson);
// Position verticale aléatoire. L'eau fait 450 px de haut, et le poisson 18px.
poisson.style.top=(Math.random()*(450-18))+'px';
poisson.style.left='840px';
// Compliqué. On demande au navigateur de prendre en compte la situation actuelle.
// Ceci va permettre de déclencher l'animation du poisson à la ligne suivante (transition CSS).
window.getComputedStyle(poisson).top;
// Ceci ne se fait pas immédiatement. La transition CSS dit que ca se fera en 2 secondes.
// C'est ce qui crée le défilement du poisson.
poisson.style.left='-40px';
// On sait que le poisson atteindra la gauche de l'écran dans 2 secondes.
// On utilise setTimeout pour exécuter la fonction dans 2000 millisecondes (2 secondes).
window.setTimeout(function(){
// On fait disparaître le poisson en l'enlevant de l'arbre DOM.
poisson.remove();
},2000);
// On sait que le poisson atteindra le bec du pingouin dans 1650 millisecondes.
window.setTimeout(function(){
// Voir si le pingouin touche le poisson.
const rectPingouin=pingouin.getBoundingClientRect();
const rectPoisson =poisson.getBoundingClientRect();
// Si oui, on augmente le score.
if(rectPingouin.bottom>rectPoisson.top && rectPingouin.top<rectPoisson.bottom)
{
score++;
document.getElementById('score').textContent=score;
// On fait disparaître le poisson en l'enlevant de l'arbre DOM.
poisson.remove();
}
},1650);
},500);
// On crée un phoque à intervalles réguliers.
window.setInterval(function(){
console.log('Création phoque');
const phoque=document.createElement('img');
phoque.src='phoque.svg';
phoque.className='phoque';
eau.append(phoque);
// Position verticale aléatoire. L'eau fait 450 px de haut, et le phoque 117px.
phoque.style.top=(Math.random()*(450-117))+'px';
phoque.style.left='920px';
// Compliqué. On demande au navigateur de prendre en compte la situation actuelle.
// Ceci va permettre de déclencher l'animation du phoque à la ligne suivante (transition CSS).
window.getComputedStyle(phoque).top;
// Ceci ne se fait pas immédiatement. La transition CSS dit que ca se fera en 2 secondes.
// C'est ce qui crée le défilement du phoque.
phoque.style.left='-120px';
// On sait que le phoque atteindra la gauche de l'écran dans 2 secondes.
// On utilise setTimeout pour exécuter la fonction dans 2000 millisecondes (2 secondes).
window.setTimeout(function(){
// On fait disparaître le phoque en l'enlevant de l'arbre DOM.
phoque.remove();
},2000);
// On sait que le phoque atteindra le bec du pingouin dans 1625 millisecondes.
window.setTimeout(function(){
// Voir si le pingouin touche le phoque.
const rectPingouin=pingouin.getBoundingClientRect();
const rectPhoque =phoque.getBoundingClientRect();
// Si oui, on perd
if(rectPingouin.bottom>rectPhoque.top && rectPingouin.top<rectPhoque.bottom)
{
alert('Mangé par le phoque!');
}
},1625);
},4000);
jeu.css
#eau {
position: relative;
width: 800px;
height: 450px;
background-image: url(eau.svg);
overflow: hidden;
}
#pingouin {
position: absolute;
z-index: 10;
transition: top 1s;
}
.poisson {
position: absolute;
left: 840px;
transition: left 2s;
transition-timing-function: linear;
}
.phoque {
position: absolute;
left: 780px;
transition: left 2s;
transition-timing-function: linear;
}