.. note:: Ciao, benvenuto nella SunFounder Raspberry Pi & Arduino & ESP32 Enthusiasts Community su Facebook! Approfondisci le tue conoscenze su Raspberry Pi, Arduino e ESP32 con altri appassionati. **Perché unirsi a noi?** - **Supporto esperto**: Risolvi problemi post-vendita e sfide tecniche con l'aiuto della nostra community e del nostro team. - **Impara e condividi**: Scambia suggerimenti e tutorial per migliorare le tue competenze. - **Anteprime esclusive**: Ottieni accesso anticipato agli annunci dei nuovi prodotti e anteprime. - **Sconti speciali**: Approfitta di sconti esclusivi sui nostri prodotti più recenti. - **Promozioni e omaggi festivi**: Partecipa a promozioni e omaggi in occasione delle festività. 👉 Pronto per esplorare e creare insieme a noi? Clicca su [|link_sf_facebook|] e unisciti oggi stesso! .. _3.1.14_py_pi5: 3.1.14 GIOCO – Not Not ========================= Introduzione -------------------- In questa lezione, costruiremo un dispositivo per un gioco divertente chiamato "Not Not". Durante il gioco, la matrice a punti mostrerà casualmente una freccia. Il tuo compito è premere il pulsante nella direzione opposta alla freccia entro un tempo limitato. Se il tempo scade o se viene premuto il pulsante nella stessa direzione della freccia, perdi la partita. Questo gioco è un ottimo esercizio di pensiero inverso. Sei pronto per una prova? Componenti Necessari ------------------------------ Per questo progetto, ci servono i seguenti componenti. .. image:: ../python_pi5/img/3.1.14_game_not_not_list.png :width: 800 :align: center Schema Elettrico ----------------------- ============ ======== ======== === 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 Procedure Sperimentali --------------------------- **Passo 1:** Costruisci il circuito. .. image:: ../python_pi5/img/3.1.14_game_not_not_circuit.png **Passo 2:** Apri il file del codice. .. raw:: html .. code-block:: cd ~/davinci-kit-for-raspberry-pi/python-pi5 **Passo 3:** Esegui. .. raw:: html .. code-block:: sudo python3 3.1.14_MotionControl.py Dopo l'avvio del programma, sulla matrice a punti appare una freccia che punta a destra o a sinistra. Devi premere il pulsante nella direzione opposta alla freccia entro un tempo limitato. Successivamente, sulla matrice a punti apparirà il simbolo \"**√**\". Se il tempo scade o se viene premuto il pulsante nella stessa direzione della freccia, sei fuori e la matrice visualizzerà una \"x\". Puoi anche aggiungere 2 nuovi pulsanti o sostituirli con i tasti del Joystick per ottenere le quattro direzioni (su, giù, sinistra e destra) e aumentare la difficoltà del gioco. .. warning:: Se appare il messaggio di errore ``RuntimeError: Cannot determine SOC peripheral base address``, consulta :ref:`faq_soc` **Codice** .. note:: È possibile **Modificare/Reimpostare/Copiare/Eseguire/Arrestare** il codice qui sotto. Prima di farlo, però, è necessario accedere al percorso del codice sorgente, come ``davinci-kit-for-raspberry-pi/python-pi5``. Dopo aver modificato il codice, è possibile eseguirlo direttamente per vederne l'effetto. .. raw:: html .. code-block:: python #!/usr/bin/env python3 from gpiozero import OutputDevice, Button import time import threading import random # Pin GPIO per il registro a scorrimento 74HC595 SDI = OutputDevice(17) # Input Dati Seriali RCLK = OutputDevice(18) # Clock del Registro SRCLK = OutputDevice(27) # Clock del Registro a Scorrimento # GPIO pins for buttons AButtonPin = Button(20) # Button A BButtonPin = Button(26) # Button B # Game variables initialization timerPlay = 0 timerCheck = 0 waypoint = "NULL" stage = "NULL" # Arrow glyphs for LED matrix display arrow = { "right": [0xFF, 0xEF, 0xDF, 0x81, 0xDF, 0xEF, 0xFF, 0xFF], "left": [0xFF, 0xF7, 0xFB, 0x81, 0xFB, 0xF7, 0xFF, 0xFF] } # Feedback visivo per risposte corrette/sbagliate 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() # Cancel the play timer timerCheck.cancel() # Cancel the checkpoint timer # Run the game, handle KeyboardInterrupt for clean exit try: main() except KeyboardInterrupt: destroy() **Spiegazione del Codice** Basato su **1.1.6 Matrice LED**, questa lezione aggiunge **2** pulsanti per creare un dispositivo di gioco divertente. Pertanto, se non hai familiarità con la matrice LED, consulta :ref:`1.1.6_py_pi5`. #. Il codice inizia importando le librerie necessarie. ``gpiozero`` viene utilizzata per interagire con i pin GPIO come pulsanti e dispositivi di uscita. ``time`` permette di aggiungere ritardi, ``threading`` consente di eseguire più attività contemporaneamente e ``random`` è utile per introdurre casualità nel progetto. .. code-block:: python #!/usr/bin/env python3 from gpiozero import OutputDevice, Button import time import threading import random #. Inizializza i pin GPIO per il registro a scorrimento (``SDI``, ``RCLK``, ``SRCLK``) e i pulsanti (``AButtonPin``, ``BButtonPin``). Il registro a scorrimento consente di controllare più LED utilizzando meno pin GPIO, il che è essenziale per la matrice LED. .. code-block:: python # Pin GPIO per il registro a scorrimento 74HC595 SDI = OutputDevice(17) # Ingresso dati seriale RCLK = OutputDevice(18) # Clock del Registro SRCLK = OutputDevice(27) # Clock del Registro a Scorrimento # Pin GPIO per i pulsanti AButtonPin = Button(20) # Pulsante A BButtonPin = Button(26) # Pulsante B #. Inizializza le variabili utilizzate nella logica di gioco, come i timer e gli indicatori dello stato di gioco. .. code-block:: python # Inizializzazione delle variabili di gioco timerPlay = 0 timerCheck = 0 waypoint = "NULL" stage = "NULL" #. Definisce schemi binari per la visualizzazione delle frecce e del feedback (corretto/errato) sulla matrice LED. Ogni elemento dell'array rappresenta una riga della matrice, dove ``1`` e ``0`` corrispondono rispettivamente a un LED acceso o spento. .. code-block:: python # Frecce per visualizzazione su matrice LED arrow = { "right": [0xFF, 0xEF, 0xDF, 0x81, 0xDF, 0xEF, 0xFF, 0xFF], "left": [0xFF, 0xF7, 0xFB, 0x81, 0xFB, 0xF7, 0xFF, 0xFF] } # Feedback visivo per risposte corrette/sbagliate check = { "wrong": [0xFF, 0xBB, 0xD7, 0xEF, 0xD7, 0xBB, 0xFF, 0xFF], "right": [0xFF, 0xFF, 0xF7, 0xEB, 0xDF, 0xBF, 0xFF, 0xFF] } #. Questa funzione invia un byte di dati al registro a scorrimento 74HC595. Cicla su ogni bit del byte ``dat``, impostando il pin ``SDI`` alto o basso di conseguenza, e attiva il pin ``SRCLK`` per far scorrere il bit nel registro. .. 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() #. Questa funzione visualizza un simbolo sulla matrice LED. Invia ogni riga del simbolo (rappresentata da ``glyphCode``) e l'indirizzo della riga al registro a scorrimento tramite ``hc595_shift``, quindi attiva il pin ``RCLK`` per aggiornare la visualizzazione. .. 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() #. Questa funzione seleziona casualmente un simbolo dall'array ``arrow``, avvia il timer di gioco e imposta lo stato del gioco su "PLAY". ``threading.Timer`` viene utilizzato per il controllo del tempo nel gioco. .. 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() #. Questa funzione verifica la risposta del giocatore rispetto al simbolo corrente. Se la risposta è corretta, imposta ``waypoint`` su "right", altrimenti su "wrong". Cancella quindi il timer di gioco corrente e ne avvia uno nuovo per il prossimo simbolo. .. 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() #. Questa funzione viene chiamata quando il tempo del gioco scade. Invoca ``checkPoint`` con "empty" per indicare che nessun pulsante è stato premuto in tempo. .. code-block:: python def timeOut(): """ Handle game timeout scenario. """ checkPoint("empty") #. Questa funzione controlla lo stato dei pulsanti. Se ``AButtonPin`` è premuto (e ``BButtonPin`` non lo è), chiama ``checkPoint`` con "right". Se ``BButtonPin`` è premuto (e ``AButtonPin`` non lo è), chiama ``checkPoint`` con "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 funzione ``main`` controlla il flusso del gioco. Inizia creando un simbolo, quindi verifica continuamente lo stato del gioco. Se si trova nello stato "PLAY", visualizza il simbolo corrente e controlla i pulsanti. In stato "CHECK", visualizza il feedback in base all'azione del giocatore. .. code-block:: python def main(): """ Main game loop. """ creatGlyph() while True: if stage == "PLAY": display(arrow[waypoint]) getKey() elif stage == "CHECK": display(check[waypoint]) #. Questa funzione annulla eventuali timer attivi quando il programma termina, assicurando una chiusura pulita. .. code-block:: python def destroy(): """ Clean up resources on program exit. """ global timerPlay, timerCheck timerPlay.cancel() # Annulla il timer di gioco timerCheck.cancel() # Annulla il timer di verifica #. Il gioco viene eseguito in un blocco ``try``. Se si verifica una ``KeyboardInterrupt`` (come premendo Ctrl+C), cattura l'eccezione e chiama ``destroy`` per ripulire prima di uscire. .. code-block:: python # Esegue il gioco, gestisce KeyboardInterrupt per un'uscita pulita try: main() except KeyboardInterrupt: destroy()