I tried to make a simple level with Pygame, which changes the background, when the player moves to a specific position (a simple level/scene change).
At startup, my first background is drawn correctly. When I change the background (move to the top left corner), the second background gets drawn correctly. But when I move to specific positions on my screen, behind the transparent sprite (set transparent with set_keycolor) not my second (correct) background is drawn, but the initial first one.
Do I heave to explicitly clear the background from the screen object? Do I have to delete the screen object, and create a complete new one?
program.py
#!/usr/bin/env python
import pygame
from player import Character
# see if we can load more than standard BMP
if not pygame.image.get_extended():
raise SystemExit("Sorry, extended image module required")
# globals
id = 1
# main
def main(winstyle=0):
# Initialize pygame
pygame.init()
SCREENRECT = pygame.Rect(0, 0, 630, 450)
winstyle = 0 # |FULLSCREEN
bestdepth = pygame.display.mode_ok(SCREENRECT.size, winstyle, 32)
screen = pygame.display.set_mode(SCREENRECT.size, winstyle, bestdepth)
BG_TILE_SIZE = 90
# decorate the game window
pygame.display.set_caption("Pygame TEST")
pygame.mouse.set_visible(0)
# create the background, tile the bgd image
background = pygame.Surface(SCREENRECT.size)
background.fill((0,0,255))
screen.blit(background, (0, 0))
pygame.display.flip()
# Initialize Game Groups
all = pygame.sprite.RenderUpdates()
# assign default groups to each sprite class
Character.containers = all
# Create Some Starting Values
clock = pygame.time.Clock()
# initialize our starting sprites
player = Character(SCREENRECT)
# Run our main loop whilst the player is alive.
while player.alive():
# get input
for event in pygame.event.get():
if event.type == pygame.QUIT:
return
if event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE:
return
# update all the sprites
all.update()
# handle player input
player.move(pygame.key.get_pressed(), SCREENRECT)
# change background
indexX, indexY = player.rect.center
if checkPlayerPosition(indexY, screen, background):
player.rect = player.image.get_rect(center=SCREENRECT.center)
# clear/erase the last drawn sprites
all.clear(screen, background)
# draw the scene
dirty = all.draw(screen)
pygame.display.update(dirty)
# cap the framerate at 60fps. Also called 60HZ or 60 times per second.
clock.tick(60)
pygame.time.wait(1000)
# change the background
def checkPlayerPosition(indexY, screen, background):
global id
if id == 1:
if indexY < 90:
screen.fill((0,0,0))
pygame.display.flip()
background.fill((0,0,255))
id = -1
return True
else:
if indexY > 360:
screen.fill((0,0,255))
pygame.display.flip()
background.fill((0,0,0))
id = 1
return True
return False
# call the "main" function if running this script
if __name__ == "__main__":
main()
pygame.quit()
Here's the code for my sprite.
player.py:
import os
import pygame
class Character(pygame.sprite.Sprite):
# fields
speed = 4
run = 1
images = []
# constructor
def __init__(self, SCREENRECT):
pygame.sprite.Sprite.__init__(self, self.containers)
self.setCharImages()
self.image = self.images[0]
self.rect = self.image.get_rect(center=SCREENRECT.center)
self.reloading = 0
self.origtop = self.rect.top
self.facing = -1
# sets the character image array
def setCharImages(self):
img = self.load_image("char.png")
img.set_colorkey((0,0,0))
self.images = [img,
pygame.transform.flip(img, 1, 1),
pygame.transform.rotate(img, 270),
pygame.transform.rotate(img, 90)]
# loads an image from disk
def load_image(self, file):
try:
MAIN_DIR = os.path.split(os.path.abspath(__file__))[0]
surface = pygame.image.load(os.path.join(MAIN_DIR, "img", file))
except pygame.error:
raise SystemExit('Could not load image "%s" %s' % (file, pygame.get_error()))
return surface.convert()
# move operation and animation
def move(self, keystate, SCREENRECT):
if keystate[pygame.K_LSHIFT]:
self.run = 2
else:
self.run = 1
movX = (keystate[pygame.K_RIGHT] - keystate[pygame.K_LEFT]) * self.speed * self.run
movY = (keystate[pygame.K_DOWN] - keystate[pygame.K_UP]) * self.speed * self.run
self.rect.move_ip(movX, movY)
self.rect = self.rect.clamp(SCREENRECT)
if movX < 0:
self.image = self.images[0]
elif movX > 0:
self.image = self.images[1]
if movY < 0:
self.image = self.images[2]
elif movY > 0:
self.image = self.images[3]
Here's the first level, when starting the game.
Here's the glitched version, after I change the level and the background gets black. As you can see, the transparent background of the sprite get's replaced with the first added background layer, not the second one.
So basicaly I'd say, when moving my sprite the wrong background get's redrawn, when it leaves it position. This only happens on the second screen as well! If I move back to the first one, I don't experience this glitch.
So basically the two lines in my short code example above are actually calling this function here. Maybe this causes the problem?!