В эти дни я пытался сделать Игру жизни Конвея в Pygame. Он уже закончен и работает хорошо, но я не хотел ограничивать себя в том, чтобы запускать игру с небольшой сеткой, поэтому я решил попробовать что-то вроде сетки 274x147 (так что она почти заполняет весь экран). Проблема в том, что с python нормальными «матрицами» (массивами массивов) он работал невероятно медленно. После некоторого чтения я пришел к выводу, что было бы лучше использовать Numpy матрицы, но после этого ничего существенно не изменилось. Проводя дальнейшие исследования, я наткнулся на разреженные матрицы Scipy, которые идеально вписались в проект, потому что в игровой жизни матрица в большинстве случаев разрежена, но когда я попытался реализовать их в коде, FPS значительно упал, даже когда Я не перебирал их. Почему это? Любой совет, чтобы помочь мне оптимизировать мой код?
Я прилагаю свой основной скрипт здесь:
import math
import numpy
import scipy.sparse as sparse
import pygame.math as m
from text import Text
from button import Button
pygame.init()
clock = pygame.time.Clock()
drawing = False
erasing = False
started = False
timer = False
time_since_last_iter = 0
screen = pygame.display.set_mode((0, 0), pygame.FULLSCREEN)
pygame.display.set_caption("Game of Life")
icon = pygame.image.load("res/icon.png")
cell_img = pygame.image.load("res/cell.png")
font = pygame.font.Font("res/arcadeclassic.ttf", 32)
pygame.display.set_icon(icon)
bg = pygame.image.load("res/grid.png")
fps_txt = Text(screen, (255, 255, 255), font, m.Vector2(10, 10)) #Fps text object, so I can see how's the game running
button = Button(screen, m.Vector2(screen.get_width() - 110, 10), m.Vector2(100, 30), (95, 95, 95), (80, 80, 80), "Run") #Button to start the game
mat_dim = (274, 147)
cell = sparse.lil_matrix(mat_dim, dtype=bool)
running = True
while running:
screen.fill((0,0,0))
screen.blit(bg, (0, 0))
mp = pygame.mouse.get_pos()
mouse_pos = m.Vector2(mp[0], mp[1])
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
running = False
if event.type == pygame.MOUSEBUTTONDOWN:
if event.button == 1 and button.check_pos(mouse_pos):
started = True
elif not started:
if event.button == 1 and not button.check_pos(mouse_pos):
drawing = True
elif event.button == 3 and not started:
erasing = True
if event.type == pygame.MOUSEBUTTONUP and not started:
if event.button == 1:
drawing = False
elif event.button == 3:
erasing = False
if not started:
if drawing:
if mouse_pos.y >= 50:
grid_mouse_y = mouse_pos.y - 50
cell[int(mouse_pos.x / 7), int(grid_mouse_y / 7)] = True
elif erasing:
if mouse_pos.y >= 50:
grid_mouse_y = mouse_pos.y - 50
cell[int(mouse_pos.x / 7), int(grid_mouse_y / 7)] = False
global_time = pygame.time.get_ticks()
if global_time - time_since_last_iter > 200:
time_since_last_iter = global_time
timer = True
if started:
global_time = pygame.time.get_ticks()
if global_time - time_since_last_iter > 200:
time_since_last_iter = global_time
timer = True
if timer:
next_matrix = sparse.lil_matrix(mat_dim, dtype=bool)
for i in range(mat_dim[0]):
for j in range(mat_dim[1]):
neighbours = 0
# Neighbour count
for s_i in range(-1, 2):
for s_j in range(-1, 2):
try:
if cell[i + s_i, j + s_j] and not (s_i == 0 and s_j == 0):
neighbours += 1
except IndexError:
continue
if cell[i, j]:
if neighbours > 3 or neighbours < 2:
next_matrix[i, j] = False
else:
next_matrix[i, j] = True
elif neighbours == 3:
next_matrix[i, j] = True
else:
next_matrix[i, j] = False
for i in range(mat_dim[0]):
for j in range(mat_dim[1]):
if not next_matrix[i, j] and cell[i, j]:
cell[i, j] = False
elif next_matrix[i, j] and not cell[i, j]:
cell[i, j] = True
timer = False
for i in range(mat_dim[0]):
for j in range(mat_dim[1]):
if cell[i, j]:
screen.blit(cell_img, (i * 7, j * 7 + 50))
button.draw(mouse_pos)
clock.tick()
fps_txt.draw("fps " + str(math.ceil(clock.get_fps())))
pygame.display.update()```