added next major revision with cleanups and documentation
This commit is contained in:
		
							
								
								
									
										769
									
								
								gametest_rev2.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										769
									
								
								gametest_rev2.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,769 @@
 | 
			
		||||
#!/usr/bin/env python
 | 
			
		||||
#coding=utf-8
 | 
			
		||||
 | 
			
		||||
############################################
 | 
			
		||||
########### GENERAL INFORMATION ############
 | 
			
		||||
############################################
 | 
			
		||||
 | 
			
		||||
"""
 | 
			
		||||
This is the software for the project heisser_draht from the bfi itlabs st.stefan
 | 
			
		||||
 | 
			
		||||
The idea of the game is to follow a wire with a ring, without touching it.
 | 
			
		||||
The ones with the fastest times to reach the end (and with the least errors)
 | 
			
		||||
are written onto the highscore table. Said table is temporary, and not saved on exit!
 | 
			
		||||
 | 
			
		||||
The main game loop is running in 4 states:
 | 
			
		||||
 | 
			
		||||
    * The game is not running and not ending (State 0)
 | 
			
		||||
        This state is the default "starting" page of the game.
 | 
			
		||||
        The screen shows the highscore table, and the game waits for a start signal.
 | 
			
		||||
 | 
			
		||||
    * The game is running and not ending (State 1)
 | 
			
		||||
        This is the game running. A timer is displayed on screen.
 | 
			
		||||
        Errors are shown on screen aswell.
 | 
			
		||||
        The game is waiting for error signals and stop signals
 | 
			
		||||
 | 
			
		||||
    * The game is not running and ending (State 2)
 | 
			
		||||
        Once the stop signal has been reached in the running game, this state is reached.
 | 
			
		||||
        The game checks for highscores and asks for a name, should a highscore have been made.
 | 
			
		||||
        This state automatically ends after a few seconds and returns the game to State 0.
 | 
			
		||||
 | 
			
		||||
    * The game is neither running nor ending (State 3)
 | 
			
		||||
        This state is currently invalid and does nothing. it should never be reached.
 | 
			
		||||
        there's no functionality assigned to this, and this state is never run, but included
 | 
			
		||||
        for completeness sake.
 | 
			
		||||
 | 
			
		||||
The game also features a (not entirely interactive) LED lighting control. The LEDs are supposed
 | 
			
		||||
to be driven by a small MOSFET driver circuit. DO NOT ATTACH LEDS DIRECTLY!
 | 
			
		||||
The correct type of LEDs are the ones that have a common 12V rail per segment, and are switched
 | 
			
		||||
by clamping the ground. Those ground clamps are driven by the Raspberry via a PWM signal.
 | 
			
		||||
 | 
			
		||||
Pin explanation:
 | 
			
		||||
 | 
			
		||||
pin_blue, pin_green, pin_red
 | 
			
		||||
 | 
			
		||||
    Type: PWM Output
 | 
			
		||||
    Use: These pins are for controlling the lighting. They are to be connected to a  MOSFET driver stage
 | 
			
		||||
    that clamps the ground.
 | 
			
		||||
 | 
			
		||||
pin_start
 | 
			
		||||
 | 
			
		||||
    Type: Input, Pull Up
 | 
			
		||||
    Use: Start pin. If this is active, the game starts.
 | 
			
		||||
 | 
			
		||||
pin_stop
 | 
			
		||||
 | 
			
		||||
    Type: Input, Pull Up
 | 
			
		||||
    Use: Stop pin. If this is active, the game ends
 | 
			
		||||
 | 
			
		||||
pin_error
 | 
			
		||||
 | 
			
		||||
    Type: Input, Pull Up
 | 
			
		||||
    Use: This is to be attached to the game wire. If the wire is touched,
 | 
			
		||||
    the pin is pulled up and an error is registered.
 | 
			
		||||
 | 
			
		||||
pin_shutdown
 | 
			
		||||
 | 
			
		||||
    Type: Input, Pull Up
 | 
			
		||||
    Use: Triggering this input causes a system shutdown.
 | 
			
		||||
 | 
			
		||||
GPIO Pinout for assembly:
 | 
			
		||||
 | 
			
		||||
              3V3  (1) (2)  5V
 | 
			
		||||
                -  (3) (4)  5V
 | 
			
		||||
                -  (5) (6)  GND
 | 
			
		||||
                -  (7) (8)  -
 | 
			
		||||
              GND  (9) (10) -
 | 
			
		||||
                - (11) (12) -
 | 
			
		||||
                - (13) (14) GND
 | 
			
		||||
                - (15) (16) pin_blue
 | 
			
		||||
              3V3 (17) (18) pin_green
 | 
			
		||||
                - (19) (20) GND
 | 
			
		||||
                - (21) (22) pin_red
 | 
			
		||||
                - (23) (24) -
 | 
			
		||||
              GND (25) (26) -
 | 
			
		||||
                - (27) (28) -
 | 
			
		||||
                - (29) (30) GND
 | 
			
		||||
                - (31) (32) pin_start
 | 
			
		||||
        pin_error (33) (34) GND
 | 
			
		||||
                - (35) (36) pin_shutdown
 | 
			
		||||
         pin_stop (37) (38) -
 | 
			
		||||
              GND (39) (40) -
 | 
			
		||||
 | 
			
		||||
Default state of pins:
 | 
			
		||||
 | 
			
		||||
32: pull up
 | 
			
		||||
33: pull up
 | 
			
		||||
36: pull up
 | 
			
		||||
37: pull up
 | 
			
		||||
 | 
			
		||||
Make sure leds are on pull-up default pins
 | 
			
		||||
so when their state is undefined, the led
 | 
			
		||||
strips are switched off!
 | 
			
		||||
 | 
			
		||||
22: pull up
 | 
			
		||||
18: pull up
 | 
			
		||||
16: pull up
 | 
			
		||||
 | 
			
		||||
Credits:
 | 
			
		||||
Based on a script made by TODO: source, although it has been heavily altered
 | 
			
		||||
Changes made by: Clima Philip, Krajnc Moris, Glantschnig Raphael
 | 
			
		||||
 | 
			
		||||
Hosted on:
 | 
			
		||||
https://git.wolfsberg.local/philip.clima/heisser_draht
 | 
			
		||||
 | 
			
		||||
"""
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
############################################
 | 
			
		||||
############# START OF IMPORTS #############
 | 
			
		||||
############################################
 | 
			
		||||
import signal
 | 
			
		||||
import sys
 | 
			
		||||
import os
 | 
			
		||||
import pygame
 | 
			
		||||
from PIL import Image
 | 
			
		||||
from pygame.locals import *
 | 
			
		||||
import RPi.GPIO as GPIO
 | 
			
		||||
 | 
			
		||||
############################################
 | 
			
		||||
############## END OF IMPORTS ##############
 | 
			
		||||
############################################
 | 
			
		||||
 | 
			
		||||
############################################
 | 
			
		||||
########### START OF DEFINITIONS ###########
 | 
			
		||||
############################################
 | 
			
		||||
 | 
			
		||||
# base pygame settings
 | 
			
		||||
pygame_fps = 30 #frames per second setting
 | 
			
		||||
pygame_clock = pygame.time.Clock()
 | 
			
		||||
 | 
			
		||||
# GPIO for Buttons
 | 
			
		||||
pin_start = 32
 | 
			
		||||
pin_stop = 37
 | 
			
		||||
pin_error = 33
 | 
			
		||||
pin_shutdown = 36
 | 
			
		||||
 | 
			
		||||
# GPIO for LED
 | 
			
		||||
pin_red = 22
 | 
			
		||||
pin_green = 18
 | 
			
		||||
pin_blue = 16
 | 
			
		||||
 | 
			
		||||
# other constants
 | 
			
		||||
# every time the wire is touched, some time is added as penalty.
 | 
			
		||||
# number is in ms
 | 
			
		||||
time_per_error = 5000
 | 
			
		||||
 | 
			
		||||
# screen settings
 | 
			
		||||
screen_size_x = 1920
 | 
			
		||||
screen_size_y = 1080
 | 
			
		||||
 | 
			
		||||
# name length for highscores
 | 
			
		||||
max_name_length = 10
 | 
			
		||||
 | 
			
		||||
# preset highscores
 | 
			
		||||
hs1_name = "Fritz"
 | 
			
		||||
hs2_name = "Bernd"
 | 
			
		||||
hs3_name = "Max"
 | 
			
		||||
hs1_time = 100
 | 
			
		||||
hs2_time = 200
 | 
			
		||||
hs3_time = 300
 | 
			
		||||
 | 
			
		||||
############################################
 | 
			
		||||
############ END OF DEFINITIONS ############
 | 
			
		||||
############################################
 | 
			
		||||
 | 
			
		||||
############################################
 | 
			
		||||
####### START OF PRE-INITIALISATION ########
 | 
			
		||||
############################################
 | 
			
		||||
 | 
			
		||||
# here goes stuff that is requires by functions
 | 
			
		||||
# so they can be properly defined
 | 
			
		||||
 | 
			
		||||
# initialise the game
 | 
			
		||||
pygame.init()
 | 
			
		||||
 | 
			
		||||
# fonts
 | 
			
		||||
pygame_font_1 = pygame.font.Font('freesansbold.ttf', 90)
 | 
			
		||||
pygame_font_2 = pygame.font.Font('freesansbold.ttf', 65)
 | 
			
		||||
pygame_font_3 = pygame.font.Font('freesansbold.ttf', 45)
 | 
			
		||||
 | 
			
		||||
# colors
 | 
			
		||||
pygame_color_green = pygame.Color(42, 217, 13)
 | 
			
		||||
pygame_color_black = pygame.Color(0, 0, 0)
 | 
			
		||||
pygame_color_white = pygame.Color(255, 255, 255)
 | 
			
		||||
pygame_color_yellow = pygame.Color(255, 215, 0)
 | 
			
		||||
pygame_color_grey = pygame.Color(196, 202, 206)
 | 
			
		||||
pygame_color_brown = pygame.Color(177, 86, 15)
 | 
			
		||||
 | 
			
		||||
# font colors
 | 
			
		||||
pygame_font_main_color = pygame_color_black
 | 
			
		||||
 | 
			
		||||
# initialise gpio
 | 
			
		||||
GPIO.setmode(GPIO.BOARD)
 | 
			
		||||
GPIO.setup(pin_start, GPIO.IN)
 | 
			
		||||
GPIO.setup(pin_error, GPIO.IN)
 | 
			
		||||
GPIO.setup(pin_shutdown, GPIO.IN)
 | 
			
		||||
 | 
			
		||||
# predefinition of led variables, for use in functions
 | 
			
		||||
led_red = 0
 | 
			
		||||
led_green = 0
 | 
			
		||||
led_blue = 0
 | 
			
		||||
 | 
			
		||||
############################################
 | 
			
		||||
######## END OF PRE-INITIALISATION #########
 | 
			
		||||
############################################
 | 
			
		||||
 | 
			
		||||
############################################
 | 
			
		||||
###### START OF FUNCTION DEFINITIONS #######
 | 
			
		||||
############################################
 | 
			
		||||
 | 
			
		||||
def get_image_width(filepath):
 | 
			
		||||
    """get the width of an image"""
 | 
			
		||||
    return (Image.open(filepath).size)[0]
 | 
			
		||||
 | 
			
		||||
def get_image_height(filepath):
 | 
			
		||||
    """get the height of an image"""
 | 
			
		||||
    return (Image.open(filepath).size)[1]
 | 
			
		||||
 | 
			
		||||
def signal_handler(sig, frame):
 | 
			
		||||
    """
 | 
			
		||||
    signal handler, later called to interpret
 | 
			
		||||
    ctrl+c as "quit" rather than "abort"
 | 
			
		||||
    """
 | 
			
		||||
    print('Programm exiting')
 | 
			
		||||
    exit_application()
 | 
			
		||||
 | 
			
		||||
def led_init():
 | 
			
		||||
    """
 | 
			
		||||
    initialises the LED pins
 | 
			
		||||
    mind that the pins for the LEDs are pullup by default,
 | 
			
		||||
    which is on purpose, since this causes the LED strip to
 | 
			
		||||
    be turned off when the program isnt running or their state
 | 
			
		||||
    is undefined
 | 
			
		||||
 | 
			
		||||
    set the led pins to be outputs
 | 
			
		||||
    careful: these pins dont drive the
 | 
			
		||||
    led strip themselves, but rather 3
 | 
			
		||||
    n-channel mosfets, type IRLZ34N
 | 
			
		||||
    """
 | 
			
		||||
    global led_red, led_green, led_blue
 | 
			
		||||
    GPIO.setup(pin_red, GPIO.OUT)
 | 
			
		||||
    GPIO.setup(pin_green, GPIO.OUT)
 | 
			
		||||
    GPIO.setup(pin_blue, GPIO.OUT)
 | 
			
		||||
 | 
			
		||||
    # set the pwm frequency to 100
 | 
			
		||||
    # if you experience strobing, try changing
 | 
			
		||||
    # the number
 | 
			
		||||
    led_red = GPIO.PWM(pin_red, 100)
 | 
			
		||||
    led_blue = GPIO.PWM(pin_blue, 100)
 | 
			
		||||
    led_green = GPIO.PWM(pin_green, 100)
 | 
			
		||||
 | 
			
		||||
    # start pwm generation with a duty cycle of 0
 | 
			
		||||
    led_green.start(0)
 | 
			
		||||
    led_blue.start(0)
 | 
			
		||||
    led_red.start(0)
 | 
			
		||||
 | 
			
		||||
def change_red(amount):
 | 
			
		||||
    """
 | 
			
		||||
    takes an input from 0 to 255 and converts it to Duty Cycle
 | 
			
		||||
    valid duty cycle values are between 0 and 100
 | 
			
		||||
    stores the new value in led_brightness_COLOUR
 | 
			
		||||
    this value is later read by the led_handler to set the
 | 
			
		||||
    corresponding duty cycles to allow fast interactive updating
 | 
			
		||||
    to be used by change_led_colour
 | 
			
		||||
    """
 | 
			
		||||
 | 
			
		||||
    global led_red
 | 
			
		||||
    factor = 100/255
 | 
			
		||||
    led_green.ChangeDutyCycle(amount*factor)
 | 
			
		||||
 | 
			
		||||
def change_green(amount):
 | 
			
		||||
    """
 | 
			
		||||
    takes an input from 0 to 255 and converts it to Duty Cycle
 | 
			
		||||
    valid duty cycle values are between 0 and 100
 | 
			
		||||
    stores the new value in led_brightness_COLOUR
 | 
			
		||||
    this value is later read by the led_handler to set the
 | 
			
		||||
    corresponding duty cycles to allow fast interactive updating
 | 
			
		||||
    to be used by change_led_colour
 | 
			
		||||
    """
 | 
			
		||||
 | 
			
		||||
    global led_green
 | 
			
		||||
    factor = 100/255
 | 
			
		||||
    led_green.ChangeDutyCycle(amount*factor)
 | 
			
		||||
 | 
			
		||||
def change_blue(amount):
 | 
			
		||||
    """
 | 
			
		||||
    takes an input from 0 to 255 and converts it to Duty Cycle
 | 
			
		||||
    valid duty cycle values are between 0 and 100
 | 
			
		||||
    stores the new value in led_brightness_COLOUR
 | 
			
		||||
    this value is later read by the led_handler to set the
 | 
			
		||||
    corresponding duty cycles to allow fast interactive updating
 | 
			
		||||
    to be used by change_led_colour
 | 
			
		||||
    """
 | 
			
		||||
 | 
			
		||||
    global led_blue
 | 
			
		||||
    factor = 100/255
 | 
			
		||||
    led_blue.ChangeDutyCycle(amount*factor)
 | 
			
		||||
 | 
			
		||||
def change_led_colour(red_amount, green_amount, blue_amount):
 | 
			
		||||
    """
 | 
			
		||||
    takes an rgb value as input
 | 
			
		||||
    and converts it to duty cycles
 | 
			
		||||
    and then applies that.
 | 
			
		||||
    """
 | 
			
		||||
    global led_red, led_green, led_blue
 | 
			
		||||
    # sets an RGB value for the led strip.
 | 
			
		||||
    if red_amount < 0 or red_amount > 255:
 | 
			
		||||
        # valid rgb values should be between 0 and 255
 | 
			
		||||
        print('change_led_colour: invalid red value received: ' + str(red_amount))
 | 
			
		||||
        return False
 | 
			
		||||
    if green_amount < 0 or green_amount > 255:
 | 
			
		||||
        # valid rgb values should be between 0 and 255
 | 
			
		||||
        print('change_led_colour: invalid green value received: '+ str(green_amount))
 | 
			
		||||
        return False
 | 
			
		||||
    if blue_amount < 0 or blue_amount > 255:
 | 
			
		||||
        # valid rgb values should be between 0 and 255
 | 
			
		||||
        print('change_led_colour: invalid blue value received: ' + str(blue_amount))
 | 
			
		||||
        return False
 | 
			
		||||
 | 
			
		||||
    change_red(red_amount)
 | 
			
		||||
    change_blue(blue_amount)
 | 
			
		||||
    change_green(green_amount)
 | 
			
		||||
    return True
 | 
			
		||||
 | 
			
		||||
def toggle_fullscreen():
 | 
			
		||||
    """switches the game to fullscreen"""
 | 
			
		||||
    screen = pygame.display.get_surface()
 | 
			
		||||
    tmp = screen.convert()
 | 
			
		||||
    caption = pygame.display.get_caption()
 | 
			
		||||
    cursor = pygame.mouse.get_cursor() # Duoas 16-04-2007
 | 
			
		||||
 | 
			
		||||
    screen_width, screen_height = screen.get_width(), screen.get_height()
 | 
			
		||||
    flags = screen.get_flags()
 | 
			
		||||
    bits = screen.get_bitsize()
 | 
			
		||||
 | 
			
		||||
    pygame.display.quit()
 | 
			
		||||
    pygame.display.init()
 | 
			
		||||
 | 
			
		||||
    screen = pygame.display.set_mode((screen_width, screen_height), flags^FULLSCREEN, bits)
 | 
			
		||||
    screen.blit(tmp, (0, 0))
 | 
			
		||||
    pygame.display.set_caption(*caption)
 | 
			
		||||
 | 
			
		||||
    pygame.key.set_mods(0) # HACK: work-a-round for a SDL bug??
 | 
			
		||||
 | 
			
		||||
    pygame.mouse.set_cursor(*cursor) # Duoas 16-04-2007
 | 
			
		||||
    return screen
 | 
			
		||||
 | 
			
		||||
def clear_screen():
 | 
			
		||||
    """fills the screen with a colour"""
 | 
			
		||||
    screen.fill(pygame_color_white)
 | 
			
		||||
 | 
			
		||||
def handle_events():
 | 
			
		||||
    """looks for things to do every tick"""
 | 
			
		||||
    for event in pygame.event.get():
 | 
			
		||||
        if event.type == KEYDOWN and event.key == K_ESCAPE:
 | 
			
		||||
            exit_application()
 | 
			
		||||
 | 
			
		||||
    # shutdown raspberry if shutdown pin is detected
 | 
			
		||||
    if GPIO.INPUT(pin_shutdown):
 | 
			
		||||
        shutdown_raspberry()
 | 
			
		||||
 | 
			
		||||
def exit_application():
 | 
			
		||||
    """ exit the application with proper cleanup"""
 | 
			
		||||
    pygame.quit()
 | 
			
		||||
    GPIO.cleanup()
 | 
			
		||||
    sys.exit()
 | 
			
		||||
 | 
			
		||||
def shutdown_raspberry():
 | 
			
		||||
    """shutdown the system with proper cleanup"""
 | 
			
		||||
    pygame.quit()
 | 
			
		||||
    GPIO.cleanup()
 | 
			
		||||
    os.system("sudo shutdown -h now")
 | 
			
		||||
 | 
			
		||||
def enter_name():
 | 
			
		||||
    """asks for a name on screen and then returns that name"""
 | 
			
		||||
    clear_screen()
 | 
			
		||||
    print('text entry started')
 | 
			
		||||
    name = ''
 | 
			
		||||
    while True:
 | 
			
		||||
        clear_screen()
 | 
			
		||||
 | 
			
		||||
        # add all needed surfaces
 | 
			
		||||
        highscore_surface = pygame_font_1.render('High Score!', True, pygame_font_main_color)
 | 
			
		||||
        highscore_rectangle = highscore_surface.get_rect()
 | 
			
		||||
        highscore_rectangle.topleft = (700, 250)
 | 
			
		||||
 | 
			
		||||
        screen.blit(highscore_surface, highscore_rectangle)
 | 
			
		||||
 | 
			
		||||
        textbox_text_surface = pygame_font_2.render('Enter Name:', True, pygame_font_main_color)
 | 
			
		||||
        textbox_text_rectangle = textbox_text_surface.get_rect()
 | 
			
		||||
        textbox_text_rectangle.topleft = (700, 400)
 | 
			
		||||
 | 
			
		||||
        textbox_surface = pygame_font_2.render(str(name), True, pygame_font_main_color)
 | 
			
		||||
        textbox_rectangle = textbox_surface.get_rect()
 | 
			
		||||
        textbox_rectangle.topleft = (800, 480)
 | 
			
		||||
 | 
			
		||||
        # draw everything
 | 
			
		||||
        screen.blit(textbox_text_surface, textbox_text_rectangle)
 | 
			
		||||
        screen.blit(textbox_surface, textbox_rectangle)
 | 
			
		||||
 | 
			
		||||
        # add the border and logos
 | 
			
		||||
        draw_border()
 | 
			
		||||
        draw_logos()
 | 
			
		||||
 | 
			
		||||
        # display everything
 | 
			
		||||
        pygame.display.flip()
 | 
			
		||||
 | 
			
		||||
        # handle key events
 | 
			
		||||
        for event in pygame.event.get():
 | 
			
		||||
            # read new keys for as long as the max length for the name hasnt been reached
 | 
			
		||||
            if len(name) < max_name_length:
 | 
			
		||||
                if event.type == KEYDOWN:
 | 
			
		||||
                    # if someone presses the erase key, erase 1 letter
 | 
			
		||||
                    if event.key == pygame.K_BACKSPACE:
 | 
			
		||||
                        name = name[:-1]
 | 
			
		||||
                    # if enter is pressed with at least 1 letter as the name,
 | 
			
		||||
                    # return the name
 | 
			
		||||
                    elif event.key == pygame.K_RETURN and len(name) > 0:
 | 
			
		||||
                        clear_screen()
 | 
			
		||||
                        return name
 | 
			
		||||
                    # if enter is pressed without any letters in the name,
 | 
			
		||||
                    # dont return a name. do nothing instead.
 | 
			
		||||
                    elif event.key == pygame.K_RETURN:
 | 
			
		||||
                        # do nothing
 | 
			
		||||
                        pass
 | 
			
		||||
                    # if escape is pressed, exit.
 | 
			
		||||
                    # this prevents lockups since the main game loop is not running inside this function.
 | 
			
		||||
                    elif event.key == pygame.K_ESCAPE:
 | 
			
		||||
                        exit_application()
 | 
			
		||||
                    # for any other key, add the letter to the name
 | 
			
		||||
                    # Caution: this includes all sorts of weird letters, control sequences, and other unprintable chars.
 | 
			
		||||
                    else:
 | 
			
		||||
                        name += event.unicode
 | 
			
		||||
            # none of the following may be needed
 | 
			
		||||
            # TODO: Testing
 | 
			
		||||
            # if someone presses the erase key, erase 1 letter
 | 
			
		||||
            #elif event.key == pygame.K_BACKSPACE:
 | 
			
		||||
            #    name = name[:-1]
 | 
			
		||||
            #
 | 
			
		||||
            #elif event.type == KEYDOWN and event.key == pygame.K_RETURN:
 | 
			
		||||
            #    clear_screen()
 | 
			
		||||
            #    return name
 | 
			
		||||
 | 
			
		||||
    # this part of the code should be unreachable, and only here in case the event handling goes wrong horribly.
 | 
			
		||||
    clear_screen()
 | 
			
		||||
    name = 'Error'
 | 
			
		||||
    return name
 | 
			
		||||
 | 
			
		||||
def check_highscores(time):
 | 
			
		||||
    """
 | 
			
		||||
    check if a new highscore has been made
 | 
			
		||||
    this is coded in a horrible way and adding more than 3 high scores with this sorta system would be too much work.
 | 
			
		||||
    """
 | 
			
		||||
    global hs1_time, hs2_time, hs3_time, hs1_name, hs2_name, hs3_name
 | 
			
		||||
    if time <= hs1_time:
 | 
			
		||||
        print('new high score:'+str(time))
 | 
			
		||||
        # make the second the third
 | 
			
		||||
        hs3_time = hs2_time
 | 
			
		||||
        hs3_name = hs2_name
 | 
			
		||||
 | 
			
		||||
        # make the first the second
 | 
			
		||||
        hs2_time = hs1_time
 | 
			
		||||
        hs2_name = hs1_name
 | 
			
		||||
 | 
			
		||||
        # new high score
 | 
			
		||||
        hs1_time = time
 | 
			
		||||
        hs1_name = enter_name()
 | 
			
		||||
        return True
 | 
			
		||||
    elif time <= hs2_time:
 | 
			
		||||
        print('new second:'+str(time))
 | 
			
		||||
 | 
			
		||||
        # make the second the third
 | 
			
		||||
        hs3_time = hs2_time
 | 
			
		||||
        hs3_name = hs2_name
 | 
			
		||||
 | 
			
		||||
        # new second time
 | 
			
		||||
        hs2_time = time
 | 
			
		||||
        hs2_name = enter_name()
 | 
			
		||||
        return True
 | 
			
		||||
    elif time <= hs3_time:
 | 
			
		||||
        print('new third:'+str(time))
 | 
			
		||||
        hs3_time = time
 | 
			
		||||
        hs3_name = enter_name()
 | 
			
		||||
        return True
 | 
			
		||||
    else:
 | 
			
		||||
        return False
 | 
			
		||||
 | 
			
		||||
def draw_border():
 | 
			
		||||
    """draw logos"""
 | 
			
		||||
    screen.blit(img_itlablogo_image, (screen_size_x-img_itlablogo_imagex-20, screen_size_y-img_itlablogo_imagey-20))
 | 
			
		||||
    # TODO: Metallic Logo
 | 
			
		||||
 | 
			
		||||
def draw_logos():
 | 
			
		||||
    """draw rectangle border around everything"""
 | 
			
		||||
    pygame.draw.rect(screen, pygame_color_black, (500, 200, (screen_size_x-500*2), (screen_size_y-200*2)), 5)
 | 
			
		||||
 | 
			
		||||
def show_debug():
 | 
			
		||||
    """show debug information"""
 | 
			
		||||
    print('#############')
 | 
			
		||||
    print('Game running: ' + str(game_running))
 | 
			
		||||
    print('Game ending: ' + str(game_ending))
 | 
			
		||||
    print('Pin status: ')
 | 
			
		||||
    print('Start pin: ' + str(GPIO.INPUT(pin_start)))
 | 
			
		||||
    print('Error pin: ' + str(GPIO.INPUT(pin_error)))
 | 
			
		||||
    print('Shutdown pin: ' + str(GPIO.input(pin_shutdown)))
 | 
			
		||||
    print('#############')
 | 
			
		||||
 | 
			
		||||
############################################
 | 
			
		||||
####### END OF FUNCTION DEFINITIONS ########
 | 
			
		||||
############################################
 | 
			
		||||
 | 
			
		||||
############################################
 | 
			
		||||
######### START OF INITIALISATION ##########
 | 
			
		||||
############################################
 | 
			
		||||
 | 
			
		||||
# signal handing setup for controlled exit via ctrl+c
 | 
			
		||||
signal.signal(signal.SIGINT, signal_handler)
 | 
			
		||||
 | 
			
		||||
# hide mouse from screen
 | 
			
		||||
pygame.mouse.set_visible(False)
 | 
			
		||||
 | 
			
		||||
# start fullscreen mode with defined screen geometrics
 | 
			
		||||
screen = pygame.display.set_mode((screen_size_x, screen_size_y), pygame.FULLSCREEN)
 | 
			
		||||
#pygame.display.set_caption('Heisser Draht') # not required for fullscreen application
 | 
			
		||||
 | 
			
		||||
# currently unused because its not needed
 | 
			
		||||
#screen = toggle_fullscreen()
 | 
			
		||||
 | 
			
		||||
# define image variables
 | 
			
		||||
img_itlablogo = 'img/itlablogo.png'
 | 
			
		||||
img_itlablogo_image = pygame.image.load(img_itlablogo)
 | 
			
		||||
img_itlablogo_imagex = get_image_width(img_itlablogo)
 | 
			
		||||
img_itlablogo_imagey = get_image_height(img_itlablogo)
 | 
			
		||||
 | 
			
		||||
# TODO: Metallic Logo einfügen
 | 
			
		||||
#img_metalliclogo = 'img/metalliclogo.png'
 | 
			
		||||
#img_metalliclogo_image  = pygame.image.load(img_metalliclogo)
 | 
			
		||||
#img_metalliclogo_imagex = get_image_width(img_metalliclogo)
 | 
			
		||||
#img_metalliclogo_imagey = get_image_height(img_metalliclogo)
 | 
			
		||||
 | 
			
		||||
# initialise led strip
 | 
			
		||||
led_init()
 | 
			
		||||
 | 
			
		||||
# set the start state
 | 
			
		||||
game_running = False
 | 
			
		||||
game_ending = False
 | 
			
		||||
 | 
			
		||||
# enable the one-shot for changing the LEDs
 | 
			
		||||
game_just_started = True
 | 
			
		||||
 | 
			
		||||
# set start inhibitor to false by default
 | 
			
		||||
pin_start_inhibit = False
 | 
			
		||||
 | 
			
		||||
############################################
 | 
			
		||||
########## END OF INITIALISATION ###########
 | 
			
		||||
############################################
 | 
			
		||||
 | 
			
		||||
############################################
 | 
			
		||||
######### START OF MAIN GAME LOOP ##########
 | 
			
		||||
############################################
 | 
			
		||||
 | 
			
		||||
while True:
 | 
			
		||||
    # default actions to be done every cycle
 | 
			
		||||
    clear_screen()
 | 
			
		||||
    handle_events()
 | 
			
		||||
    show_debug()
 | 
			
		||||
    print(str(pygame.time.get_ticks()))
 | 
			
		||||
 | 
			
		||||
    # State 0
 | 
			
		||||
 | 
			
		||||
    if not game_running and not game_ending:
 | 
			
		||||
        # one shot for changing the led colour
 | 
			
		||||
        if game_just_started:
 | 
			
		||||
            print('game just started, changed colour of leds to green')
 | 
			
		||||
            change_led_colour(0, 200, 0)
 | 
			
		||||
            game_just_started = False
 | 
			
		||||
 | 
			
		||||
        # reset all the surfaces to be empty
 | 
			
		||||
        time_surface = 0
 | 
			
		||||
        errors_surface = 0
 | 
			
		||||
        time_rectangle = 0
 | 
			
		||||
        errors_rectangle = 0
 | 
			
		||||
 | 
			
		||||
        # fill all surfaces again to contain the proper text
 | 
			
		||||
        header_surface = pygame_font_1.render('Dr' + u'ü' + 'cken Sie Start!', True, pygame_font_main_color)
 | 
			
		||||
        header_rectangle = header_surface.get_rect()
 | 
			
		||||
        header_rectangle.topleft = (560, 250)
 | 
			
		||||
 | 
			
		||||
        highscore_header_surface = pygame_font_2.render('Highscores:', True, pygame_font_main_color)
 | 
			
		||||
        highscore_header_rectangle = highscore_header_surface.get_rect()
 | 
			
		||||
        highscore_header_rectangle = (770, 410)
 | 
			
		||||
 | 
			
		||||
        score1_surface = pygame_font_3.render(hs1_name + ": " + str(hs1_time/1000) + 's', True, pygame_color_yellow)
 | 
			
		||||
        score1_rectangle = score1_surface.get_rect()
 | 
			
		||||
        score1_rectangle.topleft = (820, 540)
 | 
			
		||||
 | 
			
		||||
        score2_surface = pygame_font_3.render(hs2_name + ": " + str(hs2_time/1000) + 's', True, pygame_color_grey)
 | 
			
		||||
        score2_rectangle = score2_surface.get_rect()
 | 
			
		||||
        score2_rectangle.topleft = (820, 630)
 | 
			
		||||
 | 
			
		||||
        score3_surface = pygame_font_3.render(hs3_name + ": " + str(hs3_time/1000) + 's', True, pygame_color_brown)
 | 
			
		||||
        score3_rectangle = score3_surface.get_rect()
 | 
			
		||||
        score3_rectangle.topleft = (820, 720)
 | 
			
		||||
 | 
			
		||||
        # draw headline, highscore headline, the 3 scores, as well as the logos to the screen
 | 
			
		||||
        screen.blit(header_surface, header_rectangle)
 | 
			
		||||
        screen.blit(highscore_header_surface, highscore_header_rectangle)
 | 
			
		||||
        screen.blit(score1_surface, score1_rectangle)
 | 
			
		||||
        screen.blit(score2_surface, score2_rectangle)
 | 
			
		||||
        screen.blit(score3_surface, score3_rectangle)
 | 
			
		||||
 | 
			
		||||
        # event handling for if the start button is pushed
 | 
			
		||||
        #wait for the user to press start button
 | 
			
		||||
        if GPIO.input(pin_start) and not pin_start_inhibit:
 | 
			
		||||
            # change game state to running and not ending
 | 
			
		||||
            game_running = True
 | 
			
		||||
            game_ending = False
 | 
			
		||||
 | 
			
		||||
            # set an inhibitor bit to stop the contact from possibly vibrating and
 | 
			
		||||
            # causing a stop of the game immediately after start
 | 
			
		||||
            pin_start_inhibit = True
 | 
			
		||||
            timer_pin_start_inhibit_starttime = pygame.time.get_ticks()
 | 
			
		||||
 | 
			
		||||
            # reset errors
 | 
			
		||||
            errors = 0
 | 
			
		||||
            error_added = False
 | 
			
		||||
            error_cooldown_start = 0
 | 
			
		||||
 | 
			
		||||
            # change the headline
 | 
			
		||||
            header_surface = pygame_font_1.render('Spiel l' + u'ä' + 'uft!', True, pygame_font_main_color)
 | 
			
		||||
 | 
			
		||||
            # start the timer
 | 
			
		||||
            timer_game_running_start = pygame.time.get_ticks()
 | 
			
		||||
 | 
			
		||||
            # change led colour to blue
 | 
			
		||||
            change_led_colour(0, 0, 200)
 | 
			
		||||
 | 
			
		||||
    # State 1
 | 
			
		||||
 | 
			
		||||
    if game_running and not game_ending:
 | 
			
		||||
 | 
			
		||||
        # reset the highscore check
 | 
			
		||||
        highscore_checked = False
 | 
			
		||||
 | 
			
		||||
        # if the start pin is inhibited and at least 3 seconds have passed,
 | 
			
		||||
        # one shot: stop blocking the pin
 | 
			
		||||
        if pin_start_inhibit:
 | 
			
		||||
            if (pygame.time.get_ticks()-timer_pin_start_inhibit_starttime) > 3000:
 | 
			
		||||
                pin_start_inhibit = False
 | 
			
		||||
 | 
			
		||||
        # add errors if error pin is detected, only once per 500 ms
 | 
			
		||||
        if GPIO.input(pin_error):
 | 
			
		||||
            if not error_added:
 | 
			
		||||
                errors += 1
 | 
			
		||||
                error_added = True
 | 
			
		||||
                error_cooldown_start = pygame.time.get_ticks()
 | 
			
		||||
                change_led_colour(200, 0, 0)
 | 
			
		||||
 | 
			
		||||
        # if an error happened, error_added is set to true - which prohibits adding another error.
 | 
			
		||||
        # after 500 ms error_added is set to false again.
 | 
			
		||||
        # this provides a cooldown
 | 
			
		||||
        if error_added and (pygame.time.get_ticks()-error_cooldown_start) > 500:
 | 
			
		||||
            error_added = False
 | 
			
		||||
            change_led_colour(0, 0, 200)
 | 
			
		||||
 | 
			
		||||
        # calculate the current time
 | 
			
		||||
        timer_game_running = (pygame.time.get_ticks() - timer_game_running_start) + (errors * time_per_error)
 | 
			
		||||
 | 
			
		||||
        # fill the surface with the current time and errors
 | 
			
		||||
        time_surface = pygame_font_2.render('Zeit: ' + str(timer_game_running/1000) + 's', True, pygame_font_main_color)
 | 
			
		||||
        time_rectangle = time_surface.get_rect()
 | 
			
		||||
        time_rectangle.topleft = (640, 480)
 | 
			
		||||
 | 
			
		||||
        errors_surface = pygame_font_2.render('Fehler: ' + str(errors), True, pygame_font_main_color)
 | 
			
		||||
        errors_rectangle = errors_surface.get_rect()
 | 
			
		||||
        errors_rectangle.topleft = (640, 560)
 | 
			
		||||
 | 
			
		||||
        clear_screen()
 | 
			
		||||
 | 
			
		||||
        # draw errors, time and headline to the screen
 | 
			
		||||
        screen.blit(errors_surface, errors_rectangle) #errors
 | 
			
		||||
        screen.blit(time_surface, time_rectangle) #time
 | 
			
		||||
        screen.blit(header_surface, header_rectangle) #header
 | 
			
		||||
 | 
			
		||||
        # display everything
 | 
			
		||||
        #pygame.display.flip()
 | 
			
		||||
 | 
			
		||||
        # if another push of start is detected (i.e. the game is ending!)
 | 
			
		||||
        if GPIO.input(pin_stop):
 | 
			
		||||
            # change led colour to red
 | 
			
		||||
            change_led_colour(200, 0, 200)
 | 
			
		||||
 | 
			
		||||
            # reset the one shot latch for the end of game timer
 | 
			
		||||
            timer_game_ending_started = False
 | 
			
		||||
 | 
			
		||||
            # change the state to not running and ending
 | 
			
		||||
            game_running = False
 | 
			
		||||
            game_ending = True
 | 
			
		||||
 | 
			
		||||
    # State 2
 | 
			
		||||
 | 
			
		||||
    if not game_running and game_ending:
 | 
			
		||||
        # check highscores only once when game ended
 | 
			
		||||
        if not highscore_checked:
 | 
			
		||||
            check_highscores(timer_game_running)
 | 
			
		||||
            highscore_checked = True
 | 
			
		||||
 | 
			
		||||
        # timer for ending the game after 5 seconds
 | 
			
		||||
        if not timer_game_ending_started:
 | 
			
		||||
            timer_game_ending_timout = pygame.time.get_ticks()
 | 
			
		||||
            timer_game_ending_started = True
 | 
			
		||||
 | 
			
		||||
        clear_screen()
 | 
			
		||||
 | 
			
		||||
        # change the headline to game over
 | 
			
		||||
        header_surface = pygame_font_1.render('Game over!', True, pygame_font_main_color)
 | 
			
		||||
 | 
			
		||||
        # draw errors, time, and new headline to the screen
 | 
			
		||||
        screen.blit(errors_surface, errors_rectangle) #errors
 | 
			
		||||
        screen.blit(time_surface, time_rectangle) #time
 | 
			
		||||
        screen.blit(header_surface, header_rectangle) #header
 | 
			
		||||
 | 
			
		||||
        # if 5 seconds have passed since the game state changed to ending (see: timer_game_ending_timeout)
 | 
			
		||||
        if ((pygame.time.get_ticks()-timer_game_ending_timout)/1000) > 5:
 | 
			
		||||
            # reset game_just_started flag to enable the one shot led change in the first state
 | 
			
		||||
            game_just_started = True
 | 
			
		||||
 | 
			
		||||
            # change state
 | 
			
		||||
            game_running = False
 | 
			
		||||
            game_ending = False
 | 
			
		||||
 | 
			
		||||
            # reset highscore one shot
 | 
			
		||||
            highscore_checked = False
 | 
			
		||||
 | 
			
		||||
            # reset timer started one shot
 | 
			
		||||
            timer_game_ending_started = False
 | 
			
		||||
 | 
			
		||||
            # unblock the start pin unconditionally
 | 
			
		||||
            pin_start_inhibit = False
 | 
			
		||||
 | 
			
		||||
    # State 3
 | 
			
		||||
 | 
			
		||||
    if game_running and game_ending:
 | 
			
		||||
        # something went horribly wrong...
 | 
			
		||||
        # this state is never supposed to be reached
 | 
			
		||||
        pass
 | 
			
		||||
 | 
			
		||||
    # overlaying structure - this is to be drawn no matter what's below
 | 
			
		||||
    draw_border()
 | 
			
		||||
    draw_logos()
 | 
			
		||||
 | 
			
		||||
    # flip everything, update display, do a tick
 | 
			
		||||
    pygame.display.flip()
 | 
			
		||||
    pygame.display.update()
 | 
			
		||||
    pygame_clock.tick(pygame_fps)
 | 
			
		||||
 | 
			
		||||
############################################
 | 
			
		||||
########## END OF MAIN GAME LOOP ###########
 | 
			
		||||
############################################
 | 
			
		||||
		Reference in New Issue
	
	Block a user