Я создаю игру-платформер с использованием PyGame и собираюсь использовать тайловый подход к каждому уровню с классом, который содержит весь 2D-массив тайлов в макете, подобном уровню, и называю его TileMap. Однако при запуске игры я ожидаю 120+ кадров в секунду, чего и следовало ожидать, поскольку это не особенно требовательное приложение для запуска.
Однако я начал замечать, что игра работала со скоростью 45-50 кадров в секунду, 60 подряд, что меня удивило. Используя функцию с модулями cProfile, pstats и io, которая по существу работает как отладочное сообщение, мне было показано, что в каждом кадре функция TileMap.draw() вызывает метод draw() для каждого тайла в окне просмотра камеры (1536x960 на экране с разрешением 1920x1200, масштабирование 125%) - всего это было 1519 раз, то есть 1519 блитов. Это было очень медленно: требовалось 38% времени, которое мне требовалось для длительности каждого кадра (3 из 8 мс), если я хотел достичь 120 кадров в секунду. Поэтому я разработал в TileMap метод, который, как только все тайлы установлены (это происходит извне, поэтому вы не увидите, как фрагменты загружаются внутри TileMap при инициализации), установщик также вызывает TileMap.gen_chunks(), присваивая возвращаемый список[pygame.Surface] TileMap.chunks. Каждый фрагмент имеет размер моего экрана, поэтому для уровня размером 35 на 30 тайлов (каждый тайл — 32 пикселя) весь уровень был покрыт всего двумя фрагментами.
Я ожидал, что это значительно улучшит мою производительность, ведь это всего лишь два блита. Я написал функцию draw_fast() — на случай, если она не сработает, я сохранил старую функцию draw() — и теперь отладочное сообщение показывало мне, что происходит только два блита, как я и ожидал. Но по неизвестной причине каждый отдельный кадр занимает 13 мс, что почти вдвое превышает целевое значение для одних только 120 кадров в секунду. Что я сделал не так? Смотрите мой код ниже:
tilemap.py
from data.constants import *
from world.tile import Tile, TileType
from world.camera import Camera
import logic.geometry as geometry
import pygame
import math
#tilemap class, used for a large group of tiles
class TileMap:
def __init__(self, width: int, height: int):
self.width = width
self.height = height
self.tiles = self.gen_tiles() #indexed [y][x]
self.tile_size = TILE_SIZE
self.start_tile : tuple[int, int] | None = None
self.end_tile : tuple[int, int] | None = None
self.chunks : list[pygame.Surface] = []
def gen_tiles(self):
tiles : list[list[Tile]] = []
for row in range(self.height):
row_list : list[Tile] = []
for col in range(self.width):
row_list.append(Tile(TileType.EMPTY, pygame.Vector2(col * TILE_SIZE, row * TILE_SIZE)))
tiles.append(row_list)
return tiles
def get_tile(self, grid_x: int, grid_y: int):
if not(0