Nota
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 [Qui] e unisciti oggi stesso!
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.
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 |
Procedure Sperimentali
Passo 1: Costruisci il circuito.
Passo 2: Apri il file del codice.
cd ~/davinci-kit-for-raspberry-pi/python-pi5
Passo 3: Esegui.
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.
Avvertimento
Se appare il messaggio di errore RuntimeError: Cannot determine SOC peripheral base address, consulta Se gpiozero non funziona.
Codice
Nota
È 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.
#!/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 1.1.6 Matrice di LED.
Il codice inizia importando le librerie necessarie.
gpiozeroviene utilizzata per interagire con i pin GPIO come pulsanti e dispositivi di uscita.timepermette di aggiungere ritardi,threadingconsente di eseguire più attività contemporaneamente erandomè utile per introdurre casualità nel progetto.#!/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.# 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.
# 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
1e0corrispondono rispettivamente a un LED acceso o spento.# 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 pinSDIalto o basso di conseguenza, e attiva il pinSRCLKper far scorrere il bit nel registro.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 tramitehc595_shift, quindi attiva il pinRCLKper aggiornare la visualizzazione.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.Timerviene utilizzato per il controllo del tempo nel gioco.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
waypointsu «right», altrimenti su «wrong». Cancella quindi il timer di gioco corrente e ne avvia uno nuovo per il prossimo simbolo.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
checkPointcon «empty» per indicare che nessun pulsante è stato premuto in tempo.def timeOut(): """ Handle game timeout scenario. """ checkPoint("empty")
Questa funzione controlla lo stato dei pulsanti. Se
AButtonPinè premuto (eBButtonPinnon lo è), chiamacheckPointcon «right». SeBButtonPinè premuto (eAButtonPinnon lo è), chiamacheckPointcon «left».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
maincontrolla 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.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.
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 unaKeyboardInterrupt(come premendo Ctrl+C), cattura l’eccezione e chiamadestroyper ripulire prima di uscire.# Esegue il gioco, gestisce KeyboardInterrupt per un'uscita pulita try: main() except KeyboardInterrupt: destroy()