In your code flow, you are drawing the "Pause" text immediately when the player presses
p. Later on in the same frame, you draw the other sprites. Pygame
blit operations always draw on top of what has already been drawn.
If you want the pause text to appear above everything else in the game environment, you'll have to move the code that blits it to a point after everything else is blitted. Also, you'll want to draw it every frame.
Some code snippets might look like the following:
# Declare a boolean to track pause state.
paused = False
# Some other game code...
elif event.type == KEYDOWN:
if event.key == K_p:
if not paused:
paused = not paused
# Some more game code...
# Blit the rest of the game world to the background.
# Draw the pause text on top of everything else.
# Some other pause code...
I noticed that you tried to throw the game into a second loop while it's paused to limit what's executed. Personally, I don't recommend this pattern, but if you'd like to stick with it I think that you'd just need to add a
pygame.display.flip() to that loop and pull the blitting of the pause text out of the conditional for unpausing:
if event.type == KEYDOWN and event.key == K_p:
pause = False
screen.blit(self.background, self.pause_text.rect, self.pause_text.rect)
It doesn't make any sense to re-blit the pause text when the player unpauses the game.