Search code examples
pythongraphicspyglet

How to draw sprites using batch.draw() from pyglet library in Python


This might seem like a duplicate and maybe it is but I'm using windows 10 and sprite.py only has v2i in one place and changing it doesn't fix the issue. Maybe I'm using batch drawing wrong so I've provided the code. draw() is called from game object by on_draw() function.

class Island:
    def __init__(self):
        self.island = [[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
                       [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
                       [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
                       [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
                       [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
                       [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
                       [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
                       [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
                       [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
                       [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
                       [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
                       [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
                       [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
                       [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
                       [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],]
        self.tile_width = 30
        self.offsetx = 350
        self.offsety = 100
        self.batch = pyglet.graphics.Batch()
        self.water_tile = pyglet.image.load("path")
        self.grass_tile = pyglet.image.load("path")
        self.render_phase = True
    def render(self):
        for i in range(len(self.island)):
            for j in range(len(self.island[i])):
                if self.island[i][j] == 0:
                    x = j*self.tile_width - i*self.tile_width + self.offsetx
                    y = int((j*self.tile_width+i*self.tile_width)/2+self.offsety)
                    pyglet.sprite.Sprite(self.water_tile, x, y, batch=self.batch)
                elif self.island[i][j] == 1:
                    x = j * self.tile_width - i * self.tile_width + self.offsetx
                    y = int((j * self.tile_width + i * self.tile_width) / 2 + self.offsety)
                    pyglet.sprite.Sprite(self.grass_tile, x, y, batch=self.batch)
    def draw(self):
        if self.render_phase:
            self.render()
            self.render_phase = False
        else:
            self.batch.draw()

Solution

  • Problem is that you don't assign Sprites to global or class variable(s) so it probably removes Sprites (as local objects) when it ends render()

    def __init__(self):
    
        self.all_sprites = []
    
    def render(self):
    
        s = pyglet.sprite.Sprite(self.water_tile, x, y, batch=self.batch)
        self.sprites.append(s)
    

    Full example - try it with and without self.sprites.append(s)

    import pyglet
    
    class Island:
        def __init__(self):
            self.my_batch = pyglet.graphics.Batch()
            self.image = pyglet.image.load("image.jpg")
            self.all_sprites = []
            self.render()
    
        def render(self):
            for y in range(0, 100, 30):
                for x in range(0, 100, 30):
                    s = pyglet.sprite.Sprite(self.image, x, y, batch=self.my_batch)
                    self.all_sprites.append(s)  # <-- try without this line
    
        def draw(self):
            print('island.draw()')
            self.my_batch.draw()
    
    window = pyglet.window.Window()
    island = Island()
    
    @window.event()
    def on_draw():
        window.clear()
        island.draw()
    
    pyglet.app.run()