2

I'm learning the basics of the pygame library and already struggling. The "game" at this point only has a player and walls. There are 2 main surfaces: "world" (the actual game map) and "screen" (which serves as a viewport for "view_src" w/ scaling & scrolling, "viewport" is the corresponding rect).

Here's the problem: I want to implement at least basic optimisation and only render sprites that are actually visible, so I'm filtering the "all" group to whatever collides with the viewport. That acts as expected. But when I call the rendering functions on the "visible" ad hoc group I get artifacts whereas calling them on "all" works just fine.

Here's the relevant snippet from the game loop:

        # clear old sprites
        all.clear(world, background) # this should clear the OLD position of all sprites, right?


        # handle input and generic game logic here
        if player.move(key_state, walls) != (0,0): # moves the player's rect if possible
            scroll_view(world, player.last_move, view_src) # shifts view_src if applicable


        # this does very little and should be unrelated to the issue
        all.update()


        # draw the new scene
        visible = pg.sprite.Group([ spr for spr in all.sprites() if view_src.colliderect(spr.rect) ])
        print(visible.sprites()) # confirms the visible sprites are chosen correctly
        visible.draw(world) # results in drawing each sprite in its new AND old position
        #all.draw(world) # acts as it should if used instead

        scaled = pg.transform.scale(world.subsurface(view_src), viewport.size)
        screen.blit(scaled, viewport.topleft)
        pg.display.flip()

(I do .empty() the "visible" group at the end of the loop)

Even if I determine "visible" earlier and call visible.clear(world, background) and then go all.draw(world) I get the exact same issue, it only works if both .clear() and .draw() are called on "all". This is already after consulting an AI which told me this works just fine so hopefully a good old fashioned human can point me in the right direction.

4
  • What do the artifacts look like? Can you add a screenshot? Commented Jan 4 at 16:06
  • @halfer It looked like the old position of a sprite was never cleared so each sprite would be drawn in every position it's ever been in on the screen surface. Can't screenshot it because I've completely changed the rendering logic since then and it doesn't happen anymore, but I'm still curious why this happened to begin with. Commented Jan 4 at 21:52
  • Are you repainting the background? Clearing the window? Sprites don't "erase" themselves. Commented Jan 7 at 6:04
  • @Kingsley That's what Group.clear() is for. But now that I re-read its docs very carefully it says it clears sprites used in the last .draw() call so it won't work on a different group and the reason it doesn't work when both of those Groups are the custom one is that it's re-assigned in each iteration of the game loop. I think that's it! Commented Jan 8 at 15:43

1 Answer 1

0

Found the problem and the fix thanks to Kingsley's nudge.

The issue:

Group.clear() clears the sprites drawn by the last .draw() of that exact same group. So using a different group for .clear() and .draw() doesn't work, and the continuity it needs to function is also lost by re-assigning the "visible" group each time.

The solution:

Initialise "visible" before the loop, persist it between iterations and add/remove sprites as needed.

Fixed code:

        # clear old sprites
        visible.clear(world, background) # clears sprites from the last .draw()

        # handle input and generic game logic here
        if player.move(key_state, walls) != (0,0):
            scroll_view(world, player, view_src)

        # "step event", update positions etc here
        all.update()

        # draw the new scene
        visible.empty()
        visible.add([ spr for spr in all if view_src.colliderect(spr.rect) ])
        visible.draw(world)
        render_view(screen, world, view_src, viewport) # this is still what it was before
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.