Итак, вместе с друзьями я делаю игру на Pygame, и я только что начал программировать анимацию для главного героя.
Я подумал, что есть несколько способов сделать это. Либо составьте список изображений и просто перебирайте список, либо создайте словарь, содержащий координаты изображений на листе спрайтов.
Я выбрал второй вариант и решил проверить, какой из них быстрее. Поэтому я запрограммировал их обоих довольно упрощенным способом, просто чтобы быстро проверить, как они работают.
Результаты были очень близки друг к другу (0,41 со словарями и около 0,40 без них). Затем я решил, что хочу попробовать, что произойдет, если я выберу первый вариант, за исключением того, что я вызову pygame.image.load в отдельном файле и сохраню кадры анимации как глобальные переменные, которые затем будут импортированы в основной файл.
Я думал, что это будет очень медленно, потому что я где-то читал, что импорт python очень медленный ... Но на удивление я получил результат 0,021 секунды!
Это огромное изменение производительности, которое может иметь решающее значение для моей игры, поэтому мне было интересно, знает ли кто-нибудь, почему этот метод намного быстрее, и только из-за определенных x или y, почему он быстрее в этом случай и будет очень медленным в другом.
Вот код, похожий на текущее состояние моей игры:
import pygame
import time
start_time = time.time()
playerSpriteSize = 192
img = (0, 0)
class SpriteSheet():
def __init__(self, filename):
self.sheet = pygame.image.load(filename).convert()
def get_image(self, coords, size, flip=False):
surf = pygame.Surface(size).convert()
surf.blit(self.sheet, (0, 0), (coords[0], coords[1], size[0], size[1]))
pygame.transform.flip(surf, False, True)
surf.set_colorkey((0, 0, 0))
surf = pygame.transform.flip(surf, flip, False)
return surf
pygame.init()
displaySurface = pygame.display.set_mode((400, 400))
x = SpriteSheet("playerAnimation.png")
animationList = {0: (0, playerSpriteSize*0), 1: (0, playerSpriteSize*1), 2: (0, playerSpriteSize*2),
3: (0, playerSpriteSize*3), 4: (0, playerSpriteSize*4), 5: (0, playerSpriteSize*5),
6: (0, playerSpriteSize*6)}
rounda = 0
for i in animationList:
a1 = x.get_image(animationList[rounda], (playerSpriteSize, playerSpriteSize))
displaySurface.blit(a1, (30, 30))
rounda += 1
pygame.display.update()
print("--- %s seconds ---" %(time.time() - start_time))
Вот код, который использовал изображения, загруженные перед основным игровым циклом:
import pygame
import time
start_time = time.time()
imageSize = 192
img = (0, 0)
class SpriteSheet():
def __init__(self, filename):
self.sheet = pygame.image.load(filename).convert()
def get_image(self, coords, size, flip=False):
surf = pygame.Surface(size).convert()
surf.blit(self.sheet, (0, 0), (coords[0], coords[1], size[0], size[1]))
pygame.transform.flip(surf, False, True)
surf.set_colorkey((0, 0, 0))
surf = pygame.transform.flip(surf, flip, False)
return surf
pygame.init()
displaySurface = pygame.display.set_mode((400, 400))
x = SpriteSheet("playerAnimation.png")
a1 = x.get_image((0, 0), (imageSize, imageSize))
a2 = x.get_image((0, 192), (imageSize, imageSize))
a3 = x.get_image((0, 384), (imageSize, imageSize))
a4 = x.get_image((0, 576), (imageSize, imageSize))
a5 = x.get_image((0, 768), (imageSize, imageSize))
a6 = x.get_image((0, 960), (imageSize, imageSize))
a7 = x.get_image((0, 1152), (imageSize, imageSize))
animationList = [a1, a2, a3, a4, a5, a6, a7]
for i in animationList:
displaySurface.blit(i, (30, 30))
pygame.display.update()
print("--- %s seconds ---" %(time.time() - start_time))
и это код (разделенный на 2 файла), который выполняется примерно за 0,021 секунды: Файл 1 (основной файл)
import pygame
import time
from mainDifferentExtern import a1, a2, a3, a4, a5, a6, a7
start_time = time.time()
imageSize = 192
img = (0, 0)
class SpriteSheet():
def __init__(self, filename):
self.sheet = pygame.image.load(filename).convert()
def get_image(self, coords, size, flip=False):
surf = pygame.Surface(size).convert()
surf.blit(self.sheet, (0, 0), (coords[0], coords[1], size[0], size[1]))
pygame.transform.flip(surf, False, True)
surf.set_colorkey((0, 0, 0))
surf = pygame.transform.flip(surf, flip, False)
return surf
pygame.init()
displaySurface = pygame.display.set_mode((400, 400))
x = SpriteSheet("playerAnimation.png")
animationList = [a1, a2, a3, a4, a5, a6, a7]
for i in animationList:
displaySurface.blit(i, (30, 30))
pygame.display.update()
print("--- %s seconds ---" %(time.time() - start_time))
и файл, из которого он импортирует:
import pygame
imageSize = 192
class SpriteSheet():
def __init__(self, filename):
self.sheet = pygame.image.load(filename).convert()
def get_image(self, coords, size, flip=False):
surf = pygame.Surface(size).convert()
surf.blit(self.sheet, (0, 0), (coords[0], coords[1], size[0], size[1]))
pygame.transform.flip(surf, False, True)
surf.set_colorkey((0, 0, 0))
surf = pygame.transform.flip(surf, flip, False)
return surf
pygame.init()
pygame.display.set_mode((1, 1))
x = SpriteSheet("playerAnimation.png")
a1 = x.get_image((0, 0), (imageSize, imageSize))
a2 = x.get_image((0, 192), (imageSize, imageSize))
a3 = x.get_image((0, 384), (imageSize, imageSize))
a4 = x.get_image((0, 576), (imageSize, imageSize))
a5 = x.get_image((0, 768), (imageSize, imageSize))
a6 = x.get_image((0, 960), (imageSize, imageSize))
a7 = x.get_image((0, 1152), (imageSize, imageSize))
Обновлено: как было предложено матчем, я изменил метод измерения времени и вместо этого использовал профилирование python (с использованием cProfile), но я получил примерно те же результаты, за исключением того, что время для первых двух методов оказалось немного дольше
@match Вместо этого я перешел на профилирование python и отредактировал сообщение, но мой результат не сильно изменился






С отдельным файлом все вызовы getImage происходят при первом импорте файла. Вы не рассчитываете время импорта, поэтому игнорируете стоимость всего, что делает файл.
Я поместил предложение синхронизации над импортом, и сейчас он также синхронизируется, но метод импорта по-прежнему намного быстрее, поскольку программа выполняется только на 0,02 секунды медленнее и заканчивается на 0,041 секунды по сравнению с другими, которые имеют 0,41 и 0,40
Я считаю, что разница здесь связана с компиляцией байт-кода python для любых импортированных модулей. Это, в свою очередь, ускорит загрузку / выполнение импорта. Вы можете увидеть их как файлы .pyc в каталоге вместе с исходным кодом.
Я подозреваю, что если вы сделаете следующее, ваши результаты снова выровняются:
rm *.pyc
PYTHONDONTWRITEBYTECODE=1 python mygame.py
Также имейте в виду, что вероятность 0,02 секунды находится в пределах обычного «дрейфа» любой системы - вот почему такие инструменты, как timeit, запускают один и тот же код много тысяч раз и усредняют результаты.
В этой заметке - подумайте, сколько раз ваша потенциально медленная операция происходит в коде - если вы загружаете изображения только один раз, а прирост производительности, выполняя это иначе, составляет 0,02 секунды - в то время как игра, как ожидается, будет работать в течение минут или часов, тогда это подозрительно похоже на преждевременную оптимизацию.
Дело в том, что изменение составляет не 0,02 секунды, а 0,2 секунды, что, я бы сказал, большая разница (хотя я могу ошибаться).
Такое измерение времени - не очень точный способ измерения производительности, особенно для быстрых операций. Лучше всего использовать что-то вроде
timeitдля конкретной части, которая, по вашему мнению, может повлиять на производительность, или использовать профилировщик.