PyGame正在以非常慢的速度运行生命的游戏

2022-02-22 00:00:00 python numpy pygame

问题描述

与此相关的两个其他问题已通过将绘制事件移出不应该在其中的循环来解决。不过,我没有这个问题。如有任何帮助,我们将不胜感激!

Python:3.8

PyGame:1.9.6

如果您需要测试播放:

运行游戏。在屏幕上绘制以放置活动单元格。单击"R"开始。您也可以在开始停止并重新绘制后单击"S",但您需要在单击几代之后才能真正停止(因为我假设是由于相同的延迟)。

import pygame
import numpy

class Game():
    def __init__(self):
        self.Run()

    def GetAdj(self, x, y):
        nb = 0
        for c in range (-1, 2):
            for r in range (-1, 2):
                if r == 0 and c == 0:
                    pass
                else:
                    nposx = x + r
                    nposy = y + c
                    if nposx < len(self.pixels):
                        if nposy < len(self.pixels[nposx]):
                            if self.pixels[nposx][nposy] == 1:
                                nb += 1
        return nb

    def NextGeneration(self):
        newGeneration = numpy.zeros(self.ScreenWidth//2, self.ScreenHeight//2, dtype=int)
        for x, c in enumerate(self.pixels):
            for y, cell in enumerate(c):
                nbrs = self.GetAdj(x, y)
                if cell == 1:
                    if nbrs in [2, 3]:
                        newGeneration[x][y] = 1
                else:
                    if nbrs == 3:
                        newGeneration[x][y] = 1
        self.pixels = newGeneration

    def DrawBG(self):
        black = (0,0,0)
        white = (255,255,255)
        self.bg.fill(black)
        for c in range(self.ScreenWidth // self.cellsize):
            for r in range(self.ScreenHeight // self.cellsize):
                if self.pixels[c][r] == 1:
                    pygame.draw.rect(self.bg, white, (c*self.cellsize, r*self.cellsize, self.cellsize, self.cellsize))

    def Run(self):
        pygame.init()
        self.ScreenHeight = 720
        self.ScreenWidth = 1280
        self.ScreenSize = (self.ScreenWidth, self.ScreenHeight)
        screen = pygame.display.set_mode(self.ScreenSize)
        self.bg = pygame.Surface(self.ScreenSize)
        clock = pygame.time.Clock()
        mousedown = False
        self.pixels = numpy.zeros(self.ScreenWidth//2, self.ScreenHeight//2, dtype=int)
        self.cellsize = 10
        stage = 'Draw'
        running = True
        while running:
            clock.tick(60)
            events = pygame.event.get()
            for event in events:
                if event.type == pygame.QUIT:
                    running = False
            if stage == 'Draw':
                for event in events:
                    if event.type == pygame.MOUSEBUTTONUP and mousedown:
                        mousedown = False
                    elif event.type == pygame.MOUSEBUTTONDOWN:
                        mousedown = True
                    elif event.type == pygame.MOUSEMOTION and mousedown and stage == 'Draw':
                        mposx, mposy = pygame.mouse.get_pos()
                        self.pixels[mposx//self.cellsize][mposy//self.cellsize] = 1
                    elif event.type == pygame.KEYDOWN and event.key == pygame.K_r:
                        stage = 'Run'
                        self.NextGeneration()

            elif stage == 'Run':
                for event in events:
                    if event.type == pygame.KEYDOWN and event.key == pygame.K_s:
                        stage = 'Draw'
                self.NextGeneration()

            self.DrawBG()
            screen.blit(self.bg, (0,0))
            pygame.display.flip()

if __name__ == "__main__":
    Game()

解决方案

Numpy数组太大。您可以为每个像素(而不是每个单元格)创建一个数组。所以不要计算每个单元格,而要计算每个像素。

更改NextGenerationRun方法中的数组大小:

newGeneration = numpy.zeros(self.ScreenWidth//2, self.ScreenHeight//2, dtype=int)

newGeneration = numpy.zeros((self.ScreenWidth//self.cellsize, self.ScreenHeight//self.cellsize), dtype=int)

self.pixels = numpy.zeros(self.ScreenWidth//2, self.ScreenHeight//2, dtype=int)

self.cellsize = 10
self.pixels = numpy.zeros((self.ScreenWidth//self.cellsize, self.ScreenHeight//self.cellsize), dtype=int)

GetAdj方法可以通过numpy.sum

大大简化
class Game():
    # [...]

    def GetAdj(self, x, y):
        x0, y0 = max(0, x-1), max(0, y-1)
        nb = numpy.sum(self.pixels[x0 : x+2, y0 : y+2]) - self.pixels[x, y]
        return nb

使用scipy.ndimage.convolve和查找表(参见Indexing Multi-dimensional arrays)可以进一步提高性能:

import numpy
from scipy.ndimage import convolve

class Game():
    def __init__(self):
        self.kernel = numpy.array([[1,1,1], [1,0,1], [1,1,1]])
        self.lookup = numpy.array([0,0,0,1,0,0,0,0,0, 0,0,1,1,0,0,0,0,0])
        self.Run()

    def NextGeneration(self):
        adjacent = convolve(self.pixels, self.kernel, mode='constant')
        newGeneration = self.lookup[self.pixels * 9 + adjacent]
        self.pixels = newGeneration

相关文章