.. note::
Bonjour et bienvenue dans la communauté Facebook des passionnés de SunFounder Raspberry Pi, Arduino et ESP32 ! Plongez plus profondément dans l'univers du Raspberry Pi, de l'Arduino et de l'ESP32 avec d'autres passionnés.
**Pourquoi nous rejoindre ?**
- **Support d'experts** : Résolvez les problèmes post-achat et les défis techniques grâce à l'aide de notre communauté et de notre équipe.
- **Apprenez & Partagez** : Échangez des astuces et des tutoriels pour améliorer vos compétences.
- **Aperçus exclusifs** : Accédez en avant-première aux nouvelles annonces de produits et aux avant-goûts.
- **Réductions spéciales** : Profitez de remises exclusives sur nos derniers produits.
- **Promotions festives et cadeaux** : Participez à nos tirages au sort et à nos promotions de saison.
👉 Prêt à explorer et à créer avec nous ? Cliquez sur [|link_sf_facebook|] et rejoignez-nous dès aujourd'hui !
.. _3.1.14_py_pi5:
3.1.14 JEU – Not Not
========================
Introduction
---------------
Dans cette leçon, nous allons créer un dispositif de jeu amusant, que nous appelons « Not Not ».
Pendant le jeu, la matrice de points affichera aléatoirement une flèche. Votre objectif est d'appuyer sur le bouton opposé à la direction de la flèche dans un temps limité. Si le temps est écoulé, ou si vous appuyez sur le bouton correspondant à la même direction que la flèche, vous perdez.
Ce jeu est idéal pour entraîner votre pensée inversée. Alors, on essaie ?
Composants nécessaires
--------------------------
Pour ce projet, nous aurons besoin des composants suivants :
.. image:: ../python_pi5/img/3.1.14_game_not_not_list.png
:width: 800
:align: center
Schéma de câblage
--------------------
============ ======== ======== ===
T-Board Name physical wiringPi BCM
GPIO17 Pin 11 0 17
GPIO18 Pin 12 1 18
GPIO27 Pin 13 2 27
GPIO20 Pin 38 28 20
GPIO26 Pin 37 25 26
============ ======== ======== ===
.. image:: ../python_pi5/img/3.1.14_game_not_not_schematic.png
:align: center
Procédures expérimentales
-----------------------------
**Étape 1 :** Construisez le circuit.
.. image:: ../python_pi5/img/3.1.14_game_not_not_circuit.png
**Étape 2 :** Ouvrez le fichier du code.
.. raw:: html
.. code-block::
cd ~/davinci-kit-for-raspberry-pi/python-pi5
**Étape 3 :** Exécutez le programme.
.. raw:: html
.. code-block::
sudo python3 3.1.14_MotionControl.py
Après le démarrage du programme, une flèche pointant vers la gauche ou la droite
apparaît sur la matrice de points. Vous devez appuyer sur le bouton dans la direction
opposée à la flèche dans un temps limité. Ensuite, le symbole \"**√**\" s'affichera sur
la matrice de points. Si le temps est écoulé ou si vous appuyez sur le bouton correspondant
à la même direction que la flèche, vous êtes éliminé et la matrice affichera \"x\". Vous
pouvez également ajouter deux nouveaux boutons ou les remplacer par des touches de joystick
pour les directions haut, bas, gauche et droite afin d'augmenter la difficulté du jeu.
.. warning::
Si vous recevez le message d'erreur ``RuntimeError: Cannot determine SOC peripheral base address``, veuillez vous référer à :ref:`faq_soc`
**Code**
.. note::
Vous pouvez **Modifier/Réinitialiser/Copier/Exécuter/Arrêter** le code ci-dessous. Mais avant cela, vous devez vous rendre dans le chemin source, tel que ``davinci-kit-for-raspberry-pi/python-pi5``. Après avoir modifié le code, vous pouvez l'exécuter directement pour voir le résultat.
.. raw:: html
.. code-block:: python
#!/usr/bin/env python3
from gpiozero import OutputDevice, Button
import time
import threading
import random
# Broches GPIO pour le registre à décalage 74HC595
SDI = OutputDevice(17) # Entrée de données série
RCLK = OutputDevice(18) # Horloge du registre
SRCLK = OutputDevice(27) # Horloge du registre à décalage
# Broches GPIO pour les boutons
AButtonPin = Button(20) # Bouton A
BButtonPin = Button(26) # Bouton B
# Initialisation des variables de jeu
timerPlay = 0
timerCheck = 0
waypoint = "NULL"
stage = "NULL"
# Glyphes des flèches pour l'affichage sur la matrice LED
arrow = {
"right": [0xFF, 0xEF, 0xDF, 0x81, 0xDF, 0xEF, 0xFF, 0xFF],
"left": [0xFF, 0xF7, 0xFB, 0x81, 0xFB, 0xF7, 0xFF, 0xFF]
}
# Glyphes de retour pour les réponses correctes/incorrectes
check = {
"wrong": [0xFF, 0xBB, 0xD7, 0xEF, 0xD7, 0xBB, 0xFF, 0xFF],
"right": [0xFF, 0xFF, 0xF7, 0xEB, 0xDF, 0xBF, 0xFF, 0xFF]
}
def hc595_shift(dat):
""" Shift data to the 74HC595 shift register. """
for i in range(8):
SDI.value = 0x80 & (dat << i)
SRCLK.on()
SRCLK.off()
def display(glyphCode):
""" Display a glyph on the LED matrix. """
for i in range(0, 8):
hc595_shift(glyphCode[i])
hc595_shift(0x80 >> i)
RCLK.on()
RCLK.off()
def creatGlyph():
""" Create a new glyph for the game and start the play timer. """
global waypoint, stage, timerPlay
waypoint = random.choice(list(arrow.keys()))
stage = "PLAY"
timerPlay = threading.Timer(2.0, timeOut)
timerPlay.start()
def checkPoint(inputKey):
""" Check player's input and update game state. """
global waypoint, stage, timerCheck
if inputKey == "empty" or inputKey == waypoint:
waypoint = "wrong"
else:
waypoint = "right"
timerPlay.cancel()
stage = "CHECK"
timerCheck = threading.Timer(1.0, creatGlyph)
timerCheck.start()
def timeOut():
""" Handle game timeout scenario. """
checkPoint("empty")
def getKey():
""" Detect button press and trigger checkpoint. """
if AButtonPin.is_pressed and not BButtonPin.is_pressed:
checkPoint("right")
elif not AButtonPin.is_pressed and BButtonPin.is_pressed:
checkPoint("left")
def main():
""" Main game loop. """
creatGlyph()
while True:
if stage == "PLAY":
display(arrow[waypoint])
getKey()
elif stage == "CHECK":
display(check[waypoint])
def destroy():
""" Clean up resources on program exit. """
global timerPlay, timerCheck
timerPlay.cancel() # Annule le minuteur de jeu
timerCheck.cancel() # Annule le minuteur de vérification
# Exécute le jeu et gère l'interruption clavier pour une sortie propre
try:
main()
except KeyboardInterrupt:
destroy()
**Explication du Code**
Basé sur la leçon **1.1.6 Matrice LED**, cette activité ajoute **2** boutons pour créer un dispositif de jeu amusant. Si vous n'êtes pas encore très familier avec la matrice LED, veuillez vous référer à :ref:`1.1.6_py_pi5`.
#. Le code commence par importer les bibliothèques nécessaires. ``gpiozero`` est utilisé pour interagir avec les broches GPIO, comme les boutons et les dispositifs de sortie. ``time`` permet d'ajouter des délais, ``threading`` permet d'exécuter plusieurs tâches simultanément, et ``random`` est utile pour introduire de l'aléatoire dans le projet.
.. code-block:: python
#!/usr/bin/env python3
from gpiozero import OutputDevice, Button
import time
import threading
import random
#. Initialisation des broches GPIO pour le registre à décalage (``SDI``, ``RCLK``, ``SRCLK``) et pour les boutons (``AButtonPin``, ``BButtonPin``). Le registre à décalage permet de contrôler plusieurs LED avec moins de broches GPIO, ce qui est essentiel pour l'affichage sur la matrice LED.
.. code-block:: python
# Broches GPIO pour le registre à décalage 74HC595
SDI = OutputDevice(17) # Entrée de données série
RCLK = OutputDevice(18) # Horloge du registre
SRCLK = OutputDevice(27) # Horloge du registre à décalage
# Broches GPIO pour les boutons
AButtonPin = Button(20) # Bouton A
BButtonPin = Button(26) # Bouton B
#. Initialisation des variables utilisées dans la logique du jeu, telles que les minuteurs et les indicateurs d'état du jeu.
.. code-block:: python
# Initialisation des variables de jeu
timerPlay = 0
timerCheck = 0
waypoint = "NULL"
stage = "NULL"
#. Définit les motifs binaires pour afficher les flèches et les retours (correct/incorrect) sur la matrice LED. Chaque élément du tableau représente une ligne de la matrice LED, où ``1`` et ``0`` correspondent respectivement à une LED allumée ou éteinte.
.. code-block:: python
# Glyphes de flèches pour l'affichage sur la matrice LED
arrow = {
"right": [0xFF, 0xEF, 0xDF, 0x81, 0xDF, 0xEF, 0xFF, 0xFF],
"left": [0xFF, 0xF7, 0xFB, 0x81, 0xFB, 0xF7, 0xFF, 0xFF]
}
# Glyphes de retour pour les réponses correctes/incorrectes
check = {
"wrong": [0xFF, 0xBB, 0xD7, 0xEF, 0xD7, 0xBB, 0xFF, 0xFF],
"right": [0xFF, 0xFF, 0xF7, 0xEB, 0xDF, 0xBF, 0xFF, 0xFF]
}
#. Cette fonction transfère un octet de données vers le registre à décalage 74HC595. Elle parcourt chaque bit de l'octet ``dat``, règle la broche ``SDI`` sur haut ou bas en conséquence, et bascule la broche ``SRCLK`` pour déplacer le bit dans le registre.
.. code-block:: python
def hc595_shift(dat):
""" Shift data to the 74HC595 shift register. """
for i in range(8):
SDI.value = 0x80 & (dat << i)
SRCLK.on()
SRCLK.off()
#. Cette fonction affiche un glyphe sur la matrice LED. Elle envoie chaque ligne du glyphe (représentée par ``glyphCode``) et l'adresse de la ligne au registre à décalage en utilisant ``hc595_shift``, puis bascule la broche ``RCLK`` pour mettre à jour l'affichage.
.. code-block:: python
def display(glyphCode):
""" Display a glyph on the LED matrix. """
for i in range(0, 8):
hc595_shift(glyphCode[i])
hc595_shift(0x80 >> i)
RCLK.on()
RCLK.off()
#. Cette fonction sélectionne aléatoirement un glyphe du dictionnaire ``arrow``, démarre le minuteur de jeu et définit l'état du jeu à "PLAY". ``threading.Timer`` est utilisé pour le contrôle du temps dans le jeu.
.. code-block:: python
def creatGlyph():
""" Create a new glyph for the game and start the play timer. """
global waypoint, stage, timerPlay
waypoint = random.choice(list(arrow.keys()))
stage = "PLAY"
timerPlay = threading.Timer(2.0, timeOut)
timerPlay.start()
#. Cette fonction vérifie l'entrée du joueur par rapport au glyphe actuel. Si l'entrée est correcte, elle règle le waypoint sur "right", sinon sur "wrong". Elle annule ensuite le minuteur de jeu actuel et démarre un nouveau minuteur pour le prochain glyphe.
.. code-block:: python
def checkPoint(inputKey):
""" Check player's input and update game state. """
global waypoint, stage, timerCheck
if inputKey == "empty" or inputKey == waypoint:
waypoint = "wrong"
else:
waypoint = "right"
timerPlay.cancel()
stage = "CHECK"
timerCheck = threading.Timer(1.0, creatGlyph)
timerCheck.start()
#. Cette fonction est appelée lorsque le temps imparti est écoulé. Elle invoque ``checkPoint`` avec "empty" pour indiquer qu'aucun bouton n'a été pressé à temps.
.. code-block:: python
def timeOut():
""" Handle game timeout scenario. """
checkPoint("empty")
#. Cette fonction vérifie l'état des boutons. Si ``AButtonPin`` est pressé (et ``BButtonPin`` ne l'est pas), elle appelle ``checkPoint`` avec "right". Si ``BButtonPin`` est pressé (et ``AButtonPin`` ne l'est pas), elle appelle ``checkPoint`` avec "left".
.. code-block:: python
def getKey():
""" Detect button press and trigger checkpoint. """
if AButtonPin.is_pressed and not BButtonPin.is_pressed:
checkPoint("right")
elif not AButtonPin.is_pressed and BButtonPin.is_pressed:
checkPoint("left")
#. La fonction ``main`` contrôle le déroulement du jeu. Elle commence par créer un glyphe, puis vérifie continuellement l'état du jeu. Si l'état est "PLAY", elle affiche le glyphe actuel et vérifie les pressions de bouton. Si l'état est "CHECK", elle affiche le retour d'information en fonction de l'action du joueur.
.. code-block:: python
def main():
""" Main game loop. """
creatGlyph()
while True:
if stage == "PLAY":
display(arrow[waypoint])
getKey()
elif stage == "CHECK":
display(check[waypoint])
#. Cette fonction annule tous les minuteurs en cours lors de la sortie du programme, assurant ainsi une fermeture propre.
.. code-block:: python
def destroy():
""" Clean up resources on program exit. """
global timerPlay, timerCheck
timerPlay.cancel() # Annule le minuteur de jeu
timerCheck.cancel() # Annule le minuteur de vérification
#. Le jeu est exécuté dans un bloc ``try``. Si une ``KeyboardInterrupt`` (comme en appuyant sur Ctrl+C) se produit, l'exception est interceptée et ``destroy`` est appelé pour nettoyer avant de quitter.
.. code-block:: python
# Exécute le jeu et gère l'interruption clavier pour une sortie propre
try:
main()
except KeyboardInterrupt:
destroy()