ENIB 2024 : D1 Pong des zinzins
Titre de la fiche expérience :
Sommaire
Description
Le jeu du D1 Pong nécessite 2 joueurs qui s'affrontent. Le but est que la balle dépasse la raquette de son adversaire.
jeu du pong |
Ici, pour la conception de ce jeu de pong, nous avons une balle qui se déplace uniquement tout droit et les raquettes ne bougent pas.
Introduction
Nous sommes un groupe de 4 élèves en 3ème année en école d'ingénieurs. Nous réalisons ce projet dans le cadre d'un hackathon qui a lieu durant l'intersemestre de notre école
Photo du groupe |
Outils et matériels
Outils
- cutter
- fer à souder
- pistolet à colle
Matériels
- carton
- 2 boutons poussoirs
- 1 carte arduino nano
- 28 LEDs
- câbles d'alimentation
Maquette
Maquette en carton | Maquette en carton fonctionnelle |
Prototype
fichiers à joindre
code, ficher d'impression 3D, de découpe laser ou vinyle, ...
Code Arduino
1 /*
2 Code de fonctionnement pour le jeu PONG.
3 Par les petits debrouillards.
4 */
5
6 #include <FastLED.h>
7
8 // Definition des couleurs
9 const CRGB NOIR = CRGB(0, 0, 0 );
10 const CRGB BLANC = CRGB(255, 255, 255);
11 const CRGB ROUGE = CRGB(255, 0, 0 );
12 const CRGB VERT = CRGB(0, 255, 0 );
13 const CRGB BLEU = CRGB(0, 0, 255);
14 const CRGB JAUNE = CRGB(255, 255, 0 );
15 const CRGB ROSE = CRGB(255, 0, 255);
16 const CRGB CYAN = CRGB(0, 255, 255);
17
18 // Definition des notes de musique
19 const int PONG_SOUND = 250; //380
20 const int LOOSE_SOUND = 180;
21
22
23 /******************************
24 PARAMETRES DE BRANCHEMENTS
25 ******************************/
26
27 const int LED_PIN = 8; // Numero de branchement de la bande de LEDs
28 const int BUTTON1_PIN = 2; // Numero de branchement du premier bouton
29 const int BUTTON2_PIN = 4; // Numero de branchement du deuxieme bouton
30 const int HAUT_PARLEUR_PIN = 6; // Numero de branchement du haut parleur (optionnel)
31
32
33 /***********************
34 PARAMETRES GENERAUX
35 ***********************/
36 const int NUM_LEDS = 28; // Nombre de LEDs sur la bande
37 const CRGB PLAYER1_COLOR = VERT; // Couleur player 1
38 const CRGB PLAYER2_COLOR = ROUGE; // Couleur player 2
39
40
41 /***********************
42 PARAMETRES PONG
43 ***********************/
44 const float BALL_SPEED = 0.5; // Vitesse de la balle
45 const float ACCELERATION = 9; // Accelleration de la balle a chaque tir, si ACCELERATION = 10 on augmente la vitesse de 10 pourcent a chaque tir
46 const int HIT_ZONE = 8; // Nombre de LED pendant lesquelles on peut renvoyer la balle
47 const int MAX_SCORE = 3;
48
49 const CRGB BALL_COLOR = BLANC; // Couleur de la balle
50
51 /*******************************
52 PARAMETRES TIR A LA CORDE
53 *******************************/
54 const float INCREMENT = 0.05; // De combien avance la corde lorsqu'on appuie sur le bouton
55 const float ROPE_SMOOTH = 1.0; // Parametre servant a lisser la position de la corde
56
57 const float WAVE_LENGTH = 0.2; // Taille des ondes
58 const float WAVE_SPEED = 1.0; // Vitesse des ondes
59
60
61
62 /******************************
63 VARIABLES GENERALES
64 ******************************/
65 // Players
66 enum Player
67 {
68 PERSONNE,
69 PLAYER1,
70 PLAYER2
71 };
72
73 // Etats du jeu
74 enum GameState
75 {
76 START,
77 PONG, // Mode pong
78 TAC // Mode tir a la corde
79 };
80
81 unsigned long lastMillis = 0;
82 unsigned long beginTimer = 0;
83 unsigned int counter = 0;
84
85 Player player = PLAYER1; // Prochain joueur a appuyer sur son bouton
86 Player lastWinner = PERSONNE;
87
88 CRGB leds[NUM_LEDS];
89 GameState gameState = START;
90
91
92 /**********************************************
93 FONCTIONS DE FONCTIONNEMENT GENERALES
94 **********************************************/
95
96 // Fonction permettant de changer la couleur d'une LED relativement au player 1 ou 2
97 void ledColor(Player player, int pos, CRGB color)
98 {
99 if (player == PLAYER1)
100 {
101 leds[pos] = color;
102 }
103 else // player == PLAYER2
104 {
105 leds[NUM_LEDS - pos - 1] = color;
106 }
107 }
108
109 // Fonction permettant de changer la couleur d'une LED
110 void ledColor(int pos, CRGB color)
111 {
112 leds[pos] = color;
113 }
114
115 /*********************************************
116 VARIABLES DE FONCTIONNEMENT DU PONG
117 *********************************************/
118 float ballSpeed = BALL_SPEED; // Vitesse de la balle
119 float ballPosition = 1; // Position de la balle sur la bande de led (Si ballPosition = 0, la balle est devant le player 1. Si ballPosition = 1, la balle est devant le player 2)
120 int player1Score = 0; // Score du player 1
121 int player2Score = 0; // Score du player 2
122
123 /**********************************************
124 FONCTIONS DE FONCTIONNEMENT DU PONG
125 **********************************************/
126 // Fonction servant a afficher les scores
127 void showScore()
128 {
129 // On commence par effacer toutes les couleurs de led
130 FastLED.clear();
131
132 // On allume le nombre de led correspondant au score du player 1
133 for (int i = 0; i < player1Score; i++)
134 {
135 ledColor(PLAYER1, NUM_LEDS / 2 - (i + 1), PLAYER1_COLOR);
136 }
137
138 // On allume le nombre de led correspondant au score du player 2
139 for (int i = 0; i < player2Score; i++)
140 {
141 ledColor(PLAYER2, NUM_LEDS / 2 - (i + 1), PLAYER2_COLOR);
142 }
143
144 // On envoie les nouvelles couleurs a la bande de led
145 FastLED.show();
146
147 // On fait clignotter trois fois
148 if (lastWinner == PLAYER1)
149 {
150 for (int i = 0; i < 3; i++)
151 {
152 // On eteint la derniere LED pendant 0.5s
153 delay(500);
154 ledColor(PLAYER1, NUM_LEDS / 2 - player1Score, NOIR);
155 FastLED.show();
156
157 // On allume la derniere LED pendant 0.5s
158 delay(500);
159 ledColor(PLAYER1, NUM_LEDS / 2 - player1Score, PLAYER1_COLOR);
160 FastLED.show();
161 }
162 }
163 else // lastWinner == PLAYER2
164 {
165 for (int i = 0; i < 3; i++)
166 {
167 // On eteint la derniere LED pendant 0.5s
168 delay(500);
169 ledColor(PLAYER2, NUM_LEDS / 2 - player2Score, NOIR);
170 FastLED.show();
171
172 // On allume la derniere LED pendant 0.5s
173 delay(500);
174 ledColor(PLAYER2, NUM_LEDS / 2 - player2Score, PLAYER2_COLOR);
175 FastLED.show();
176 }
177 }
178
179 // Si la partie est terminee on va a l'affichage de fin
180 if (player1Score == MAX_SCORE || player2Score == MAX_SCORE)
181 {
182 gameState = START;
183
184 // On reinitialise les scores
185 player1Score = 0;
186 player2Score = 0;
187
188 // On reinitialise la vitesse
189 ballSpeed = BALL_SPEED;
190
191 // On reinitialise les leds
192 FastLED.clear();
193 }
194 // Sinon on reprend le jeu
195 else
196 {
197 gameState = PONG;
198 ballSpeed = BALL_SPEED;
199 }
200 }
201
202
203 /***************************************
204 FONCTION PRINCIPALE DU PONG
205 ***************************************/
206 void pong_loop()
207 {
208 // Calcul du temps ecoule entre deux boucles
209 unsigned long currentMillis = millis();
210
211 // On calcule le numero de la LED allumee
212 int ballLed = ballPosition * NUM_LEDS;
213
214 // On s'assure que la position de la balle ne depasse pas la taille de la bande de LED
215 ballLed = min(ballLed, NUM_LEDS - 1);
216
217 // On regarde qui est en train de jouer
218 if (player == PLAYER1)
219 {
220 // On regarde si le player a appuye sur son bouton et si le delai de debut de jeu est passe
221 if (digitalRead(BUTTON1_PIN) == LOW && currentMillis - beginTimer > 500)
222 {
223 // Si la balle est hors de la zone de tir, l'autre player marque un point
224 if (ballLed >= HIT_ZONE)
225 {
226 player2Score += 1;
227 lastWinner = PLAYER2;
228 ballPosition = 0;
229
230 // On joue le son de defaite
231 tone(HAUT_PARLEUR_PIN, LOOSE_SOUND, 800);
232
233 // On passe en mode affichage des scores
234 showScore();
235
236 // C'est a l'autre player de jouer
237 player = PLAYER2;
238
239 // Actualisation de la variable lastMillis
240 lastMillis = millis();
241 }
242 else
243 {
244 // On accelere la balle
245 ballSpeed *= 1.0 + ACCELERATION / 100;
246
247 // C'est a l'autre player de jouer
248 player = PLAYER2;
249
250 // On joue la note de musique
251 tone(HAUT_PARLEUR_PIN, PONG_SOUND, 100);
252 }
253
254 return;
255 }
256
257 // On fait avancer la balle
258 ballPosition -= ballSpeed * (currentMillis - lastMillis) * 0.001f;
259
260 // On regarde si la balle est sortie de la zone
261 if (ballPosition < 0.0f)
262 {
263 // Si oui le player 2 marque un point
264 player2Score += 1;
265 lastWinner = PLAYER2;
266 ballPosition = 0;
267
268 // On joue le son de defaite
269 tone(HAUT_PARLEUR_PIN, LOOSE_SOUND, 800);
270
271 // On passe en mode affichage des scores
272 showScore();
273
274 // C'est a l'autre player de jouer
275 player = PLAYER2;
276
277 // Actualisation de la variable lastMillis
278 lastMillis = millis();
279 return;
280 }
281 }
282 else // player == PLAYER2
283 {
284 // On regarde si le player a appuye sur son bouton et si le delai de debut de jeu est passe
285 if (digitalRead(BUTTON2_PIN) == LOW && currentMillis - beginTimer > 500)
286 {
287 // Si la balle est hors de la zone de tir, l'autre player marque un point
288 if (ballLed < NUM_LEDS - HIT_ZONE)
289 {
290 player1Score += 1;
291 lastWinner = PLAYER1;
292 ballPosition = 1;
293
294 // On joue le son de defaite
295 tone(HAUT_PARLEUR_PIN, LOOSE_SOUND, 800);
296
297 // On passe en mode affichage des scores
298 showScore();
299
300 // C'est a l'autre player de jouer
301 player = PLAYER1;
302
303 // Actualisation de la variable lastMillis
304 lastMillis = millis();
305 }
306 else
307 {
308 // On accelere la balle
309 ballSpeed *= 1.1;
310
311 // C'est a l'autre player de jouer
312 player = PLAYER1;
313
314 // On joue la note de musique
315 tone(HAUT_PARLEUR_PIN, PONG_SOUND, 100);
316 }
317
318 return;
319 }
320
321 // On fait avancer la balle dans l'autre sens
322 ballPosition += ballSpeed * (currentMillis - lastMillis) * 0.001f;
323
324 // On regarde si la balle est sortie de la zone
325 if (ballPosition >= 1)
326 {
327 // Si oui le player 1 marque un point
328 player1Score += 1;
329 lastWinner = PLAYER1;
330 ballPosition = 1;
331
332 // On joue le son de defaite
333 tone(HAUT_PARLEUR_PIN, LOOSE_SOUND, 800);
334
335 // On passe en mode affichage des scores
336 showScore();
337 // C'est a l'autre player de jouer
338 player = PLAYER1;
339
340 // Actualisation de la variable lastMillis
341 lastMillis = millis();
342 return;
343 }
344 }
345
346 ///// AFFICHAGE BANDE DE LEDs /////
347 // Premierement on efface toutes les couleurs precedentes
348 FastLED.clear();
349
350 // Ensuite on allume faiblement les LEDs correspondant a la zone de chaque cote
351 for (int i = 0; i < HIT_ZONE; i++)
352 {
353 // On allume de chaque cote
354 ledColor(PLAYER1, i, PLAYER1_COLOR / 10); // On divise la couleur par 10 pour la rendre 10 fois moins puissante
355 ledColor(PLAYER2, i, PLAYER2_COLOR / 10);
356 }
357
358 // Ensuite on allume faiblement les LEDs correspondant aux scores
359 // Pour le player 1
360 for (int i = 0; i < player1Score; i++)
361 {
362 ledColor(PLAYER1, NUM_LEDS / 2 - (i + 1), PLAYER1_COLOR / 15);
363 }
364 // Pour le player 2
365 for (int i = 0; i < player2Score; i++)
366 {
367 ledColor(PLAYER2, NUM_LEDS / 2 - (i + 1), PLAYER2_COLOR / 15);
368 }
369
370 // Ensuite on actualise la position de la balle
371 // On donne la couleur de la led en fonction de si la balle est dans la zone d'un player ou non
372
373 // Si la balle est dans le camp d'un des player, elle est rouge.
374 if (ballLed < HIT_ZONE || ballLed >= NUM_LEDS - HIT_ZONE)
375 {
376 ledColor(ballLed, ROUGE);
377 }
378 // Si elle en est proche, elle est jaune
379 else if (ballLed < 2 * HIT_ZONE || ballLed >= NUM_LEDS - 2 * HIT_ZONE)
380 {
381 ledColor(ballLed, JAUNE);
382 }
383 // Sinon la balle a sa couleur par defaut
384 else
385 {
386 ledColor(ballLed, BALL_COLOR);
387 }
388
389 // On envoie la couleur des leds a la bande de leds
390 FastLED.show();
391
392 // On actualise la variable lastMillis pour la boucle suivante
393 lastMillis = currentMillis;
394 }
395
396
397
398 /*******************************************************
399 VARIABLES DE FONCTIONNEMENT DU TIR A LA CORDE
400 *******************************************************/
401 float ropePosition = 0.5; // Position non lissee de la corde
402 float displayedRopePosition = 0.5; // Position lissee de la corde
403 bool player1Pushed = false;
404 bool player2Pushed = false;
405
406 float player1Waves[10] = { 0 };
407 float player2Waves[10] = { 0 };
408
409 /***********************************************
410 FONCTION PRINCIPALE DU TIR A LA CORDE
411 ***********************************************/
412 void tac_loop()
413 {
414 // Calcul des temps
415 unsigned long ms = millis();
416 float dt = (ms - lastMillis) * 0.001f;
417 lastMillis = ms;
418
419 // Si moins d'une seconde s'est ecoule depuis le debut, on ne fait rien (pour eviter d'appuyer sans faire expres)
420 if (ms - beginTimer < 1000)
421 return;
422
423 bool player1Push = !digitalRead(BUTTON1_PIN);
424 bool player2Push = !digitalRead(BUTTON2_PIN);
425
426 if (player1Push && !player1Pushed)
427 {
428 // On incremente la position de la corde
429 ropePosition += INCREMENT;
430
431 // On lance une nouvelle onde
432 for (int i = 0; i < 10; i++)
433 {
434 if (player1Waves[i] == 0.0f)
435 {
436 //player1Waves[i] = WAVE_SPEED * dt;
437 player1Waves[i] = 0.01f;
438 break;
439 }
440 }
441 }
442 if (player2Push && !player2Pushed)
443 {
444 // On incremente la position de la corde
445 ropePosition -= INCREMENT;
446
447 // On lance une nouvelle onde
448 for (int i = 0; i < 10; i++)
449 {
450 if (player2Waves[i] == 0.0f)
451 {
452 player2Waves[i] = 0.99f;
453 break;
454 }
455 }
456 }
457
458 // Memorisation des etats des boutons
459 player1Pushed = player1Push;
460 player2Pushed = player2Push;
461
462
463
464
465 // On calcule la position lissee de la corde (displayedRopePosition correspond a la variable ropePosition avec un lissage supplementaire)
466 displayedRopePosition += (ropePosition - displayedRopePosition) * dt / ROPE_SMOOTH;
467
468 // On regarde si player 1 a gagne
469 if (displayedRopePosition >= 1.0f)
470 {
471 lastWinner = PLAYER1;
472 gameState = START;
473 beginTimer = millis();
474
475 ropePosition = 0.5f;
476 displayedRopePosition = 0.5f;
477
478 FastLED.clear();
479 return;
480 }
481 // On regarde si player 2 a gagne
482 else if (displayedRopePosition <= 0.0f)
483 {
484 lastWinner = PLAYER2;
485 gameState = START;
486 beginTimer = millis();
487
488 ropePosition = 0.5f;
489 displayedRopePosition = 0.5f;
490
491 FastLED.clear();
492 return;
493 }
494
495 // On propage les ondes
496 float dx = WAVE_SPEED * dt;
497
498 for (int wave = 0; wave < 10; wave++)
499 {
500 // Ondes player 1
501 if (player1Waves[wave] != 0.0f)
502 {
503 player1Waves[wave] += dx;
504
505 // Si toute l'onde depasse le point de la corde, on l'arrete
506 if (player1Waves[wave] - WAVE_LENGTH > displayedRopePosition)
507 {
508 player1Waves[wave] = 0.0f;
509 }
510 }
511
512 // Ondes player 2
513 if (player2Waves[wave] != 0.0f)
514 {
515 player2Waves[wave] -= dx;
516
517 // Si toute l'onde depasse le point de la corde, on l'arrete
518 if (player2Waves[wave] + WAVE_LENGTH < displayedRopePosition)
519 {
520 player2Waves[wave] = 0.0f;
521 }
522 }
523 }
524
525 // On actualise la bande de leds
526 float ledLuminosity;
527 float ledPosition;
528
529 FastLED.clear();
530
531 // On commence par calculer le numero de la led correspondant a la position de la corde
532 int ropeLedPosition = NUM_LEDS * displayedRopePosition;
533
534 // On dessine la zone du player 1
535 // Pour cela on calcule la luminosite led par led
536 for (int led = 0; led < ropeLedPosition; led++)
537 {
538 // La luminosite minimale d'une led est 10% de la luminosite max
539 ledLuminosity = 0.1f;
540 ledPosition = float(led) / float(NUM_LEDS);
541
542 // Pour chaque onde, on ajoute la luminosite a la led
543 for (int wave = 0; wave < 10; wave++)
544 {
545 // Si l'onde n'est pas active ou si l'onde est avant la led, on n'ajoute aucune luminosite
546 if (player1Waves[wave] == 0.0f || player1Waves[wave] < ledPosition)
547 continue;
548
549 // On ajoute de la luminosite de facon decroissante. plus l'onde est loin, moins on ajoute de luminosite.
550 ledLuminosity += max(0.0f, 0.9f - (player1Waves[wave] - ledPosition) / WAVE_LENGTH);
551 }
552 // La valeur maximale de luminosite est 1.0
553 if (ledLuminosity > 2.0f)
554 ledLuminosity = 2.0f;
555
556 // On actualise la valeur de luminosite de la led
557 ledColor(led, PLAYER1_COLOR / int(2.0f / ledLuminosity) / 5);
558 }
559
560 // On dessine la zone du player 2
561 for (int led = ropeLedPosition + 1; led < NUM_LEDS; led++)
562 {
563 // La luminosite minimale d'une led est 10% de la luminosite max
564 ledLuminosity = 0.1f;
565 ledPosition = float(led) / float(NUM_LEDS);
566
567 // Pour chaque onde, on ajoute la luminosite a la led
568 for (int wave = 0; wave < 10; wave++)
569 {
570 // Si l'onde n'est pas active ou si l'onde est avant la led, on n'ajoute aucune luminosite
571 if (player2Waves[wave] == 0.0f || ledPosition > player2Waves[wave])
572 continue;
573
574 // On ajoute de la luminosite de facon decroissante. plus l'onde est loin, moins on ajoute de luminosite.
575 ledLuminosity += max(0.0f, 0.9f - (player2Waves[wave] - ledPosition) / WAVE_LENGTH);
576 }
577 // La valeur maximale de luminosite est 1.0
578 if (ledLuminosity > 2.0f)
579 ledLuminosity = 2.0f;
580
581 // On actualise la valeur de luminosite de la led
582 ledColor(led, PLAYER2_COLOR / int(1.0f / ledLuminosity) / 5);
583 }
584
585 // On actualise la led correspondant a la position de la corde
586 ledColor(ropeLedPosition, BLANC);
587 FastLED.show();
588 }
589
590
591
592 /****************************************************************
593 Cette fonction s'execute une fois lorsque la carte s'allume.
594 ****************************************************************/
595 void setup() {
596 // Initialisation des LEDs
597 FastLED.addLeds<WS2812B, LED_PIN, GRB>(leds, NUM_LEDS);
598
599 // Initialisations des boutons
600 pinMode(BUTTON1_PIN, INPUT_PULLUP);
601 pinMode(BUTTON2_PIN, INPUT_PULLUP);
602
603 // Initialisation du haut parleur
604 pinMode(HAUT_PARLEUR_PIN, OUTPUT);
605
606 // COULEUR DES LEDS EN DEBUT DE PARTIE
607 FastLED.clear();
608 // Couleurs player 1
609 ledColor(PLAYER1, 0, PLAYER1_COLOR);
610 ledColor(PLAYER1, 1, PLAYER1_COLOR);
611 ledColor(PLAYER1, 2, PLAYER1_COLOR);
612 ledColor(PLAYER1, 3, PLAYER1_COLOR);
613 ledColor(PLAYER1, 4, PLAYER1_COLOR);
614
615 // Couleurs player 2
616 ledColor(PLAYER2, 0, PLAYER2_COLOR);
617 ledColor(PLAYER2, 1, PLAYER2_COLOR);
618 ledColor(PLAYER2, 2, PLAYER2_COLOR);
619 ledColor(PLAYER2, 3, PLAYER2_COLOR);
620 ledColor(PLAYER2, 4, PLAYER2_COLOR);
621
622 // On envoie les changements a la bande de leds
623 FastLED.show();
624
625 // Initialisation du temps d'allumage
626 beginTimer = millis();
627 }
628
629 /*************************************************************
630 Cette fonction s'execute en continue tout au long du jeu.
631 *************************************************************/
632 void loop() {
633
634 switch (gameState)
635 {
636 case START:
637 // Si un player a gagne, on affiche l'arc en ciel du cote du vainqueur
638 if (lastWinner == PLAYER1)
639 {
640 fill_rainbow(leds, NUM_LEDS / 2, counter++, 7);
641 FastLED.show();
642 }
643 else if (lastWinner == PLAYER2)
644 {
645 fill_rainbow(leds + NUM_LEDS / 2, NUM_LEDS / 2, counter++, 7);
646 FastLED.show();
647 }
648
649 // On regarde si un temps minimim s'est ecoule et si un des boutons est appuye
650 if (millis() - beginTimer > 1000 && (digitalRead(BUTTON1_PIN) == LOW || digitalRead(BUTTON2_PIN) == LOW))
651 {
652 unsigned long pushBegin = millis();
653
654 while (digitalRead(BUTTON1_PIN) == LOW || digitalRead(BUTTON2_PIN) == LOW);
655
656 if (millis() - pushBegin < 1000)
657 {
658 gameState = PONG;
659 }
660 else
661 {
662 gameState = TAC;
663 }
664
665 // On joue la note de musique
666 tone(HAUT_PARLEUR_PIN, PONG_SOUND, 100);
667
668 // Initialisation de la varable lastMillis
669 lastMillis = millis();
670
671 // Initialisation du temps de debut de jeu
672 beginTimer = millis();
673 }
674
675 break;
676
677 case PONG:
678 pong_loop();
679 break;
680
681 case TAC:
682 tac_loop();
683 break;
684 }
685 }
étapes de fabrication
indiquer autant d'étape que nécessaire, chacune illustrée par des images (phot, dessins, ...)
étape 1
étape 2
étape ...
troubleshouting
quelles sont difficultés, les problèmes, quelles sont les solutions, les trucs et astuces pour que ça marche ?