pythonsdlpysdl2

PySDL2 drawing order


The code below draws a black background, a white box and text. However it seems that the drawing order is not determined and I sometimes have the text or the rectangle covered by the background rectangle. I'm trying to understand what the appropriate way to manage this is?

import sdl2.ext
import sdl2.sdlttf
from sdl2 import SDL_Color, SDL_Init

WHITE = SDL_Color(255, 255, 255)

class Entity(sdl2.ext.Entity):
    def __init__(self, world, sprite, posx=0, posy=0):
        self.sprite = sprite
        self.sprite.position = posx, posy

sdl2.ext.init()

window = sdl2.ext.Window("PySDL2", size=(320, 240))
window.show()
world = sdl2.ext.World()

texture_renderer = sdl2.ext.Renderer(window)
spriterenderer = sdl2.ext.TextureSpriteRenderSystem(texture_renderer)
factory = sdl2.ext.SpriteFactory(sdl2.ext.TEXTURE, renderer=texture_renderer)

world.add_system(spriterenderer)

sdl2.sdlttf.TTF_Init()
font = sdl2.sdlttf.TTF_OpenFont('resources/Helvetica.dfont',32)
text_surface = sdl2.sdlttf.TTF_RenderText_Blended(font, 'test', WHITE).contents
sdl2.sdlttf.TTF_CloseFont(font)

bg = factory.from_color(sdl2.ext.Color(0, 0, 0), size = (320,240))
Entity(world, bg, 0, 0)

c = factory.from_color(sdl2.ext.Color(255, 255, 255), size = (50,50))
Entity(world, c, 100, 100)

text_sprite = factory.from_surface(text_surface)
text_entity = Entity(world, text_sprite, 50, 50)

def run():
    running = True
    while running:
        events = sdl2.ext.get_events()
        for event in events:
            if event.type == sdl2.SDL_QUIT:
                running = False
                break
        world.process()
run()
sdl2.ext.quit()

Solution

  • The default implementation of the TextureSpriteRenderSystem uses the depth attribute of Sprite object to determine the drawing order. If all sprites feature the same depth, the drawing order of them is undetermined, which results in your unwanted behaviour.

    A Sprite with a depth value of 0 will be drawn below (or prior to) a Sprite with a higher depth value, e.g. 10. The default depth for each Sprite being created is 0. You could set your background's and rectangle's depth to a negative value in order to enforce the drawing order:

    bg = factory.from_color(sdl2.ext.Color(0, 0, 0), size = (320,240))
    bg.depth = -99 # always below everything
    Entity(world, bg, 0, 0)
    
    c = factory.from_color(sdl2.ext.Color(255, 255, 255), size = (50,50))
    c.depth = -1
    Entity(world, c, 100, 100)
    

    You can read more about it in the PySDL2 sprite documentation.