Search code examples
pythonpygamepygame-surface

I can't seem to properly blit surfaces onto screen


So here's my code, I am trying to understand how I can be able to display the surfaces I created onto the main screen which is SCREEN. I drew the maze onto another surface and then I blitted that surface onto the main screen. Then I blitted the PacMan surface onto the main screen, I am also trying to blit the background image onto the screen as well. My question is how do I blit them properly, like for example do I blit the maze first then the PacMan then the background, or what would be the correct order to blit them?

As for the PacManBite function, I am updating the PacManStartSurface to give it the effect that it is biting the dots, but then I also am updating the entire screen, is there a way to properly use the pygame.update() function because I think that's why the screen tends to flicker?

I also wanted to use SCREEN.fill(BLACK) so that it can get rid of any trails the PacMan leaves but for some reason I don't know where to place it in my main loop. Any help would be appreciated.

import pygame

pygame.init()
pygame.display.set_caption("Pac-Man")

# Sets the size of the screen via (WIDTH, HEIGHT)
SCREEN_WIDTH = 475
SCREEN_HEIGHT = 608
# Speed of Characters
SPEED = 1
# Frames per second, how fast the game runs
FPS = 50
# Colors (RED,GREEN,BLUE)
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
YELLOW = (255, 255, 0)
BLUE = (0, 0, 255)

HIGH_SCORE = 0

# Sets the WIDTH and HEIGHT of the window
WINDOW = (SCREEN_WIDTH, SCREEN_HEIGHT)
# Displays the screen
SCREEN = pygame.display.set_mode(WINDOW)
CLOCK = pygame.time.Clock()

PacManStartSurface = pygame.transform.scale(pygame.image.load 
                                           ("PacManStart.png").convert(), 
                                           (25, 25))
PacManStartRect = PacManStartSurface.get_rect(topleft = 
                                             (((SCREEN_WIDTH - 22) // 2),
                                             (SCREEN_HEIGHT + 225) // 2))

PacManSurface = pygame.transform.scale(pygame.image.load 
                                      ("PacManRight.png").convert(), (25, 25))
PacManRect = PacManStartSurface.get_rect(topleft = 
                                        (((SCREEN_WIDTH - 22) // 2),
                                        (SCREEN_HEIGHT + 225) // 2))

CurrentSurface = PacManStartSurface
CurrentRect = PacManStartRect

BackgroundSurface = pygame.image.load("Background.png").convert()

class PacMan():
    def __init__(self):
        self.LIVES = 3
        
class PowerUp(pygame.sprite.Sprite):
    def __init__(self):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.transform.scale(pygame.image.load("PowerUp.png")
                                            .convert(), (23, 23))
        self.mask = pygame.mask.from_surface(self.image)
        
class YellowGhost(pygame.sprite.Sprite):
    def __init__(self):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.transform.scale(pygame.image.load("YellowGhost.png")
                                           .convert(), (23, 23))
        self.rect = self.image.get_rect(topleft = (235, 347))
        self.mask = pygame.mask.from_surface(self.image)
        
class RedGhost(pygame.sprite.Sprite):
    def __init__(self):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.transform.scale(pygame.image.load("RedGhost.png")
                                           .convert(), (23, 23))
        self.rect = self.image.get_rect(topleft = (235, 347))
        self.mask = pygame.mask.from_surface(self.image)
        
class BlueGhost(pygame.sprite.Sprite):
    def __init__(self):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.transform.scale(pygame.image.load("BlueGhost.png")
                                           .convert(), (23, 23))
        self.rect = self.image.get_rect(topleft = (235, 347))
        self.mask = pygame.mask.from_surface(self.image)
        
class PinkGhost(pygame.sprite.Sprite):
    def __init__(self):        
        self.image = pygame.transform.scale(pygame.image.load("PinkGhost.png")
                                           .convert(), (23, 23))
        self.rect = self.image.get_rect(topleft = (235, 347))
        self.mask = pygame.mask.from_surface(self.image)
        
class Maze():
    def __init__(self):
        self.DOTS = []
        self.WALLS = []
        self.BLOCK_WIDTH = 22
        self.BLOCK_HEIGHT = 22
        self.MARGIN = 3
        # 0 - Dots
        # 1 - Walls
        # 2 - Power Up
        # 3 - Empty Space
        # 4 - Ghosts
        self.MATRIX = [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1], \
                      [1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1], \
                      [1,2,1,1,0,1,1,1,0,1,0,1,1,1,0,1,1,2,1], \
                      [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1], \
                      [1,0,1,1,0,1,0,1,1,1,1,1,0,1,0,1,1,0,1], \
                      [1,0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,1], \
                      [1,1,1,1,0,1,1,1,3,1,3,1,1,1,0,1,1,1,1], \
                      [3,3,3,1,0,1,3,3,3,3,3,3,3,1,0,1,3,3,3], \
                      [1,1,1,1,0,1,3,1,1,1,1,1,3,1,0,1,1,1,1], \
                      [0,0,0,0,0,3,3,1,4,4,4,1,3,3,0,0,0,0,0], \
                      [1,1,1,1,0,1,3,1,1,1,1,1,3,1,0,1,1,1,1], \
                      [3,3,3,1,0,1,3,3,3,3,3,3,3,1,0,1,3,3,3], \
                      [1,1,1,1,0,1,3,1,1,1,1,1,3,1,0,1,1,1,1], \
                      [1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1], \
                      [1,2,1,1,0,1,1,1,0,1,0,1,1,1,0,1,1,2,1], \
                      [1,0,0,1,0,0,0,0,0,3,0,0,0,0,0,1,0,0,1], \
                      [1,1,0,1,0,1,0,1,1,1,1,1,0,1,0,1,0,1,1], \
                      [1,0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,1], \
                      [1,0,1,1,1,1,1,1,0,1,0,1,1,1,1,1,1,0,1], \
                      [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1], \
                      [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]
        self.MAZE_HEIGHT = (self.MARGIN + self.BLOCK_HEIGHT) \
                           * len(self.MATRIX)
        self.MAZE_WIDTH = (self.MARGIN + self.BLOCK_WIDTH) \
                          * len(self.MATRIX[0])
        
    def DrawGrid(self, MazeSurface):
        for ROW in range(len(self.MATRIX)):
            for COLUMN in range(len(self.MATRIX[0])):
                if self.MATRIX[ROW][COLUMN] == 0:
                    self.DOTS.append(pygame.draw.circle(MazeSurface, YELLOW, 
                                    [((self.MARGIN + self.BLOCK_WIDTH)
                                    * COLUMN + self.MARGIN) + 9,
                                    ((self.MARGIN + self.BLOCK_HEIGHT) 
                                    * ROW + self.MARGIN) + 50], 2))
                if self.MATRIX[ROW][COLUMN] == 1:
                    self.WALLS.append(pygame.draw.rect(MazeSurface, WHITE,
                                     [((self.MARGIN + self.BLOCK_WIDTH)
                                     * COLUMN + self.MARGIN) - 2,
                                     ((self.MARGIN + self.BLOCK_HEIGHT) 
                                     * ROW + self.MARGIN) + 41, 
                                     self.BLOCK_WIDTH, self.BLOCK_HEIGHT]))
                    

class Main(Maze):
    def __init__(self):
        # Inherits Maze class
        Maze.__init__(self)
        self.DIRECTION = ""
        self.SCORE = 0
        
    def Movement(self):
        key = pygame.key.get_pressed()
        if key[pygame.K_LEFT] and not key[pygame.K_UP] \
                              and not key[pygame.K_DOWN]:
            self.DIRECTION = "LEFT"
        elif key[pygame.K_RIGHT] and not key[pygame.K_UP] \
                               and not key[pygame.K_DOWN]:
            self.DIRECTION = "RIGHT"
        elif key[pygame.K_UP] and not key[pygame.K_LEFT] \
                            and not key[pygame.K_RIGHT]:
            self.DIRECTION = "UP"
        elif key[pygame.K_DOWN] and not key[pygame.K_LEFT] \
                              and not key[pygame.K_RIGHT]:
            self.DIRECTION = "DOWN"
            
    def ContinueMovement(self):
        if self.DIRECTION == "LEFT":
            CurrentRect.x -= SPEED
            self.WallDetection(-1, 0, CurrentRect)
        if self.DIRECTION == "RIGHT":
            CurrentRect.x += SPEED
            self.WallDetection(1, 0, CurrentRect)
        if self.DIRECTION == "UP":
            CurrentRect.y -= SPEED
            self.WallDetection(0, -1, CurrentRect)
        if self.DIRECTION == "DOWN":
            CurrentRect.y += SPEED
            self.WallDetection(0, 1, CurrentRect)

    def ChangeImage(self):
        global CurrentSurface
        if self.DIRECTION == "LEFT":
            CurrentSurface = pygame.transform.rotate(PacManSurface, 180)
        if self.DIRECTION == "RIGHT":
            CurrentSurface = PacManSurface
        if self.DIRECTION == "UP":
            CurrentSurface = pygame.transform.rotate(PacManSurface, 90)
        if self.DIRECTION == "DOWN":
            CurrentSurface = pygame.transform.rotate(PacManSurface, 270)
        
    def Teleport(self):
        if CurrentRect.right < 0:
            CurrentRect.right = SCREEN_WIDTH + 20
        if CurrentRect.left > SCREEN_WIDTH:
            CurrentRect.right = 0
    
    def WallDetection(self, x, y, CurrentRect):
        CurrentRect.right += x
        for wall in self.WALLS:
            collide = CurrentRect.colliderect(wall)
            if collide:
                if x < 0: 
                    CurrentRect.left = wall.right
                elif x > 0:
                    CurrentRect.right = wall.left
                break
        
        CurrentRect.top += y
        for wall in self.WALLS:
            collide = CurrentRect.colliderect(wall)
            if collide:
                if y < 0:
                    CurrentRect.top = wall.bottom
                if y > 0:
                    CurrentRect.bottom = wall.top
                break
            
    def EatDots(self):
        for ROW in range(len(self.MATRIX)):
            for COLUMN in range(len(self.MATRIX[0])):
                for DOT in self.DOTS:
                    chomp = CurrentRect.colliderect(DOT)
                    if chomp:
                        self.DOTS.remove(DOT)
                        self.MATRIX[ROW][COLUMN] = 3
                        self.SCORE += 10
                        return str(self.SCORE)
                        
    def EatGhosts(self):
        pass
    
    def EatPowerUp(self):
        pass
                
    def ShowText(self):
        Font = pygame.font.Font("emulogic.ttf", 15)
        OneUpText = Font.render("1UP", True, WHITE)
        OneUpTextRect = OneUpText.get_rect(center = (70, 10))
        OneUpScoreText = Font.render("00", True, WHITE)
        UpdateScore = Main.EatDots(self)
        if int(self.SCORE) > 0:
            OneUpScoreText = Font.render(UpdateScore, True, WHITE)
        OneUpScoreRect = OneUpScoreText.get_rect(center =
                                                ((SCREEN_WIDTH - 290) 
                                                // 2, 26))
        HighScoreText = Font.render("High Score", True, WHITE)
        HighScoreTextRect = HighScoreText.get_rect(center = 
                                                  (SCREEN_WIDTH // 2, 10))
        HighScoreNumber = Font.render("00", True, WHITE)
        HighScoreNumberRect = HighScoreNumber.get_rect(center = 
                                                      ((SCREEN_WIDTH + 90) 
                                                       // 2, 26))
        
        SCREEN.blit(OneUpText, OneUpTextRect)
        SCREEN.blit(OneUpScoreText, OneUpScoreRect)
        SCREEN.blit(HighScoreText, HighScoreTextRect)
        SCREEN.blit(HighScoreNumber, HighScoreNumberRect)
        
    def PacManBite(self):
        SCREEN.blit(PacManStartSurface, PacManStartRect)
        pygame.display.update()
    
Player = Main()

BackgroundImage = pygame.transform.scale(BackgroundSurface, 
                                        (Player.MAZE_WIDTH, 
                                         Player.MAZE_HEIGHT))
BackgroundRect = BackgroundImage.get_rect(topleft = (0, 41))

MazeSurface = pygame.Surface((SCREEN_WIDTH, SCREEN_HEIGHT - 10))
MazeRect = MazeSurface.get_rect(topleft = ((SCREEN_WIDTH - 475, 
                                          SCREEN_HEIGHT - 608)))
Player.DrawGrid(MazeSurface)
    
'''
pregame = True
while pregame:
    if key button pressed:
        pregame = False
    run = True
'''

run = True
while run:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            run = False
        if event.type == pygame.KEYDOWN:
            Player.Movement()
            Player.ChangeImage()
            Player.Teleport()   
            
    Player.ContinueMovement()
    Player.PacManBite()
    
    SCREEN.blit(MazeSurface, MazeRect)  
    MazeSurface.blit(CurrentSurface, CurrentRect)
    #SCREEN.blit(BackgroundImage, BackgroundRect)
    Player.ShowText()
    pygame.display.update()
    CLOCK.tick(FPS)
            
pygame.quit()

Solution

  • You have to blit the CurrentSurface on the MazeSurface, before you blit the MazeSurface on the SCREEN:

    MazeSurface.blit(CurrentSurface, CurrentRect)
    SCREEN.blit(MazeSurface, MazeRect)