A simple Multiple choice quiz with Pygame

This was some code I made some times ago, also on repl.it. I made some changes and I want to make it more usable and clear, cause it’s really messy. Here is my progress until now

import pygame
import pygame.gfxdraw
import sys
import time
import random



pygame.init()
screen = pygame.display.set_mode((600, 600))

clock = pygame.time.Clock()
buttons = pygame.sprite.Group()
num = 1
class Button(pygame.sprite.Sprite):
    
    def __init__(self, position, text, size,
        colors="white on blue",
        hover_colors="red on green",
        style=1,
        borderc=(255,255,255),
        command=lambda: print("No command activated for this button")):

        # the hover_colors attribute needs to be fixed
        super().__init__()
        global num


        self.text = text

        self.command = command
        # --- colors ---
        self.colors = colors
        self.original_colors = colors
        self.fg, self.bg = self.colors.split(" on ")

        if hover_colors == "red on green":
            self.hover_colors = f"{self.bg} on {self.fg}"
        else:
            self.hover_colors = hover_colors

        self.style = style
        self.borderc = borderc # for the style2
        # font
        self.font = pygame.font.SysFont("Arial", size)
        self.render(self.text)
        self.x, self.y, self.w , self.h = self.text_render.get_rect()
        self.x, self.y = position
        self.rect = pygame.Rect(self.x, self.y, 500, self.h)
        self.position = position
        self.pressed = 1
        # the groups with all the buttons
        buttons.add(self)

    def render(self, text):
        # we have a surface
        self.text_render = self.font.render(text, 1, self.fg)
        # memorize the surface in the image attributes
        self.image = self.text_render

    def update(self):
        self.fg, self.bg = self.colors.split(" on ")
        if self.style == 1:
            self.draw_button1()
        elif self.style == 2:
            self.draw_button2()
        if self.command != None:
            self.hover()
            self.click()

    def draw_button1(self):
        ''' draws 4 lines around the button and the background '''
        # horizontal up
        pygame.draw.line(screen, (150, 150, 150), (self.x, self.y), (self.x + self.w , self.y), 5)
        pygame.draw.line(screen, (150, 150, 150), (self.x, self.y - 2), (self.x, self.y + self.h), 5)
        # horizontal down
        pygame.draw.line(screen, (50, 50, 50), (self.x, self.y + self.h), (self.x + self.w , self.y + self.h), 5)
        pygame.draw.line(screen, (50, 50, 50), (self.x + self.w , self.y + self.h), [self.x + self.w , self.y], 5)
        # background of the button
        pygame.draw.rect(screen, self.bg, (self.x, self.y, self.w , self.h))  

    def draw_button2(self):
        ''' a linear border '''
        pygame.draw.rect(screen, self.bg, (self.x - 50, self.y, 500 , self.h))
        pygame.gfxdraw.rectangle(screen, (self.x - 50, self.y, 500 , self.h), self.borderc)

    def check_collision(self):
        if self.rect.collidepoint(pygame.mouse.get_pos()):
            # you can change the colors when the pointer is on the button if you want
            self.colors = self.hover_colors
            # pygame.mouse.set_cursor(*pygame.cursors.diamond)
        else:
            self.colors = self.original_colors
            # pygame.mouse.set_cursor(*pygame.cursors.arrow)


    def hover(self):
        ''' checks if the mouse is over the button and changes the color if it is true '''
        if self.style == 1:
            self.check_collision()
            self.render()
        else:
            self.check_collision()

    def click(self):
        ''' checks if you click on the button and makes the call to the action just one time'''
        if self.rect.collidepoint(pygame.mouse.get_pos()):
            if pygame.mouse.get_pressed()[0] and self.pressed == 1:
                print("The answer is:'" + self.text + "'")
                self.command()
                self.pressed = 0
            if pygame.mouse.get_pressed() == (0,0,0):
                self.pressed = 1




# FUNCTIONS for the buttons on click
# I used this convention ... on_+text of the button

def on_click():
    print("Click on one answer")

def on_run():
    print("Ciao bello questo è RUN")

def on_save():
    print("This is Save")

def on_right():
    global fb

    print("Right")
    forward()
    fb.render("Ok")

def on_false():
    print("Wrong")
    forward()
    fb.render("No, last answer was wrong")

def forward():
    global qnum
    
    screen.fill(0)
    if qnum < len(questions):
        time.sleep(.3)
        qnum += 1
        display_quiz(qnum)



questions = [
    ["What is Italy's Capital?", ["Rome", "Paris", "Tokyo", "Madrid"]],
    ["What is France's Capital?", ["Paris", "Rome", "Tokyo", "Madrid"]],
    ["What is England's Capital?", ["London", "Rome", "Tokyo", "Madrid"]],
]




def create_button(pos, number, color,command=None):
    Button((pos), f"{number}. ", 36, "red on yellow",
            hover_colors="blue on orange", style=2, borderc=color,
            command=None)
    Button((50, pos[1]), questions[qnum-1][1][number-1], 36, "red on yellow",
        hover_colors="blue on orange", style=2, borderc=(255,255,0),
        command=command)


def display_quiz(qnum):
    ''' put your buttons here '''
    global fb

    for sprites in buttons:
        sprites.kill()

    #                 Q U E S T I O N
    Button((10, 10), questions[qnum-1][0], 55, "white on black",
        hover_colors="blue on orange", style=2, borderc=(0,0,0),
        command=None)

    # ______ 4 MULTIPLE ANSWERS______ #

    pos = [100, 150, 200, 250]
    random.shuffle(pos)
    create_button((10,pos[0]), 1, (0,0,0), on_right)
    create_button((10,pos[1]), 2, (0,0,0), on_false)
    create_button((10,pos[2]), 3, (0,0,0), on_false)
    create_button((10,pos[3]), 4, (0,0,0), on_false)

    # feedback

    fb = Button((10, 300), "Feedback", 55, "white on black",
        hover_colors="blue on orange", style=2, borderc=(0,0,0),
        command=None)


qnum = 1
if __name__ == '__main__':
    pygame.init()
    game_on = 0
    def loop():
        # BUTTONS ISTANCES
        global qnum


        game_on = 1
        display_quiz(qnum)
        while True:
            screen.fill(0)
            for event in pygame.event.get():
                if (event.type == pygame.QUIT):
                    game_on = 0
                    pygame.quit()
                    if event.key == pygame.K_ESCAPE:
                        pygame.quit()
                        game_on = 0
            if game_on:
                buttons.update()
                buttons.draw(screen)
            else:
                pygame.quit()
                sys.exit()
            buttons.draw(screen)
            clock.tick(60)
            pygame.display.update()
        pygame.quit()




    loop()
  

This code on repl.it

https://replit.com/@EducationalChan/pyquiz?from=notifications


Subscribe to the newsletter for updates
Tkinter templates
Avatar My youtube channel

Twitter: @pythonprogrammi - python_pygame

Videos

Speech recognition game

Pygame's Platform Game

Other Pygame's posts

Published by pythonprogramming

Started with basic on the spectrum, loved javascript in the 90ies and python in the 2000, now I am back with python, still making some javascript stuff when needed.