I am trying to make it so when you get an answer correct in my trivia game, it will get rid of the big question you see and say "well done" for 5 seconds and then go back to the main menu where there are 4 randomly selected questions. The questions are loaded in from a quizfile.csv and contains:
What colour is elon musk's hair?,brown
What is most popular sport?,football
What was Queen first called?,Smile
What's superior Apple Or Windows?,Windows
They are random as they are just placeholder and for testing purposes only. The place where I want the pause/display for 5 seconds function is on line 115 of the first file.
I have tried time.sleep(5)
and this just freezes the program and doesn't display it for 5 seconds, much like for less than a second. Would I need to use pygame.event.set_timer()
and if so, how?
import csv
import sys
import random
import pygame
import textwrap
import time
import pygame_textinput
textinput = pygame_textinput.TextInput()
pygame.init()
clock = pygame.time.Clock()
FPS=60
SCREENSIZE = SCREENWIDTH, SCREENHEIGHT = 1080, 720
screen = pygame.display.set_mode(SCREENSIZE)
white = (255, 255, 255)
black = (0, 0, 0)
red = (255, 0, 0)
yellow = (255, 255, 0)
green = (0, 255, 0)
questions = {}
def wrap_text(message, wraplimit): #keep text on screen
return textwrap.fill(message, wraplimit)
def text_objects(text,font): #render text
textSurf = font.render(text, True, black)
return textSurf, textSurf.get_rect()
def question(text):
xx=0
text = wrap_text(text,20) #wrap text
largeText = pygame.font.Font('freesansbold.ttf',100)
for part in text.split('\n'): #for each line from the wrapped text
TextSurf, TextRect = text_objects(part, largeText)
TextRect.center = ((SCREENWIDTH/2)),(SCREENHEIGHT/2+xx)
screen.blit(TextSurf, TextRect)
xx+=75 #change height of text so doesnt overlap
class Button:
def __init__(self, question, answer,positionx,positiony): #setup all vars
self.question = question
self.answer = answer
self.positionx = positionx
self.positiony = positiony
def button(self):
ltr = len(self.question)
w= 12.5*ltr #make width of button big enough for text
button = pygame.Rect(self.positionx,self.positiony,w,50) #make button
largeText = pygame.font.Font('freesansbold.ttf',20)
TextSurf, TextRect = text_objects(self.question, largeText)
TextRect.center = ((self.positionx+(w/2)),(self.positiony+25)) #button text
return button, TextSurf, TextRect
def question(self):
question(self.question) #display question
def giveQuestionAnswer(self):
return self.question,self.answer #give question and answer
with open("quizfile.csv") as f: #load in questions
reader = csv.reader(f)
quiz_qas = list(reader)
z=0 #for positioning
t=0 #for loop
quiz = random.sample(quiz_qas, 4) #randomly select 4 questions
for q, a in quiz: #for every question and answer in the file
questions[q] = a #define the dictionary of questions and answers
for x, y in questions.items(): #for every answer and question in the dictionary, link them
if t==0: #the sweet spots for getting a different question every time
b = Button(x,y,200,200) #make button object
z+=50
elif t==5:
b1 = Button(x,y,600,200)
z+=50
elif t==7:
b2 = Button(x,y,600,400)
z+=50
elif t==9:
b3 = Button(x,y,200,400)
z+=50
t+=1
b2on = False #for handling displaying the question
b3on = False
b4on = False
b5on = False
correct=False
gameState = "running" # controls which state the games is in
# game loop #################### runs 60 times a second!
while gameState != "exit": # game loop - note: everything in the mainloop is indented one tab
screen.fill(white)
events = pygame.event.get()
if b2on:
q,a = b.giveQuestionAnswer() #get question and answer
question(q) #display answer
# Feed it with events every frame
# Blit its surface onto the screen
screen.blit(textinput.get_surface(), (10, 10))
if textinput.update(events): #if hit enter
if textinput.get_text() == a:
b2on = False
correct=True
if correct:
question("well done")
#PAUSE SCREEN HERE AND DISPLAY WELL DONE FOR 5 SECONDS
correct=False
elif b3on:
q,a = b1.giveQuestionAnswer()
question(q)
textinput.update(events)
screen.blit(textinput.get_surface(), (10, 10))
if textinput.update(events): #if hit enter
if textinput.get_text() == a:
b3on = False
correct=True
elif b4on:
q,a = b2.giveQuestionAnswer()
question(q)
textinput.update(events)
screen.blit(textinput.get_surface(), (10, 10))
if textinput.update(events): #if hit enter
if textinput.get_text() == a:
b4on = False
correct=True
elif b5on:
q,a = b3.giveQuestionAnswer()
question(q)
textinput.update(events)
screen.blit(textinput.get_surface(), (10, 10))
if textinput.update(events): #if hit enter
if textinput.get_text() == a:
b5on = False
correct=True
elif b2on==False and b3on==False and b4on==False and b5on==False:
B2,TextSurf,TextRect = b.button() #draw buttons
pygame.draw.rect(screen, [255, 0, 0], B2)
screen.blit(TextSurf, TextRect)
B3,TextSurf,TextRect = b1.button()
pygame.draw.rect(screen, [255, 0, 0], B3)
screen.blit(TextSurf, TextRect)
B4,TextSurf,TextRect = b2.button()
pygame.draw.rect(screen, [255, 0, 0], B4)
screen.blit(TextSurf, TextRect)
B5,TextSurf,TextRect = b3.button()
pygame.draw.rect(screen, [255, 0, 0], B5)
screen.blit(TextSurf, TextRect)
for event in pygame.event.get(): # get user interaction events
if event.type == pygame.QUIT: # tests if window's X (close) has been clicked
gameState = "exit" # causes exit of game loop
if event.type == pygame.MOUSEBUTTONDOWN:
mouse_pos = event.pos # gets mouse position
if B2.collidepoint(mouse_pos): #if click on button
b2on = True #display question
if B3.collidepoint(mouse_pos):
b3on = True
if B4.collidepoint(mouse_pos):
b4on = True
if B5.collidepoint(mouse_pos):
b5on = True
pygame.display.update()
pygame.display.flip() # transfers build screen to human visable screen
clock.tick(FPS) # limits game to frame per second, FPS value
# out of game loop ###############
print("The game has closed")
pygame.quit()
sys.exit()
and here is the pygame_textinput.py file I am using to create that blinking input effect and function.
"""
Copyright 2017, Silas Gyger, silasgyger@gmail.com, All rights reserved.
Borrowed from https://github.com/Nearoo/pygame-text-input under the MIT license.
"""
import os.path
import pygame
import pygame.locals as pl
pygame.font.init()
class TextInput:
"""
This class lets the user input a piece of text, e.g. a name or a message.
This class let's the user input a short, one-lines piece of text at a blinking cursor
that can be moved using the arrow-keys. Delete, home and end work as well.
"""
def __init__(
self,
initial_string="",
font_family="",
font_size=35,
antialias=True,
text_color=(0, 0, 0),
cursor_color=(0, 0, 1),
repeat_keys_initial_ms=400,
repeat_keys_interval_ms=35):
"""
:param initial_string: Initial text to be displayed
:param font_family: name or list of names for font (see pygame.font.match_font for precise format)
:param font_size: Size of font in pixels
:param antialias: Determines if antialias is applied to font (uses more processing power)
:param text_color: Color of text (duh)
:param cursor_color: Color of cursor
:param repeat_keys_initial_ms: Time in ms before keys are repeated when held
:param repeat_keys_interval_ms: Interval between key press repetition when helpd
"""
# Text related vars:
self.antialias = antialias
self.text_color = text_color
self.font_size = font_size
self.input_string = initial_string # Inputted text
if not os.path.isfile(font_family):
font_family = pygame.font.match_font(font_family)
self.font_object = pygame.font.Font(font_family, font_size)
# Text-surface will be created during the first update call:
self.surface = pygame.Surface((1, 1))
self.surface.set_alpha(0)
# Vars to make keydowns repeat after user pressed a key for some time:
self.keyrepeat_counters = {} # {event.key: (counter_int, event.unicode)} (look for "***")
self.keyrepeat_intial_interval_ms = repeat_keys_initial_ms
self.keyrepeat_interval_ms = repeat_keys_interval_ms
# Things cursor:
self.cursor_surface = pygame.Surface((int(self.font_size/20+1), self.font_size))
self.cursor_surface.fill(cursor_color)
self.cursor_position = len(initial_string) # Inside text
self.cursor_visible = True # Switches every self.cursor_switch_ms ms
self.cursor_switch_ms = 500 # /|\
self.cursor_ms_counter = 0
self.clock = pygame.time.Clock()
def update(self, events):
for event in events:
if event.type == pygame.KEYDOWN:
self.cursor_visible = True # So the user sees where he writes
# If none exist, create counter for that key:
if event.key not in self.keyrepeat_counters:
self.keyrepeat_counters[event.key] = [0, event.unicode]
if event.key == pl.K_BACKSPACE:
self.input_string = (
self.input_string[:max(self.cursor_position - 1, 0)]
+ self.input_string[self.cursor_position:]
)
# Subtract one from cursor_pos, but do not go below zero:
self.cursor_position = max(self.cursor_position - 1, 0)
elif event.key == pl.K_DELETE:
self.input_string = (
self.input_string[:self.cursor_position]
+ self.input_string[self.cursor_position + 1:]
)
elif event.key == pl.K_RETURN:
return True
elif event.key == pl.K_RIGHT:
# Add one to cursor_pos, but do not exceed len(input_string)
self.cursor_position = min(self.cursor_position + 1, len(self.input_string))
elif event.key == pl.K_LEFT:
# Subtract one from cursor_pos, but do not go below zero:
self.cursor_position = max(self.cursor_position - 1, 0)
elif event.key == pl.K_END:
self.cursor_position = len(self.input_string)
elif event.key == pl.K_HOME:
self.cursor_position = 0
else:
# If no special key is pressed, add unicode of key to input_string
self.input_string = (
self.input_string[:self.cursor_position]
+ event.unicode
+ self.input_string[self.cursor_position:]
)
self.cursor_position += len(event.unicode) # Some are empty, e.g. K_UP
elif event.type == pl.KEYUP:
# *** Because KEYUP doesn't include event.unicode, this dict is stored in such a weird way
if event.key in self.keyrepeat_counters:
del self.keyrepeat_counters[event.key]
# Update key counters:
for key in self.keyrepeat_counters:
self.keyrepeat_counters[key][0] += self.clock.get_time() # Update clock
# Generate new key events if enough time has passed:
if self.keyrepeat_counters[key][0] >= self.keyrepeat_intial_interval_ms:
self.keyrepeat_counters[key][0] = (
self.keyrepeat_intial_interval_ms
- self.keyrepeat_interval_ms
)
event_key, event_unicode = key, self.keyrepeat_counters[key][1]
pygame.event.post(pygame.event.Event(pl.KEYDOWN, key=event_key, unicode=event_unicode))
# Re-render text surface:
self.surface = self.font_object.render(self.input_string, self.antialias, self.text_color)
# Update self.cursor_visible
self.cursor_ms_counter += self.clock.get_time()
if self.cursor_ms_counter >= self.cursor_switch_ms:
self.cursor_ms_counter %= self.cursor_switch_ms
self.cursor_visible = not self.cursor_visible
if self.cursor_visible:
cursor_y_pos = self.font_object.size(self.input_string[:self.cursor_position])[0]
# Without this, the cursor is invisible when self.cursor_position > 0:
if self.cursor_position > 0:
cursor_y_pos -= self.cursor_surface.get_width()
self.surface.blit(self.cursor_surface, (cursor_y_pos, 0))
self.clock.tick()
return False
def get_surface(self):
return self.surface
def get_text(self):
return self.input_string
def get_cursor_position(self):
return self.cursor_position
def set_text_color(self, color):
self.text_color = color
def set_cursor_color(self, color):
self.cursor_surface.fill(color)
def clear_text(self):
self.input_string = ""
self.cursor_position = 0
Any help appreciated!
You've to use a timer event. See pygame.event
.
Create a user event and a paused
state.
pausetimerevent = pygame.USEREVENT + 1
paused = False
If the game is paused then display "well done". When the answer is correct, then set paused = True
and start the timer. See pygame.time.set_timer
:
while gameState != "exit":
if not paused and b2on:
# [...]
if paused:
question("well done")
elif correct:
correct = False
paused = True
pygame.time.set_timer(pausetimerevent, 5000) # 5000 milliseconds = 5 socond
After the the time has elapsed, the event occurs. Reset paused
and reset the timer by passing 0 to the time argument:
while gameState != "exit":
# [...]
for event in pygame.event.get(): # get user interaction events
if event.type == pygame.QUIT: # tests if window's X (close) has been clicked
gameState = "exit" # causes exit of game loop
if event.type == pygame.MOUSEBUTTONDOWN:
mouse_pos = event.pos # gets mouse position
# [...]
if event.type == pausetimerevent:
pygame.time.set_timer(pausetimerevent, 0) # stop timer
paused = False