Pygame 人生游戏 运行 慢

Pygame game of life running slow

我决定创建一个更简单的生命游戏版本,因为我无法真正使用我的旧版本。我现在有一个 GameOfLife class,但它 运行 非常慢。当我点击一个单元格时,它需要一些时间才能activates/deactivates,等等。有人知道为什么它很慢吗?是不是 FPSCLOCK 有问题,还是我 运行 不应该 运行?

import pygame

# Defining the grid dimensions.
GRID_SIZE = width, height = 500, 500
# Defining the size of the cells, and how many cells there are in the x and y direction.
CELL_SIZE = 10
X_CELLS = int(width/CELL_SIZE)
Y_CELLS = int(height/CELL_SIZE)

#  Defining a color for dead cells (background) and alive cells.
COLOR_DEAD = 0 #background
COLOR_ALIVE = 1 #alive_cell
colors = []
colors.append((  0,   0,   0)) #Black
colors.append((0, 128, 128)) #blue
# Two lists, one for the current generation, and one for the next generation, so you can have iterations.
current_generation = [[COLOR_DEAD for y in range(Y_CELLS)] for x in range(X_CELLS)]
next_generation = [[COLOR_DEAD for y in range(Y_CELLS)] for x in range(X_CELLS)]

fps_max = 10

class GameOfLife:
    def __init__(self):
        self.next_iteration = False
        self.game_over = False
        # Starting pygame
        pygame.init()
        pygame.display.set_caption("Game of Life - Created by")  # Gives a title to the window
        self.screen = pygame.display.set_mode(GRID_SIZE)  # Create the window with the GRID_SIZE.
        #Clock to set the FPS
        self.FPSCLOCK = pygame.time.Clock()
        # Initialise the generations
        self.init_gen(current_generation, COLOR_DEAD)

    # Initializing all the cells.
    def init_gen(self, generation, c):
        for y in range(Y_CELLS):
            for x in range(X_CELLS):
                generation[x][y] = c
    # Drawing the cells, color black or blue at location x/y.
    def draw_cell(self, x, y, c):
        pos = (int(x * CELL_SIZE + CELL_SIZE / 2),
               int(y * CELL_SIZE + CELL_SIZE / 2))
        # pygame.draw.rect(screen, colors[c], pygame.Rect(x * CELL_SIZE, y * CELL_SIZE, CELL_SIZE-1, CELL_SIZE-1))
        # pygame.draw.circle(screen, colors[c], pos, CELL_SIZE, CELL_SIZE) #Weird form, can also be used instead of rectangles
        pygame.draw.circle(self.screen, colors[c], pos, 5,0)  # Use the last two arguments (radius, width) to change the look of the circles.

        pygame.display.flip()
    # Updating the cells.
    def update_gen(self):
        global current_generation
        for y in range(Y_CELLS):
            for x in range(X_CELLS):
                c = next_generation[x][y]
                self.draw_cell(x, y, c)
        # Update current_generation
        current_generation = list(next_generation)

    # Activate a living cell
    def activate_living_cell(self, x, y):
        global next_generation
        next_generation[x][y] = COLOR_ALIVE

    # Deactivate a living cell
    def deactivate_living_cell(self, x, y):
        global next_generation
        next_generation[x][y] = COLOR_DEAD

    # Function to check neighbor cell
    def check_cells(self, x, y):
        # Ignoring cells off the edge
        if (x < 0) or (y < 0): return 0
        if (x >= X_CELLS) or (y >= Y_CELLS): return 0
        if current_generation[x][y] == COLOR_ALIVE:
            return 1
        else:
            return 0

    def check_cell_neighbors(self, row_index, col_index):
        # Get the number of alive cells surrounding the current cell
        num_alive_neighbors = 0
        num_alive_neighbors += self.check_cells(row_index - 1, col_index - 1)
        num_alive_neighbors += self.check_cells(row_index - 1, col_index)
        num_alive_neighbors += self.check_cells(row_index - 1, col_index + 1)
        num_alive_neighbors += self.check_cells(row_index, col_index - 1)
        num_alive_neighbors += self.check_cells(row_index, col_index + 1)
        num_alive_neighbors += self.check_cells(row_index + 1, col_index - 1)
        num_alive_neighbors += self.check_cells(row_index + 1, col_index)
        num_alive_neighbors += self.check_cells(row_index + 1, col_index + 1)
        return num_alive_neighbors

    # Rules
    # 1 Any live cell with fewer than two live neighbors dies, as if by underpopulation.
    # 2 Any live cell with two or three live neighbors lives on to the next generation.
    # 3 Any live cell with more than three live neighbors dies, as if by overpopulation.
    # 4 Any dead cell with exactly three live neighbors becomes a live cell, as if by reproduction.
    def create_next_gen(self):
        for y in range(Y_CELLS):
            for x in range(X_CELLS):
                # If cell is live, count neighboring live cells
                n = self.check_cell_neighbors(x, y)  # number of neighbors
                c = current_generation[x][y]  # current cell (either dead or alive).
                if c == COLOR_ALIVE:  # If the cell is living:
                    if (n < 2):  # Rule number 1, underpopulation
                        next_generation[x][y] = COLOR_DEAD
                    elif (n > 3):  # Rule number 3, overpopulation
                        next_generation[x][y] = COLOR_DEAD
                    else:  # Rule number 3, 2 or 3 neighbors, staying alive.
                        next_generation[x][y] = COLOR_ALIVE
                else:  # if the cell is dead:
                    if (n == 3):
                        # Rule number 4: A dead cell with three living neighbors becomes alive.
                        next_generation[x][y] = COLOR_ALIVE

    # Runs the game loop
    def handle_events(self):
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                self.game_over = True  # If pressing the quit button, it closes the window.
            if event.type == pygame.MOUSEBUTTONDOWN:  # if pressing the mouse button, it gets the position. If the cell is dead, make it alive, if the cell is alive, make it dead.
                posn = pygame.mouse.get_pos()
                x = int(posn[0] / CELL_SIZE)
                y = int(posn[1] / CELL_SIZE)
                if next_generation[x][y] == COLOR_DEAD:
                    self.activate_living_cell(x, y)
                else:
                    self.deactivate_living_cell(x, y)
            # Check for q, g, s or w keys
            if event.type == pygame.KEYDOWN:  # keydown --> quits when the button goes down. keyup --> quits when the button goes up again.
                if event.unicode == 'q':  # Press q to quit.
                    self.game_over = True
                    print("q")

                elif event.key == pygame.K_SPACE:  # Space for the next iteration manually.
                    self.create_next_gen()
                    print("keypress")
                elif event.unicode == 'a':  # a to automate the iterations.
                    self.next_iteration = True
                    print("a")
                elif event.unicode == 's':  # s to stop the automated iterations.
                    self.next_iteration = False
                    print("s")
                elif event.unicode == 'r':  # r to reset the grid.
                    self.next_iteration = False
                    self.init_gen(next_generation, COLOR_DEAD)
                    print("r")
    def run(self):
        while not self.game_over:
            # Set the frames per second.
            self.handle_events()
            if self.next_iteration:  # if next iteration is true, the next gen is created according to the rules.
                self.create_next_gen()
            # Updating
            self.update_gen()
            self.FPSCLOCK.tick(fps_max)

if __name__ == "__main__":
    game = GameOfLife()
    game.run()

pygame.display.flip() 调用重绘整个屏幕 - 您为每个重绘的单元格调用 一次

将该调用从上面的 draw_cell 方法移动到方法 gen_update() 的末尾,您应该没问题。更好的是,只需将它从任何方法中删除,并将它放在主循环的末尾,就在调用时钟滴答之前:

def run(self):
    while not self.game_over:
        # Set the frames per second.
        self.handle_events()
        if self.next_iteration:  # if next iteration is true, the next gen is created according to the rules.
            self.create_next_gen()
        # Updating
        self.update_gen()
        pygame.display.flip()
        self.FPSCLOCK.tick(fps_max)