Pyglet Image Design

I am working on a kind of 2D Minecraft clone for my first Pyglet project in depth, and I ran into a problem. Whenever I have a decent amount of blocks on the screen, the frame rate drops sharply.

Here is my rendering method: I use a dictionary with the key being a tuple (which represents the coordinate for the block), and the element is a texture.

I go through the entire dictionary and put out each block:

for key in self.blocks:
    self.blocks[key].blit(key[0] * 40 + sx,key[1] * 40+ sy)

PS sx and sy are coordinate offsets for scrolling the screen.

I would like to know if there is a way to render each block more efficiently.

+4
source share
1 answer

, , , , .

, - :

self.blocks['monster001'] = pyglet.image.load('./roar.png')

, , . , , , .

, . , , .

sprite = pyglet.sprite.Sprite(pyglet.image.load('./roar.png'))
sprite.draw() # This is instead of blit. Position is done via sprite.x = ...

, , , .blit() , , .

, ( .. duh).

, pew pew .
, LOT (: ) , . , , /.

. "".
, , , :

main_batch = pyglet.graphics.Batch()
background = pyglet.graphics.OrderedGroup(0)
# stuff_above_background = pyglet.graphics.OrderedGroup(1)
# ...

, , , .
, , ? , , ( , , , ...)

, , ? , , , , .. single... time.. monster_image, .

monster_image = pyglet.image.load('./roar.png')
for i in range(100): # We'll create 100 test monsters
    self.blocks['monster'+str(i)] = pyglet.sprite.Sprite(imgage=monster_image, x=0, y=0, batch=main_batch, group=background)

100, main_batch background. .

, self.blocks[key].blit() .draw(), main_batch.draw(), .

, , , . . , , - . , , , , , .

, , , baseSprite.
, Pyglet, , Sprite, image, , self.texture , , pyglet: D pew pew hehe.

class baseSprite(pyglet.sprite.Sprite):
    def __init__(self, texture, x, y, batch, subgroup):
        self.texture = texture

        super(baseSprite, self).__init__(self.texture, batch=batch, group=subgroup)
        self.x = x
        self.y = y

    def move(self, x, y):
        """ This function is just to show you
            how you could improve your base class
            even further """
        self.x += x
        self.y += y

    def _draw(self):
        """
        Normally we call _draw() instead of .draw() on sprites
        because _draw() will contains so much more than simply
        drawing the object, it might check for interactions or
        update inline data (and most likely positioning objects).
        """
        self.draw()

, , , :

main_batch = pyglet.graphics.Batch()
background = pyglet.graphics.OrderedGroup(0)
monster_image = pyglet.image.load('./roar.png')
self.blocks['monster001'] = baseSprite(monster_image, 10, 50, main_batch, background)
self.blocks['monster002'] = baseSprite(monster_image, 70, 20, main_batch, background)

...
main_batch.draw()

, , @on_window_draw() , , , , . - . ?
, , , . RCTYLTWADL .

class, Pyglet , sh ** , . .
, main, , , , , Pyglet.

class main(pyglet.window.Window):
    def __init__ (self):
        super(main, self).__init__(800, 800, fullscreen = False)
        self.x, self.y = 0, 0
        self.sprites = {}
        self.batches = {}
        self.subgroups = {}

        self.alive = 1

    def on_draw(self):
        self.render()

    def on_close(self):
        self.alive = 0

    def render(self):
        self.clear()

        for batch_name, batch in self.batches.items():
            batch.draw()

        for sprite_name, sprite in self.sprites.items():
            sprite._draw()

        self.flip() # This updates the screen, very much important.

    def run(self):
        while self.alive == 1:
            self.render()

            # -----------> This is key <----------
            # This is what replaces pyglet.app.run()
            # but is required for the GUI to not freeze.
            # Basically it flushes the event pool that otherwise
            # fill up and block the buffers and hangs stuff.
            event = self.dispatch_events()

x = main()
x.run()

- main, , , self.sprites self.batches.

! ._draw() , ? , , draw(), .

Anywho, .

  • , .
  • , GPU , .
  • , mojo .

:

import pyglet
from pyglet.gl import *

glEnable(GL_BLEND)
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
glEnable(GL_LINE_SMOOTH)
glHint(GL_LINE_SMOOTH_HINT, GL_DONT_CARE)

pyglet.clock.set_fps_limit(60)

class baseSprite(pyglet.sprite.Sprite):
    def __init__(self, texture, x, y, batch, subgroup):
        self.texture = texture

        super(baseSprite, self).__init__(self.texture, batch=batch, group=subgroup)
        self.x = x
        self.y = y

    def move(self, x, y):
        """ This function is just to show you
            how you could improve your base class
            even further """
        self.x += x
        self.y += y

    def _draw(self):
        """
        Normally we call _draw() instead of .draw() on sprites
        because _draw() will contains so much more than simply
        drawing the object, it might check for interactions or
        update inline data (and most likely positioning objects).
        """
        self.draw()

class main(pyglet.window.Window):
    def __init__ (self):
        super(main, self).__init__(800, 800, fullscreen = False)
        self.x, self.y = 0, 0
        self.sprites = {}
        self.batches = {}
        self.subgroups = {}

        self._handles = {}

        self.batches['main'] = pyglet.graphics.Batch()
        self.subgroups['base'] = pyglet.graphics.OrderedGroup(0)

        monster_image = pyglet.image.load('./roar.png')
        for i in range(100):
            self._handles['monster'+str(i)] = baseSprite(monster_image, randint(0, 50), randint(0, 50), self.batches['main'], self.subgroups['base'])

        # Note: We put the sprites in `_handles` because they will be rendered via
        # the `self.batches['main']` batch, and placing them in `self.sprites` will render
        # them twice. But we need to keep the handle so we can use `.move` and stuff
        # on the items later on in the game making process ;)

        self.alive = 1

    def on_draw(self):
        self.render()

    def on_close(self):
        self.alive = 0

    def render(self):
        self.clear()

        for batch_name, batch in self.batches.items():
            batch.draw()

        for sprite_name, sprite in self.sprites.items():
            sprite._draw()

        self.flip() # This updates the screen, very much important.

    def run(self):
        while self.alive == 1:
            self.render()

            # -----------> This is key <----------
            # This is what replaces pyglet.app.run()
            # but is required for the GUI to not freeze.
            # Basically it flushes the event pool that otherwise
            # fill up and block the buffers and hangs stuff.
            event = self.dispatch_events()

            # Fun fact:
            #   If you want to limit your FPS, this is where you do it
            #   For a good example check out this SO link:
            #   http://stackoverflow.com/questions/16548833/pyglet-not-running-properly-on-amd-hd4250/16548990#16548990

x = main()
x.run()

, GL, . sa FPS-, .

Edit:

, , . , , .

, .
, , . , .

, ( ) , :

global_settings = {'player position' : (50, 50)}
# The player is at X cord 50 and Y cord 50.

:

class baseSprite(pyglet.sprite.Sprite):
    def __init__(self, texture, x, y, batch, subgroup):
        self.texture = texture

        super(baseSprite, self).__init__(self.texture, batch=batch, group=subgroup)
        self.x = x + global_settings['player position'][0]#X
        self.y = y + global_settings['player position'][1]#Y

, draw() (, _draw(), draw, _draw), , , baseSprite :

class monster(baseSprite):
    def __init__(self, monster_image, main_batch, background):
        super(monster, self).__init__(imgage=monster_image, x=0, y=0, batch=main_batch, group=background)
    def update(self):
        self.x = x + global_settings['player position'][0]#X
        self.y = y + global_settings['player position'][1]#Y

, , .update() monster /.
, - , - , , .



( , GUI- Pyglet), - * Nix X-.. .

, , , , Pyglet. , , , , , , ^^

Pew pew lazors , !

+4

Source: https://habr.com/ru/post/1624713/


All Articles