To the game scene class, you could add something like choices.
self.choices = ['x', '-', '*', '+']
I have never used pygame.freetype
before but seems like the rendering text is done using
SimpleScene.FONT.render_to
So you can iterate over the choices and draw them
SimpleScene.FONT.render_to(screen, (rect.x+29, rect.y+29), str(self.choices[n]),
pygame.Color('white'))
To have different options for different questions, you can expand the self.choices
list to be a 2D list. Then iterate through that list and render them depending on what the current question is. Also looks like sloths original code does not adjust the size so rendering words would not work. So I have slightly modified the way boxes are rendered to fit words. Also I have added a comment called #CHANGE
to show the changes that were made to the previous one.
import pygame
import pygame.freetype
import random
class SimpleScene:
FONT = None
def __init__(self, next_scene, *text):
self.background = pygame.Surface((640, 480))
self.background.fill(pygame.Color('lightgrey'))
y = 80
if text:
if SimpleScene.FONT == None:
SimpleScene.FONT = pygame.freetype.SysFont(None, 32)
for line in text:
SimpleScene.FONT.render_to(self.background, (120, y), line, pygame.Color('black'))
SimpleScene.FONT.render_to(self.background, (119, y-1), line, pygame.Color('white'))
y += 50
self.next_scene = next_scene
self.additional_text = None
def start(self, text):
self.additional_text = text
def draw(self, screen):
screen.blit(self.background, (0, 0))
if self.additional_text:
y = 180
for line in self.additional_text:
SimpleScene.FONT.render_to(screen, (120, y), line, pygame.Color('black'))
SimpleScene.FONT.render_to(screen, (119, y-1), line, pygame.Color('white'))
y += 50
def update(self, events, dt):
for event in events:
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
return (self.next_scene, None)
class GameState:
def __init__(self, difficulty):
self.difficulty = difficulty
#CHANGE
self.questions = [
(" 4 _ 6 = 10 ?", 4),
("Which one is a fruit?", 2)
]
self.current_question = None
#CHANGE
self.question_index = 0
self.right = 0
self.wrong = 0
def pop_question(self):
q = random.choice(self.questions)
self.questions.remove(q)
self.current_question = q
#CHANGE
self.question_index += 1
return q
def answer(self, answer):
if answer == self.current_question[1]:
self.right += 1
else:
self.wrong += 1
def get_result(self):
return f'{self.right} answers correct', f'{self.wrong} answers wrong', '', 'Good!' if self.right > self.wrong else 'You can do better!'
class SettingScene:
def __init__(self):
self.background = pygame.Surface((640, 480))
self.background.fill(pygame.Color('lightgrey'))
if SimpleScene.FONT == None:
SimpleScene.FONT = pygame.freetype.SysFont(None, 32)
SimpleScene.FONT.render_to(self.background, (120, 50), 'Select your difficulty level', pygame.Color('black'))
SimpleScene.FONT.render_to(self.background, (119, 49), 'Select your difficulty level', pygame.Color('white'))
self.rects = []
#CHANGE
for n in range(4):
rect = pygame.Rect(50, (n * 70) + 100, 500, 50)
self.rects.append(rect)
def start(self, *args):
pass
def draw(self, screen):
screen.blit(self.background, (0, 0))
n = 1
for rect in self.rects:
if rect.collidepoint(pygame.mouse.get_pos()):
pygame.draw.rect(screen, pygame.Color('darkgrey'), rect)
pygame.draw.rect(screen, pygame.Color('darkgrey'), rect, 5)
#CHANGE
SimpleScene.FONT.render_to(screen, (rect.x+30, rect.y+15), str(n), pygame.Color('black'))
SimpleScene.FONT.render_to(screen, (rect.x+29, rect.y+14), str(n), pygame.Color('white'))
n+=1
def update(self, events, dt):
for event in events:
if event.type == pygame.MOUSEBUTTONDOWN:
n = 1
for rect in self.rects:
if rect.collidepoint(event.pos):
return ('GAME', GameState(n))
n += 1
class GameScene:
def __init__(self):
if SimpleScene.FONT == None:
SimpleScene.FONT = pygame.freetype.SysFont(None, 32)
self.rects = []
for n in range(4):
rect = pygame.Rect(50, (n * 70) + 100, 500, 50)
self.rects.append(rect)
#CHANGE
self.choices = [['x', '-', '*', '+'], ["whatever", "apple", "whatever", "whatever"]]
def start(self, gamestate):
self.background = pygame.Surface((640, 480))
self.background.fill(pygame.Color('lightgrey'))
self.gamestate = gamestate
question, answer = gamestate.pop_question()
SimpleScene.FONT.render_to(self.background, (120, 50), question, pygame.Color('black'))
SimpleScene.FONT.render_to(self.background, (119, 49), question, pygame.Color('white'))
def draw(self, screen):
screen.blit(self.background, (0, 0))
n = 0
for rect in self.rects:
if rect.collidepoint(pygame.mouse.get_pos()):
pygame.draw.rect(screen, pygame.Color('darkgrey'), rect)
pygame.draw.rect(screen, pygame.Color('darkgrey'),
rect, 5)
#CHANGE
for i in range(len(self.choices)):
if self.gamestate.question_index == i + 1:
SimpleScene.FONT.render_to(screen, (rect.x+30, rect.y+20), str(self.choices[i][n]), pygame.Color('black'))
SimpleScene.FONT.render_to(screen, (rect.x+29, rect.y+19), str(self.choices[i][n]), pygame.Color('white'))
n+=1
def update(self, events, dt):
for event in events:
if event.type == pygame.MOUSEBUTTONDOWN:
n = 1
for rect in self.rects:
if rect.collidepoint(event.pos):
self.gamestate.answer(n)
if self.gamestate.questions:
return ('GAME', self.gamestate)
else:
return ('RESULT', self.gamestate.get_result())
n += 1
def main():
pygame.init()
screen = pygame.display.set_mode((640, 480))
clock = pygame.time.Clock()
dt = 0
scenes = {
'TITLE': SimpleScene('SETTING', 'Welcome to the quiz', '', '', '', 'press [SPACE] to start'),
'SETTING': SettingScene(),
'GAME': GameScene(),
'RESULT': SimpleScene('TITLE', 'Here is your result:'),
}
scene = scenes['TITLE']
while True:
events = pygame.event.get()
for e in events:
if e.type == pygame.QUIT:
return
result = scene.update(events, dt)
if result:
next_scene, state = result
if next_scene:
scene = scenes[next_scene]
scene.start(state)
scene.draw(screen)
pygame.display.flip()
dt = clock.tick(60)
if __name__ == '__main__':
main()
Bug was that the questions were being picked at random so the indices didn't align. Since the original code was not designed to have different choices, the class handling answer does not have access to the random variable controlling which question gets picked. So there isn't really any way to have random questions without sacrificing encaptulation. So I suggest just remove the randomness and pop the question directly i.e
Replace
q = random.choice(self.questions)
with
q = self.questions[0]
Its in GameState
class in pop_questions
method.