Saturday, January 31, 2015

Noisy Simon

I merged the Simon game with what I learned about making sounds, and managed to get a perfectly functional Simon game with sound. I changed the names of the sound channels so that I could refer to them by number instead of color, but other than that it's a pretty straight-forward adaptation.
One modification I made to the code was to add a 0.1 second delay with the sound in order to avoid the situation that the sound has not quite finished playing before the light goes off, thus creating a situation where you press a button and no sound comes out. I stumbled across this error while playing around with it, and since adding the delay this has not been a problem.
This is the end of what I consider to be things I kind of already knew how to do. The next step for me is to go into the graphical world of pygame.
import RPi.GPIO as GPIO
import time
import random
import pygame
GPIO.setmode(GPIO.BCM)

##### Debug Scripts
def log(msg):
    if DebugDisplay == True:
        print msg

##### LED Scripts
def AllLEDsOn():
    for i in range(0,5):
        GPIO.output(LED[i], GPIO.HIGH)

def AllLEDsOff():
    for i in range(0,5):
        GPIO.output(LED[i], GPIO.LOW)

def Flashes(times, pause):
    AllLEDsOff()
    for j in range(0,times):
        AllLEDsOn()
        time.sleep(0.1)
        AllLEDsOff()
        time.sleep(0.1)
    time.sleep(pause)

def LEDFlash(LEDNum, OnTime, Sound):
    GPIO.output(LED[LEDNum], GPIO.HIGH)
    if Sound == 1:
        toneChannel[LEDNum-1].play(tone[LEDNum-1])
        time.sleep(0.1)
    time.sleep(OnTime)
    GPIO.output(LED[LEDNum], GPIO.LOW)

def PlayList(Listing):
    for i in Listing:
        LEDFlash(i, 0.5, 1)
        time.sleep(0.1)
    time.sleep(1)

##### Button Scripts

def LookupButton(channel):
    for i in range(0,5):
        if channel == button[i]:
            return i

def ButtonPressed(channel):
    global Pressed, Listening, Busy
    TheButton = LookupButton(channel)
    if (TheButton == 0):
        log("Button 0 Pressed")
        Pressed = 0
        Listening = 0
    elif (TheButton > 0 and Listening == 1):
        log("Button {} Pressed -- Listening".format(TheButton))
        Pressed = TheButton
        Listening = 0
    elif (TheButton > 0 and Listening == 0):
        log("Button {} Pressed -- NOT Listening".format(TheButton))
        Pressed = -1

##### MAIN GAME LOOP
# Game Constants
DebugDisplay = False
button = [4, 12, 16, 20, 21]
LED = [22, 5, 6, 13, 19]

pygame.mixer.init(48000, -16, 1, 1024)
tone = [pygame.mixer.Sound("RedTone.ogg"), \
        pygame.mixer.Sound("YellowTone.ogg"), \
        pygame.mixer.Sound("GreenTone.ogg"), \
        pygame.mixer.Sound("BlueTone.ogg")]

toneChannel = [pygame.mixer.Channel(1), \
               pygame.mixer.Channel(2), \
               pygame.mixer.Channel(3), \
               pygame.mixer.Channel(4) ]

# Variables
Pressed = -1
Listening = 1
GameState = 1

# Set GPIO pins
for i in range (0,5):
    GPIO.setup(button[i], GPIO.IN, pull_up_down=GPIO.PUD_UP)
    GPIO.setup(LED[i], GPIO.OUT)
    GPIO.add_event_detect(button[i], GPIO.FALLING, callback=ButtonPressed, bouncetime=200)

# LED loop in waiting mode
while True:
    Listening = 1
    if GameState == 0:
        log("GameState = 0, Exiting Game")
        break
    elif GameState == 1:
        log("GameState = 1, Pressed = {}".format(Pressed))
        if Pressed == 0:
            GameState = 0
            break
        else:
            for i in range(1,5):
                LEDFlash(i,0.2,0)
                if Pressed == 0:
                    GameState = 0
                    break
                elif Pressed > 0:
                    GameState = 2
                    break
            Pressed = -1
    elif GameState == 2:
        log("GameState = 2, Pressed = {}".format(Pressed))
        Pressed = -1
        Listening = 0
        Simon = [random.randint(1,4)]
        Flashes(5, 2)
        while GameState == 2:
            log("Starting a round, length = {}".format(len(Simon)))
            Listening = 0
            PlayList(Simon)
            Flashes(1,0)
            for Levels in range(0, len(Simon)):
                log("Waiting for user input, correct answer = {}".format(Simon[Levels]))
                GPIO.output(LED[0], GPIO.HIGH)
                Listening = 1
                Pressed = -1
                for timerloop in range(0,500):
                    if Pressed > -1:
                        break
                    time.sleep(0.01)
                if Pressed == Simon[Levels]:
                    LEDFlash(Pressed, 0.5, 1)
                else:
                    toneChannel[0].play(tone[0])
                    toneChannel[1].play(tone[1])
                    toneChannel[2].play(tone[2])
                    toneChannel[3].play(tone[3])
                    Flashes(5,2)
                    GameState = 1
                    break
            GPIO.output(LED[0], GPIO.LOW)
            if (GameState == 1 and Pressed != 0):
                PlayList(Simon[0:Levels])
                for i in range(0,10):
                    LEDFlash(Simon[Levels], 0.1, 1)
                    time.sleep(0.1)
                time.sleep(1)
            elif GameState == 2:
                Simon.append(random.randint(1,4))
                time.sleep(0.2)
                Flashes(2,0)
                time.sleep(1)
        GameState = 1
        Pressed = -1

AllLEDsOff()
GPIO.cleanup()

No comments:

Post a Comment