[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

Re: [pygame] Slow rendering speed - sprites



Hi,

See the attached for some tweaks.

I bumped the number of sprites up to 200.

When I used my own 100x100-pixels png that has an alpha layer I get a bit more than 100 fps. Alpha layers take extra CPU to render.

When I use same-size filled rects of the same dimensions I get a little over 200 fps.

When you load your image, you might get better performance if you convert() it or convert_alpha().

Hope this helps.

Gumm

On 3/7/2015 1:37 PM, David Unric wrote:
Hello,

I'm considering a game framework for next more serious project. As I'm
Python/Ruby language agnostic, I did rewrote simple sprite benchmark
from Gosu to latest Pygame to do a performance comparison. You may
find the code bellow.

I was very surprised Pygame version performs much more worse. To get
an idea, it was tested on the same machine, in the same environment,
linked against same SDL 1.2.15, run with Python 2.7.5. It starts
significantly drop framerate when sprites count gets over 20, whereas
Gosu version with Ruby 2.2.0 smoothly renders 200 sprites at 60 fps !
At about 100 sprites on the screen it becomes just a very slow slideshow.

I don't know if something important performance-wise was missed.
Simple background is a static surface, display is also initialized
with native resolution 1376x768 in fullscreen,
LayeredDirty group with DirtySprites for better performance (Gosu
version also handles z-order of each sprite).

Any idea what am I doing wrong ?


_______________________________________ snip
____________________________________________________
import pygame, pygame.gfxdraw
from pygame import *
from random import randint

def main():
     pygame.init()

     video_info = pygame.display.Info()
     if video_info.current_w != -1 and video_info.current_h != -1:
         screen_width, screen_height = video_info.current_w, video_info.current_h
     else:
         screen_width, screen_height = 800, 600

     screen  = pygame.display.set_mode((screen_width, screen_height),
             FULLSCREEN | DOUBLEBUF | HWSURFACE)
     pygame.display.set_caption(__name__.upper())

     background  = pygame.Surface(screen.get_size()).convert()
     background.fill((0, 0, 0))
     pygame.gfxdraw.filled_trigon(background,
             screen_width/10, screen_height/10,
             screen_width*9/10, screen_height*9/10,
             screen_width/2, screen_height*9/10,
             (210, 200, 77))
     sprites     = pygame.sprite.LayeredDirty()
     image       = pygame.image.load('my_sprite.png')
     for _ in xrange(30): XSprite(image, sprites)
     del image

     # main game loop
     while True:
         for event in pygame.event.get():
             if event.type   == QUIT: return
             elif event.type == KEYDOWN and event.key == K_ESCAPE: return

         screen.blit(background, (0, 0))
         sprites.update(screen)
         sprites.draw(screen)
         pygame.display.flip()

class XSprite(pygame.sprite.DirtySprite):
     def __init__(self, image, *groups):
         super(XSprite, self).__init__(*groups)
         self.image  = image
         self.rect   = self.image.get_rect()
         self.rect.x = randint(0, 60)
         self.rect.y = randint(0, 40)
         self.dx, self.dy = randint(1, 16), randint(1, 16)

     def update(self, screen, *args):
         screen_w, screen_h = screen.get_size()
         self.rect.x += self.dx
         self.rect.y += self.dy
         if (self.rect.x + self.dx  + self.rect.w > screen_w) or \
                 (self.rect.x + self.dx < 0):
             self.dx = -self.dx
         if (self.rect.y + self.dy + self.rect.h > screen_h) or \
                 (self.rect.y + self.dy < 0):
             self.dy = -self.dy
         self.rect.move_ip(self.dx, self.dy)

if __name__ == '__main__':
     main()

# vim: set ft=python ts=8 sts=4 sw=4 tw=79 fdm=indent:
_______________________________________ snip
____________________________________________________

import pygame, pygame.gfxdraw
from pygame import *
from random import randint


def main():
    pygame.init()

    video_info = pygame.display.Info()
    if video_info.current_w != -1 and video_info.current_h != -1:
        screen_width, screen_height = video_info.current_w, video_info.current_h
    else:
        screen_width, screen_height = 800, 600

    screen = pygame.display.set_mode((screen_width, screen_height), FULLSCREEN | DOUBLEBUF)  # | HWSURFACE)
    pygame.display.set_caption(__name__.upper())

    background = pygame.Surface(screen.get_size()).convert()
    background.fill((0, 0, 0))
    pygame.gfxdraw.filled_trigon(
        background,
        screen_width / 10, screen_height / 10,
        screen_width * 9 / 10, screen_height * 9 / 10,
        screen_width / 2, screen_height * 9 / 10,
        (210, 200, 77))
    sprites = pygame.sprite.LayeredDirty()
    sprites.clear(screen, background)
    # image = pygame.image.load('tomato.png').convert_alpha()
    image = pygame.Surface((100, 100))
    image.fill(Color('red'))
    for _ in xrange(200):
        XSprite(image, sprites)
    del image

    clock = pygame.time.Clock()
    timer = 1.0
    sans_font = pygame.font.SysFont('sans', 18, True)
    fps = None
    fps_rect = None

    # main game loop
    while True:
        timer -= clock.tick() / 1000.0
        if timer <= 0.0:
            timer += 1.0
            fps = sans_font.render('{0:0.0f} fps'.format(clock.get_fps()), True, Color('yellow'))

        for event in pygame.event.get():
            if event.type == QUIT:
                return
            elif event.type == KEYDOWN and event.key == K_ESCAPE:
                return

        if fps_rect:
            screen.blit(background, (0, 0), fps_rect)
        sprites.update(screen)
        dirty_rects = sprites.draw(screen)
        if fps:
            fps_rect = screen.blit(fps, (0, 0))
            dirty_rects.append(fps_rect)
        pygame.display.update(dirty_rects)


class XSprite(pygame.sprite.DirtySprite):
    def __init__(self, image, *groups):
        super(XSprite, self).__init__(*groups)
        self.image = image
        self.rect = self.image.get_rect()
        self.rect.x = randint(0, 60)
        self.rect.y = randint(0, 40)
        self.dx, self.dy = randint(1, 16), randint(1, 16)

    def update(self, screen, *args):
        screen_w, screen_h = screen.get_size()
        self.rect.x += self.dx
        self.rect.y += self.dy
        if (self.rect.x + self.dx + self.rect.w > screen_w) or \
                (self.rect.x + self.dx < 0):
            self.dx = -self.dx
        if (self.rect.y + self.dy + self.rect.h > screen_h) or \
                (self.rect.y + self.dy < 0):
            self.dy = -self.dy
        self.rect.move_ip(self.dx, self.dy)
        self.dirty = True

if __name__ == '__main__':
    main()