2013-11-05 11 views
7

Hier ist der Code. 5000 springende spinnende rote Quadrate. (16x16 png) Bei der Pygame-Version bekomme ich 30 fps, aber 10 fps mit pyglet. Soll OpenGl nicht schneller für so etwas sein?Warum ist Pyglet so langsam im Vergleich zu Pygame?

pygame Version:

import pygame, sys, random 
from pygame.locals import * 
import cProfile 

# Set FPS 
FPS = 60.0 
clock = pygame.time.Clock() 

# Set window 
WINDOWWIDTH= 800 
WINDOWHEIGHT = 600 

pygame.init() 
screen = pygame.display.set_mode((WINDOWWIDTH,WINDOWHEIGHT)) 

screen.fill((0,0,0)) 
background = screen.copy().convert() 
image = pygame.image.load("square.png").convert() 

class Square(object): 
    def __init__(self,x,y): 
     self.x = x 
     self.y = y 
     self.v_x = random.randint(1,100) 
     self.v_y = random.randint(1,100) 
     self.v_r = random.randint(-100,100) 
     self.rotation = 0 

    def __rep__(self): 
     return "Square %d,%d"%(self.x,self.y) 

    def update(self,dt): 
     if self.x > WINDOWWIDTH: 
      self.v_x *= -1 
     elif self.x < 0: 
      self.v_x *= -1 
     if self.y > WINDOWHEIGHT: 
      self.v_y *= -1 
     elif self.y < 0: 
      self.v_y *= -1 

     self.x += self.v_x * dt 
     self.y += self.v_y * dt 
     self.rotation += self.v_r * dt 

    def draw(self): 
     screen.blit(pygame.transform.rotate(image,self.rotation),(self.x,self.y)) 


sqrs = [] 
for _ in range(5000): 
    sqrs.append(Square(random.randint(0,WINDOWWIDTH-1),random.randint(0,WINDOWHEIGHT-1))) 


def main_loop(): 
    tick = 0.0 
    elapsed = 0.0 

    while elapsed < 10.0: 
     dt = tick/1000.0 
     # Events 
     for event in pygame.event.get(): 
      if event.type == QUIT: 
       pygame.quit() 
       sys.exit() 

     # Logic 
     for s in sqrs: 
      s.update(dt) 

     # Drawing 
     screen.blit(background,(0,0)) 
     for s in sqrs: 
      s.draw() 

     pygame.display.update() 
     pygame.display.set_caption('test program FPS: %s'%(clock.get_fps())) 
     tick = clock.tick(FPS) 
     elapsed += tick/1000.0 
    pygame.quit() 

cProfile.run("main_loop()") 
i = input("...") 

Pyglet Version:

import cProfile 
import pyglet, random 
# Disable error checking for increased performance 
pyglet.options['debug_gl'] = False 

from pyglet import clock 

clock.set_fps_limit(60) 

WINDOWWIDTH = 800 
WINDOWHEIGHT = 600 
FPS = 60.0 

batch = pyglet.graphics.Batch() 
window = pyglet.window.Window(WINDOWWIDTH,WINDOWHEIGHT) 
fps_display = pyglet.clock.ClockDisplay() 

image = pyglet.resource.image("square.png") 

class Square(pyglet.sprite.Sprite): 
    def __init__(self,x,y): 
     pyglet.sprite.Sprite.__init__(self,img = image,batch=batch) 
     self.x = x 
     self.y = y 
     self.v_x = random.randint(1,100) 
     self.v_y = random.randint(1,100) 
     self.v_r = random.randint(-100,100) 

    def update(self,dt): 
     if self.x > WINDOWWIDTH: 
      self.v_x *= -1 
     elif self.x < 0: 
      self.v_x *= -1 
     if self.y > WINDOWHEIGHT: 
      self.v_y *= -1 
     elif self.y < 0: 
      self.v_y *= -1 

     self.x += self.v_x * dt 
     self.y += self.v_y * dt 
     self.rotation += self.v_r * dt 

sqrs = [] 
for _ in range(5000): 
    sqrs.append(Square(random.randint(0,WINDOWWIDTH-1),random.randint(0,WINDOWHEIGHT-1))) 

elapsed = 0.0 

def update(dt): 
    global elapsed 
    elapsed += dt 
    if elapsed >= 10.0: 
     clock.unschedule(update) 
     window.close() 
    else: 
     for s in sqrs: 
      s.update(dt) 

@window.event 
def on_draw(): 
    window.clear() 
    batch.draw() 
    fps_display.draw() 


clock.schedule_interval(update, 1.0/FPS) 

if __name__ == '__main__': 
    cProfile.run("pyglet.app.run()") 
    c = input("...") 

cProfile Ergebnis für pygame:

  5341607 function calls in 9.429 seconds 

    Ordered by: standard name 

    ncalls tottime percall cumtime percall filename:lineno(function) 
     1 0.000 0.000 9.429 9.429 <string>:1(<module>) 
    1335000 2.259 0.000 2.259 0.000 pygame-test.py:32(update) 
    1335000 1.323 0.000 5.969 0.000 pygame-test.py:46(draw) 
     1 0.772 0.772 9.429 9.429 pygame-test.py:55(main_loop) 
     1 0.000 0.000 9.429 9.429 {built-in method exec} 
     267 0.020 0.000 0.020 0.000 {built-in method get} 
     1 0.237 0.237 0.237 0.237 {built-in method quit} 
    1335000 3.479 0.000 3.479 0.000 {built-in method rotate} 
     267 0.013 0.000 0.013 0.000 {built-in method set_caption} 
     267 0.067 0.000 0.067 0.000 {built-in method update} 
    1335267 1.257 0.000 1.257 0.000 {method 'blit' of 'pygame.Surface' objects} 
     1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects} 
     267 0.000 0.000 0.000 0.000 {method 'get_fps' of 'Clock' objects} 
     267 0.001 0.000 0.001 0.000 {method 'tick' of 'Clock' objects} 

Pyglet cProfile Ausgang: - Sehr lange ist dieser Teil der Ausgabe, voll Version here.

  9982775 function calls (9982587 primitive calls) in 10.066 seconds 

    Ordered by: standard name 

    ncalls tottime percall cumtime percall filename:lineno(function) 
     123 0.000 0.000 0.000 0.000 <frozen importlib._bootstrap>:1596(_handle_fromlist) 
     1 0.000 0.000 10.067 10.067 <string>:1(<module>) 
     11 0.000 0.000 0.000 0.000 __init__.py:1055(_ensure_string_data) 
     11 0.000 0.000 0.000 0.000 __init__.py:1061(_get_gl_format_and_type) 
     58 0.000 0.000 0.000 0.000 __init__.py:1140(clear) 
     75 0.000 0.000 0.012 0.000 __init__.py:1148(dispatch_event) 
     1 0.000 0.000 10.067 10.067 __init__.py:115(run) 
    ... 
     1 0.000 0.000 0.000 0.000 lib.py:124(decorate_function) 
    1108 0.005 0.000 0.005 0.000 lib_wgl.py:80(__call__) 
    285000 1.409 0.000 9.872 0.000 pyglet-test.py:29(update) 
     58 0.105 0.002 9.982 0.172 pyglet-test.py:49(update) 
    ... 
    855000 5.436 0.000 7.551 0.000 sprite.py:378(_update_position) 
    285000 0.172 0.000 2.718 0.000 sprite.py:441(_set_x) 
    851800 0.177 0.000 0.177 0.000 sprite.py:445(<lambda>) 
    285000 0.174 0.000 2.670 0.000 sprite.py:451(_set_y) 
    851115 0.155 0.000 0.155 0.000 sprite.py:455(<lambda>) 
    285000 0.182 0.000 2.692 0.000 sprite.py:461(_set_rotation) 
    285000 0.051 0.000 0.051 0.000 sprite.py:465(<lambda>) 
    ... 
    4299 0.007 0.000 0.025 0.000 vertexattribute.py:308(get_region) 
     1 0.000 0.000 0.000 0.000 vertexattribute.py:380(__init__) 
     116 0.000 0.000 0.000 0.000 vertexattribute.py:384(enable) 
     116 0.000 0.000 0.000 0.000 vertexattribute.py:387(set_pointer) 
     1 0.000 0.000 0.000 0.000 vertexattribute.py:461(__init__) 
     116 0.000 0.000 0.000 0.000 vertexattribute.py:466(enable) 
     116 0.000 0.000 0.000 0.000 vertexattribute.py:469(set_pointer) 
     1 0.000 0.000 0.000 0.000 vertexattribute.py:501(__init__) 
     116 0.000 0.000 0.000 0.000 vertexattribute.py:508(enable) 
     116 0.000 0.000 0.000 0.000 vertexattribute.py:511(set_pointer) 
     3 0.000 0.000 0.000 0.000 vertexbuffer.py:293(__init__) 
     348 0.000 0.000 0.001 0.000 vertexbuffer.py:311(bind) 
     348 0.000 0.000 0.001 0.000 vertexbuffer.py:314(unbind) 
     3 0.000 0.000 0.000 0.000 vertexbuffer.py:381(__init__) 
     348 0.001 0.000 0.004 0.000 vertexbuffer.py:388(bind) 
    4299 0.006 0.000 0.016 0.000 vertexbuffer.py:420(get_region) 
     3 0.000 0.000 0.000 0.000 vertexbuffer.py:424(resize) 
    4299 0.002 0.000 0.002 0.000 vertexbuffer.py:460(__init__) 
    855232 0.735 0.000 1.053 0.000 vertexbuffer.py:466(invalidate) 
    ... 
    855058 0.687 0.000 1.762 0.000 vertexdomain.py:581(_get_vertices) 
    ... 
    4300 0.002 0.000 0.002 0.000 {built-in method POINTER} 
    ... 
    841451 0.162 0.000 0.162 0.000 {built-in method cos} 
    ... 
2417/2415 0.000 0.000 0.000 0.000 {built-in method len} 
    855489 0.142 0.000 0.142 0.000 {built-in method max} 
    855469 0.176 0.000 0.176 0.000 {built-in method min} 
    465/407 0.000 0.000 0.000 0.000 {built-in method next} 
    ... 
    841451 0.072 0.000 0.072 0.000 {built-in method radians} 
     62 0.000 0.000 0.000 0.000 {built-in method setattr} 
    841451 0.120 0.000 0.120 0.000 {built-in method sin} 
    ... 
+0

Was ist 'Eingabe (...)' auf Pyglet? – ninMonkey

+0

Die Eingabe() in Standard-Python. 'foo = input ('Bitte geben Sie einen Wert ein:')' –

Antwort

2

Der Flaschenhals ist in Pyglet Sprite Rotation. Wenn Sie die 'self.rotation'-Zeile in der Square update() -Methode kommentieren, werden sich Ihre fps fast verdoppeln.

2

Pyglet-Bilder (und Sprites) können um einen beliebigen Anker herum gedreht werden. Wenn Sie sich pyglet/sprite.py ansehen, werden Sie sehen, dass dies mit dem Python-Mathematikmodul geschieht, weshalb es ziemlich langsam ist. Es scheint hier ein Optimierungsspielraum zu bestehen, indem Sprites mit OpenGL glRotate oder sogar einem Vertex-Shader gedreht werden.

+2

Ja, das ist auch meine Schlussfolgerung. Ich finde Standard-Pyglet/Sprite-Rendering viel zu wenig für den praktischen Gebrauch. Ich konnte eine Erhöhung der FPS um 100% erreichen, indem ich die Aufrufe von sprite._update_position verringerte. Sie sehen, dass es jedes Mal aufgerufen wird, wenn ein neues x oder y oder eine neue Rotation gesetzt wird; Es ist viel praktischer, es einmal direkt vor der draw() -Methode zu nennen. –

Verwandte Themen