Jeu labyrinthe avec touch pad : Différence entre versions
Ligne 19 : | Ligne 19 : | ||
==Réalisation du projet== | ==Réalisation du projet== | ||
− | La réalisation de ce projet est relativement simple. Elle se résume en | + | La réalisation de ce projet est relativement simple. Elle se résume en 4 étapes : |
− | # | + | # Initier les impressions 3D selon les modèles de fichiers listés dans la section '''[[#Impression 3D|Impression 3D]]''' ; |
− | # | + | # Réaliser le câblage du D1 mini Wemos avec les servomoteurs selon le schéma de câblage fourni ci-dessous dans la partie '''[[#Schéma|Schéma]]''' ; |
− | + | # Télécharger le programme dans le D1 mini Wemos ; | |
− | + | # Jouer. | |
− | ===Schéma | + | ===Schéma=== |
===Code=== | ===Code=== | ||
− | < | + | Le code nécessaire à ce projet se sépare en deux parties : |
− | + | # Web (HTML/CSS/JavaScript) permettant d'afficher un touch pad sur le téléphone portable et de commander l'inclinaison du plateau du labyrinthe ; | |
− | // | + | # C++ (Arduino) permettant de programmer le D1 mini Wemos pour qu'il ouvre une connexion WIFI et d'adresser les commandes reçues aux servomoteurs contrôlant l'inclinaison du plateau du labyrinthe. |
− | </ | + | ====Web==== |
+ | =====HTML===== | ||
+ | <syntaxhighlight lang="HTML" line> | ||
+ | <!DOCTYPE html> | ||
+ | <html lang='fr'> | ||
+ | <head> | ||
+ | <meta charset='UTF-8'> | ||
+ | <meta name='viewport' content='width=device-width, initial-scale=1.0'> | ||
+ | <title>Jeu du labyrinthe</title> | ||
+ | </head> | ||
+ | <body> | ||
+ | <div id='pad'> | ||
+ | <div id='centrePad'>+</div> | ||
+ | </div> | ||
+ | </body> | ||
+ | </html> | ||
+ | </syntaxhighlight> | ||
+ | =====CSS===== | ||
+ | <syntaxhighlight lang="CSS" line> | ||
+ | <style> | ||
+ | /* Styles pour le pad de direction */ | ||
+ | #pad { | ||
+ | background-color: #f0f0f0; | ||
+ | border-radius: 50%; | ||
+ | position: relative; | ||
+ | user-select: none; | ||
+ | } | ||
+ | #centrePad { | ||
+ | position: absolute; | ||
+ | top: 50%; | ||
+ | left: 50%; | ||
+ | transform: translate(-50%, -50%); | ||
+ | font-size: 24px; | ||
+ | } | ||
+ | </style> | ||
+ | </syntaxhighlight> | ||
+ | =====JavaScript===== | ||
+ | <syntaxhighlight lang="JavaScript" line> | ||
+ | <script> | ||
+ | let supportsPassive = false; | ||
+ | try { | ||
+ | let opts = Object.defineProperty({}, 'passive', { | ||
+ | get: function() { | ||
+ | supportsPassive = true; | ||
+ | } | ||
+ | }); | ||
+ | window.addEventListener('testPassive', null, opts); | ||
+ | window.removeEventListener('testPassive', null, opts); | ||
+ | } catch (e) {} | ||
+ | const pad = document.getElementById('pad'); | ||
+ | const rect = pad.getBoundingClientRect(); | ||
+ | let vitesse = [0, 0]; | ||
+ | let vitesseMax = 4; | ||
+ | let nbVitesses = vitesseMax * 2 + 1; | ||
+ | let taillePad = 180; | ||
+ | let pallierVitesse = taillePad / nbVitesses; | ||
+ | let timerId = null; | ||
+ | |||
+ | pad.style.width = pad.style.height = taillePad + 'px'; | ||
+ | |||
+ | function envoiMouvement() { | ||
+ | const xhr = new XMLHttpRequest(); | ||
+ | xhr.open('Mouvement', 'mouvement?x=' + vitesse[0] + '&y=' + vitesse[1], true); | ||
+ | xhr.send(); | ||
+ | } | ||
+ | |||
+ | pad.addEventListener('touchstart', (position) => { | ||
+ | vitesse[0] = Math.trunc((position.touches[0].clientX - rect.left)/pallierVitesse) - vitesseMax; | ||
+ | vitesse[1] = vitesseMax - Math.trunc((position.touches[0].clientY - rect.top)/pallierVitesse); | ||
+ | envoiMouvement(); | ||
+ | timerId = setInterval(envoiMouvement, 10); | ||
+ | }); | ||
+ | |||
+ | pad.addEventListener('touchmove', (position) => { | ||
+ | if(position.touches[0].clientX < rect.left || position.touches[0].clientX > (taillePad + rect.left) || | ||
+ | position.touches[0].clientY < rect.top || position.touches[0].clientY > (taillePad + rect.top)) | ||
+ | return; | ||
+ | |||
+ | vitesse[0] = Math.trunc((position.touches[0].clientX - rect.left)/pallierVitesse) - vitesseMax; | ||
+ | vitesse[1] = vitesseMax - Math.trunc((position.touches[0].clientY - rect.top)/pallierVitesse); | ||
+ | |||
+ | }, supportsPassive ? { passive: true } : false); | ||
+ | |||
+ | pad.addEventListener('touchend', (position) => { | ||
+ | vitesse[0] = vitesse[1] = 0; | ||
+ | clearInterval(timerId); | ||
+ | envoiMouvement(); | ||
+ | timerId = null; | ||
+ | }); | ||
+ | </script> | ||
+ | </syntaxhighlight> | ||
+ | ===Explications=== | ||
==Pour aller plus loin== | ==Pour aller plus loin== | ||
[[Catégorie:Arduino]] | [[Catégorie:Arduino]] | ||
[[Catégorie:Jeu]] | [[Catégorie:Jeu]] | ||
[[Catégorie:Fiche à Valider]] | [[Catégorie:Fiche à Valider]] |
Version du 29 mars 2024 à 14:31
Sommaire
Description
Qui ne connaît pas le jeu du labyrinthe à bille : Un jeu qui consiste à faire sortir une bille d'un labyrinthe en utilisant deux molettes permettant de faire pencher le plateau du labyrinthe vers le haut ou le bas, et vers la droite ou la gauche, le tout en évitant de faire tomber la bille dans les trous qui parsèment le chemin.
Ce projet a donc eu pour objectif de pouvoir jouer au jeu du labyrinthe en commandant les inclinaisons du plateau grâce à un touch pad depuis un téléphone portable.
Liste du matériel
Électronique
- 1 x Module Wifi D1 Mini Wemos
- 2 x Servomoteurs 0-180°
- Câbles électriques, connecteurs et 1 câble USB/mini USB pour connecter le D1 mini Wemos à l'ordinateur
Impression 3D
Les fichiers nécessaires à l'impression 3D du modèle utilisé dans ce tutoriel sont accessibles A COMPLETER
Coût
Pour l'ensemble du projet, il faut compter un coût global électronique + impression 3D de 15 euros environ.
Réalisation du projet
La réalisation de ce projet est relativement simple. Elle se résume en 4 étapes :
- Initier les impressions 3D selon les modèles de fichiers listés dans la section Impression 3D ;
- Réaliser le câblage du D1 mini Wemos avec les servomoteurs selon le schéma de câblage fourni ci-dessous dans la partie Schéma ;
- Télécharger le programme dans le D1 mini Wemos ;
- Jouer.
Schéma
Code
Le code nécessaire à ce projet se sépare en deux parties :
- Web (HTML/CSS/JavaScript) permettant d'afficher un touch pad sur le téléphone portable et de commander l'inclinaison du plateau du labyrinthe ;
- C++ (Arduino) permettant de programmer le D1 mini Wemos pour qu'il ouvre une connexion WIFI et d'adresser les commandes reçues aux servomoteurs contrôlant l'inclinaison du plateau du labyrinthe.
Web
HTML
1 <!DOCTYPE html>
2 <html lang='fr'>
3 <head>
4 <meta charset='UTF-8'>
5 <meta name='viewport' content='width=device-width, initial-scale=1.0'>
6 <title>Jeu du labyrinthe</title>
7 </head>
8 <body>
9 <div id='pad'>
10 <div id='centrePad'>+</div>
11 </div>
12 </body>
13 </html>
CSS
1 <style>
2 /* Styles pour le pad de direction */
3 #pad {
4 background-color: #f0f0f0;
5 border-radius: 50%;
6 position: relative;
7 user-select: none;
8 }
9 #centrePad {
10 position: absolute;
11 top: 50%;
12 left: 50%;
13 transform: translate(-50%, -50%);
14 font-size: 24px;
15 }
16 </style>
JavaScript
1 <script>
2 let supportsPassive = false;
3 try {
4 let opts = Object.defineProperty({}, 'passive', {
5 get: function() {
6 supportsPassive = true;
7 }
8 });
9 window.addEventListener('testPassive', null, opts);
10 window.removeEventListener('testPassive', null, opts);
11 } catch (e) {}
12
13 const pad = document.getElementById('pad');
14 const rect = pad.getBoundingClientRect();
15 let vitesse = [0, 0];
16 let vitesseMax = 4;
17 let nbVitesses = vitesseMax * 2 + 1;
18 let taillePad = 180;
19 let pallierVitesse = taillePad / nbVitesses;
20 let timerId = null;
21
22 pad.style.width = pad.style.height = taillePad + 'px';
23
24 function envoiMouvement() {
25 const xhr = new XMLHttpRequest();
26 xhr.open('Mouvement', 'mouvement?x=' + vitesse[0] + '&y=' + vitesse[1], true);
27 xhr.send();
28 }
29
30 pad.addEventListener('touchstart', (position) => {
31 vitesse[0] = Math.trunc((position.touches[0].clientX - rect.left)/pallierVitesse) - vitesseMax;
32 vitesse[1] = vitesseMax - Math.trunc((position.touches[0].clientY - rect.top)/pallierVitesse);
33 envoiMouvement();
34 timerId = setInterval(envoiMouvement, 10);
35 });
36
37 pad.addEventListener('touchmove', (position) => {
38 if(position.touches[0].clientX < rect.left || position.touches[0].clientX > (taillePad + rect.left) ||
39 position.touches[0].clientY < rect.top || position.touches[0].clientY > (taillePad + rect.top))
40 return;
41
42 vitesse[0] = Math.trunc((position.touches[0].clientX - rect.left)/pallierVitesse) - vitesseMax;
43 vitesse[1] = vitesseMax - Math.trunc((position.touches[0].clientY - rect.top)/pallierVitesse);
44
45 }, supportsPassive ? { passive: true } : false);
46
47 pad.addEventListener('touchend', (position) => {
48 vitesse[0] = vitesse[1] = 0;
49 clearInterval(timerId);
50 envoiMouvement();
51 timerId = null;
52 });
53 </script>