问题
I am coding a very basic game on pygame for a project and the main function of the game is to ask 20 questions based on which operator(s) and level the user has picked to play the game at.
I am really struggling with two things:
the first being that the code which I have written does produce 20 questions with the correct operator and level of difficulty however I don't know how to blit these to the screen one at a time each time the user has answered the last one. Currently, the code only shows the last question on the screen.
The second problem I am having is making the multiple-choice buttons for each question. I have a 'Button' class in my game which is the same as the 'Text' class which you can see in the code however it also tracks when the button has been clicked on.
For each question, I need to have 4 instances of the button class on the screen one of which is the correct answer for each question and the other three and random numbers and I need the code to randomize which button is the answer for each question so the answer isn't always the same button.
I also have a stopwatch in my game and none of these can interfere with it.
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
exit()
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
pygame.quit()
gameBG=pygame.image.load('gameBG.bmp').convert()
screen.blit(gameBG,(0,0))
questiontxt= Text((325,45),(question), (white), 80)
questiontxt.draw(screen)
ticks=pygame.time.get_ticks()
if timing == False:
timing=True
seconds=0
seconds=int((ticks/1000%60))
minutes=int((ticks/60000%24))
out='{minutes:02d}:{seconds:02d}'.format(minutes=minutes, seconds=seconds)
timefont.render_to(screen,(855,50),out, green)
pygame.display.update()
clock.tick(60)
while j < 38:
qnum1=int(numlist[j])
qnum2=int(numlist[j+1])
if section == 'mixed':
mixedno=random.randrange(0,4)
operators=['addition','subtraction','division','multiplication']
qsection=operators[mixedno]
else:
qsection=section
if qsection == 'addition':
question=str(qnum1)+ '+'+ str(qnum2)+' = ?'
answer= qnum1+qnum2
elif qsection == 'subtraction':
question=str(qnum1)+ '-'+ str(qnum2)+' = ?'
answer= qnum1-qnum2
elif qsection == 'multiplication':
question=str(qnum1)+ 'x'+ str(qnum2)+' = ?'
answer= qnum1*qnum2
else:
question=str(qnum1)+'÷'+str(qnum2)+' = ?'
answer= qnum1/qnum2
print(question)
questiontxt= Text((325,45),(question), (white), 80)
questiontxt.draw(screen)
j=j+2
回答1:
Let's start with a new, basic pygame program. I usually start like this:
import pygame
def main():
screen = pygame.display.set_mode((640, 480))
clock = pygame.time.Clock()
dt = 0
while True:
events = pygame.event.get()
for e in events:
if e.type == pygame.QUIT:
return
screen.fill(pygame.Color('lightgrey'))
pygame.display.flip()
dt = clock.tick(60)
if __name__ == '__main__':
main()
Not much to see here. We create a window, paint it grey, handle events and keep track of the delta time (the time each frame takes).
Let's also think a moment of how the game is supposed to work. First, we have a title screen, then we select a difficulty, then we show some questions, and finally, we display the result. We call each of those parts a scene, and we jump from one to another.
Here's a way we could implement these:
import pygame
import pygame.freetype
class SimpleScene:
FONT = None
def __init__(self, text, next_scene):
self.background = pygame.Surface((640, 480))
self.background.fill(pygame.Color('lightgrey'))
if text:
if SimpleScene.FONT == None:
SimpleScene.FONT = pygame.freetype.SysFont(None, 32)
SimpleScene.FONT.render_to(self.background, (120, 180), text, pygame.Color('black'))
SimpleScene.FONT.render_to(self.background, (119, 179), text, pygame.Color('white'))
self.next_scene = next_scene
def start(self):
pass
def draw(self, screen):
screen.blit(self.background, (0, 0))
def update(self, events, dt):
for event in events:
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
return self.next_scene
def main():
pygame.init()
screen = pygame.display.set_mode((640, 480))
clock = pygame.time.Clock()
dt = 0
scenes = {
'TITLE': SimpleScene('PRESS SPACE TO START', 'GAME'),
'GAME': SimpleScene('Can you press [SPACE]', 'RESULT'),
'RESULT': SimpleScene('You win! 100 points!', 'TITLE'),
}
scene = scenes['TITLE']
while True:
events = pygame.event.get()
for e in events:
if e.type == pygame.QUIT:
return
next_scene = scene.update(events, dt)
if next_scene:
scene = scenes[next_scene]
scene.start()
scene.draw(screen)
pygame.display.flip()
dt = clock.tick(60)
if __name__ == '__main__':
main()
We can now transition between the scenes by pressing space. As you can see, each scene is like a miniature game itself; of course we only have the SimpleScene
that does nothing but draw a simple text, so let's change that and implement the real game. We also have a game state, so we need to keep track if it, too.
Here's how it could look like:
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
self.questions = [
('How many legs has a cow?', 4),
('How many legs has a bird?', 2),
('What is 1 x 1 ?', 1)
]
self.current_question = None
self.right = 0
self.wrong = 0
def pop_question(self):
q = random.choice(self.questions)
self.questions.remove(q)
self.current_question = q
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 = []
x = 120
y = 120
for n in range(4):
rect = pygame.Rect(x, y, 80, 80)
self.rects.append(rect)
x += 100
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)
SimpleScene.FONT.render_to(screen, (rect.x+30, rect.y+30), str(n), pygame.Color('black'))
SimpleScene.FONT.render_to(screen, (rect.x+29, rect.y+29), 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 = []
x = 120
y = 120
for n in range(4):
rect = pygame.Rect(x, y, 80, 80)
self.rects.append(rect)
x += 100
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 = 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)
SimpleScene.FONT.render_to(screen, (rect.x+30, rect.y+30), str(n), pygame.Color('black'))
SimpleScene.FONT.render_to(screen, (rect.x+29, rect.y+29), 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):
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()
Of course it's not 100% finished, but it should give you an idea on how to structure your game to get what you want.
As you can see, each scene handles its own aspect of the game, and the game scene jumps to itself while passing the game state. To add a timer, you can simply store the current game time (e.g. pygame.time.get_ticks()) in the game state the first time its start
function is called, and calculate the remaining time in the update
function of the scene. If the timer runs out, jump to a scene that displays the result.
来源:https://stackoverflow.com/questions/59726334/how-to-ask-20-multiple-choice-questions-on-pygame