Trying to figure out how to track Pygame events an

2019-03-01 01:32发布

问题:

I'm new to Pygame, so I'm still struggling with the whole "events" concept.

Basically, my current challenge is to:

  1. Get pygame.event.get() working outside of the main loop so that I can allow for the player to proceed from one part of the game to the next (by pressing spacebar, for instance).

  2. Figure out a way to organize the different functions of the game in the main thread so that they don't just keep looping over and over and overriding each other.

I understand how the main loop is crucial in many games, but I can't grasp how I could use it in this game when the game involves moving from one event to the next (it's a relatively simple text-based game where you go through different menus and select choices to progress). Since the main loop is a while loop, everything within it keeps repeating over and over, so how is it possible for me to go from one screen to the next without the screens infinitely clashing with each other?

For instance, I have an introductory sequence (an Intro() function) that is supposed to run first before anything else and then allow you to proceed to the actual game by hitting the spacebar. I have placed the Intro() function before the actual main loop to prevent it from looping. However, pygame.event.get() doesn't work inside it (bear in mind that I already have such an event "for" loop in the main loop), and I want to be able to progress to the game itself by hitting the spacebar.

It would be great if someone can enlighten me and give me a lesson in logic and threading.

Thanks.

回答1:

Stick with a single main loop, and don't use threads if you don't really need them.

You already figured out that your game consists of different screens (let's call them Scene so we don't confuse it with the actual screen where we draw stuff), so the next logical step is to seperate them out from the main loop.


Say you have the following scenes:

  • intro
  • main menu
  • game play

then you should create a class for each of those, which will then be responsible for drawing/event handling/whatever-needed-in-this-part.

A simple example:

import pygame
pygame.init()

class Scene(object):
    screen = None

class Intro(Scene):
    def __init__(self):
        self.c = (32, 32, 100)

    def draw(self):
        Scene.screen.fill(self.c)

    def update(self):
        # since scenes are classes, they have a state that we can modify
        r,g,b = self.c
        r += 1
        g += 1
        b += 2
        if r > 255: r = 0
        if g > 255: g = 0
        if b > 255: b = 0
        self.c = r, g, b

    def handle(self, event):
        # move to Menu-scene when space is pressed
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_SPACE:
                # returning a scene from handle or update changes the current scene
                return Menu()

class Menu(Scene):
    def draw(self):
        # draw menu
        Scene.screen.fill((200, 200, 100))

    def update(self):
        pass
        # do something

    def handle(self, event):
        # handle menu input
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_a:
                return Game()
            if event.key == pygame.K_b:
                return Intro()

class Game(Scene):
    pass # implement draw update handle

Scene.screen = pygame.display.set_mode((800, 600))

scene = Intro()
while True:
    if pygame.event.get(pygame.QUIT): break
    for e in pygame.event.get(): 
        scene = scene.handle(e) or scene
    scene = scene.update() or scene
    scene.draw()
    pygame.display.flip()

This way, you have a single mainloop, but different parts of your game are managed by seperate classes. In the simple example above, each scene knows what other scene to activate on a certain event, but this is not necessary. You could create some kind of SceneHandler that manages the transitions between the scenes. Also, you may want to have some kind of game state object that you want to pass around scenes (e.g. show your points from the game scene in your game-over scene).