pythonpygamepacman

How to make ghost in pacman move slower? Python


I'm writing pacman in pygame. I've got a problem with ghost moving. It is moving too fast. When it moves by speed 1, it is very fast. When the speed is 0.1, my code doesn't work.

Here is the ghost movement code:

#GHOST MOVE
move_list = ['right', 'left', 'up', 'down']
move_chise = random.choice(move_list)
if move_chise == 'right':
    while not sprite.spritecollide(ghost, walls, False):
        ghost.rect.x += speed
    ghost.rect.x -= 2
elif move_chise == 'left':
    while not sprite.spritecollide(ghost, walls, False):
        ghost.rect.x -= speed
    ghost.rect.x += 2
elif move_chise == 'up':
    while not sprite.spritecollide(ghost, walls, False):
        ghost.rect.y -= speed
    ghost.rect.y += 2
elif move_chise == 'down':
    while not sprite.spritecollide(ghost, walls, False):
        ghost.rect.y += speed
    ghost.rect.y -= 2

Here is my all code:

import random
from pygame import *

animCount = 0

class GameSprite(sprite.Sprite):
    def __init__(self, player_image, player_x, player_y, size_x, size_y, player_speed):
        super().__init__()
        self.image = transform.scale(image.load(player_image), (size_x, size_y))
        self.speed = player_speed
        self.rect = self.image.get_rect()
        self.rect.x = player_x
        self.rect.y = player_y
    def show(player):
        window.blit(player.image, (player.rect.x, player.rect.y))
class Hero(GameSprite):
    def update(player):
        print('fff')
class Enemy(GameSprite):
    def move(self):
        pass
class Wall(sprite.Sprite):
    def __init__(self, color1, color2, color3, wall_x, wall_y, wall_width, wall_height):
        super().__init__()
        self.color1 = color1
        self.color2 = color2
        self.color3 = color3
        self.width = wall_width
        self.height = wall_height
        self.image = Surface((self.width, self.height))
        self.image.fill((color1, color2, color3))
        self.rect = self.image.get_rect()
        self.rect.x = wall_x
        self.rect.y = wall_y
    def draw_wall(self):
        window.blit(self.image, (self.rect.x, self.rect.y))
class Coins_s(sprite.Sprite):
    def __init__(self, color1, color2, color3, wall_x, wall_y, wall_width, wall_height):
        super().__init__()
        self.color1 = color1
        self.color2 = color2
        self.color3 = color3
        self.width = wall_width
        self.height = wall_height
        self.image = Surface((self.width, self.height))
        self.image.fill((color1, color2, color3))
        self.rect = self.image.get_rect()
        self.rect.x = wall_x
        self.rect.y = wall_y
    def draw_wall(self):
        window.blit(self.image, (self.rect.x, self.rect.y))
coins = sprite.Group()

win_height = 700
win_width = 700
window = display.set_mode((win_width, win_height))
display.set_caption('Pacman Game')
clock = time.Clock()

back = transform.scale(image.load('photo_2022-06-05_21-28-54.jpg'), (700, 700))
player = Hero('photo_2022-06-05_20-54-50.jpg', 10, 309, 15, 15, 2)
ghost = Enemy('photo_2022-06-05_20-56-46.jpg', 350, 309, 20, 25, 2)

w1 = Wall(169,169,169, 0, 0, 700, 31)
w2 = Wall(169,169,169, 0, 20, 31, 210)
w3 = Wall(169,169,169, 0, 200, 145, 31)
w4 = Wall(169,169,169, 115, 200, 31, 95)
w5 = Wall(169,169,169, 0, 270, 145, 31)
w7 = Wall(169,169,169, 670, 20, 31, 210)
w8 = Wall(169,169,169, 556, 200, 145, 31)
w9 = Wall(169,169,169, 556, 200, 31, 95)
w10 = Wall(169,169,169, 556, 270, 150, 31)
w11 = Wall(169,169,169, 335, 0, 31, 95)
w12 = Wall(169,169,169, 187, 70, 110, 31)
w13 = Wall(169,169,169, 406, 70, 110, 31)
w14 = Wall(169,169,169, 187, 470, 110, 31)
w15 = Wall(169,169,169, 406, 470, 110, 31)
w16 = Wall(169,169,169, 190, 335, 31, 95)
w17 = Wall(169,169,169, 485, 335, 31, 95)
w18 = Wall(169,169,169, 0, 670, 700, 31)
w19 = Wall(169,169,169, 0, 400, 31, 280)
w20 = Wall(169,169,169, 0, 400, 145, 31)
w21 = Wall(169,169,169, 115, 340, 31, 70)
w22 = Wall(169,169,169, 0, 334, 145, 31)
w23 = Wall(169,169,169, 670, 400, 31, 280)
w24 = Wall(169,169,169, 556, 340, 31, 70)
w25 = Wall(169,169,169, 556, 334, 145, 31)
w26 = Wall(169,169,169, 556, 400, 150, 31)
w27 = Wall(169,169,169, 16, 531, 60, 31)
w28 = Wall(169,169,169, 624, 531, 60, 31)
w29 = Wall(169,169,169, 260, 340, 180, 31)
w30 = Wall(169,169,169, 260, 135, 180, 31)
w31 = Wall(169,169,169, 260, 531, 180, 31)
w32 = Wall(169,169,169, 260, 400, 180, 31)
w33 = Wall(169,169,169, 190, 135, 31, 160)
w34 = Wall(169,169,169, 335, 135, 31, 95)
w35 = Wall(169,169,169, 335, 405, 31, 95)
w36 = Wall(169,169,169, 335, 542, 31, 95)
w37 = Wall(169,169,169, 190, 535, 31, 95)
w38 = Wall(169,169,169, 485, 535, 31, 95)
w39 = Wall(169,169,169, 485, 135, 31, 160)
w40 = Wall(169,169,169, 75, 70, 70, 31)
w41 = Wall(169,169,169, 75, 133, 70, 31)
w42 = Wall(169,169,169, 555, 70, 70, 31)
w43 = Wall(169,169,169, 555, 133, 70, 31)
w44 = Wall(169,169,169, 555, 470, 70, 31)
w45 = Wall(169,169,169, 75, 470, 70, 31)
w46 = Wall(169,169,169, 115, 470, 31, 95)
w47 = Wall(169,169,169, 555, 470, 31, 95)
w48 = Wall(169,169,169, 75, 600, 220, 31)
w49 = Wall(169,169,169, 405, 600, 220, 31)
w50 = Wall(169,169,169, 215, 200, 85, 31)
w51 = Wall(169,169,169, 405, 200, 85, 31)
w52 = Wall(169,169,169, 260, 270, 30, 31)
w53 = Wall(169,169,169, 410, 270, 30, 31)
w54 = Wall(169,169,169, 260, 275, 31, 95)
w55 = Wall(169,169,169, 410, 275, 31, 95)

C1 = Coins_s(255,255,0, 130, 309, 5, 5)
C2 = Coins_s(255,255,0, 240, 309, 5, 5)
C3 = Coins_s(255,255,0, 340, 250, 5, 5)
C4 = Coins_s(255,255,0, 460, 309, 5, 5)
C5 = Coins_s(255,255,0, 570, 309, 5, 5)
C6 = Coins_s(255,255,0, 240, 180, 5, 5)
C7 = Coins_s(255,255,0, 460, 180, 5, 5)
C8 = Coins_s(255,255,0, 310, 111, 5, 5)
C9 = Coins_s(255,255,0, 390, 111, 5, 5)
C10 = Coins_s(255,255,0, 60, 180, 5, 5)
C11 = Coins_s(255,255,0, 640, 180, 5, 5)
C12 = Coins_s(255,255,0, 60, 50, 5, 5)
C13 = Coins_s(255,255,0, 640, 50, 5, 5)
C14 = Coins_s(255,255,0, 160, 409, 5, 5)
C15 = Coins_s(255,255,0, 240, 380, 5, 5)
C16 = Coins_s(255,255,0, 340, 380, 5, 5)
C17 = Coins_s(255,255,0, 460, 380, 5, 5)
C18 = Coins_s(255,255,0, 530, 409, 5, 5)
C19 = Coins_s(255,255,0, 460, 450, 5, 5)
C20 = Coins_s(255,255,0, 240, 450, 5, 5)
C21 = Coins_s(255,255,0, 390, 450, 5, 5)
C22 = Coins_s(255,255,0, 310, 450, 5, 5)
C23 = Coins_s(255,255,0, 630, 450, 5, 5)
C24 = Coins_s(255,255,0, 50, 450, 5, 5)
C25 = Coins_s(255,255,0, 600, 520, 5, 5)
C26 = Coins_s(255,255,0, 90, 520, 5, 5)
C27 = Coins_s(255,255,0, 530, 570, 5, 5)
C28 = Coins_s(255,255,0, 160, 570, 5, 5)
C29 = Coins_s(255,255,0, 60, 640, 5, 5)
C30 = Coins_s(255,255,0, 640, 640, 5, 5)
C31 = Coins_s(255,255,0, 350, 640, 5, 5)

coins.add(C1)
coins.add(C2)
coins.add(C3)
coins.add(C4)
coins.add(C5)
coins.add(C6)
coins.add(C7)
coins.add(C8)
coins.add(C9)
coins.add(C10)
coins.add(C11)
coins.add(C12)
coins.add(C13)
coins.add(C14)
coins.add(C15)
coins.add(C16)
coins.add(C17)
coins.add(C18)
coins.add(C19)
coins.add(C20)
coins.add(C21)
coins.add(C22)
coins.add(C23)
coins.add(C24)
coins.add(C25)
coins.add(C26)
coins.add(C27)
coins.add(C28)
coins.add(C29)
coins.add(C30)
coins.add(C31)

walls = [ w1, w2, w3, w4, w5, w7, w8, w9,
                w10, w11, w12, w13, w14, w15, w16, w17, w18, w19, w20, w21, w22, w23, w24,
                w25, w26, w27, w28, w29, w30, w31, w32, w33, w34, w35, w36, w37, w38, w39,
                w40, w41, w42, w43, w44, w45, w46, w47, w48, w49, w50, w51, w52, w53, w54,
                w55]

finish = False
game = True

coins_count = 0
count = 0
speed = 1

while game:
    for e in event.get():
            if e.type == QUIT:
                exit()
    #GHOST MOVE
    move_list = ['right', 'left', 'up', 'down']
    move_chise = random.choice(move_list)
    if move_chise == 'right':
        while not sprite.spritecollide(ghost, walls, False):
            ghost.rect.x += speed
        ghost.rect.x -= 2
    elif move_chise == 'left':
        while not sprite.spritecollide(ghost, walls, False):
            ghost.rect.x -= speed
        ghost.rect.x += 2
    elif move_chise == 'up':
        while not sprite.spritecollide(ghost, walls, False):
            ghost.rect.y -= speed
        ghost.rect.y += 2
    elif move_chise == 'down':
        while not sprite.spritecollide(ghost, walls, False):
            ghost.rect.y += speed
        ghost.rect.y -= 2
    #PACMAN MOVE
    side = 'None'
    keyPressed = key.get_pressed()
    if keyPressed[K_LEFT] and player.rect.x > 5:
        player.rect.x -= 2
        if sprite.spritecollide(player, walls, False):
            side = 'Right'
        if side == 'Right':
            print(side)
            player.rect.x += 2
    if keyPressed[K_RIGHT] and player.rect.x < win_width - 40:
        player.rect.x += player.speed
        if sprite.spritecollide(player, walls, False):
            side = 'Left'
        if side == 'Left':
            print(side)
            player.rect.x -= 2
    if keyPressed[K_UP] and player.rect.y > 5:
        player.rect.y -= player.speed
        if sprite.spritecollide(player, walls, False):
            side = 'Down'
        if side == 'Down':
            print(side)
            player.rect.y += 2
    if keyPressed[K_DOWN] and player.rect.y < win_height - 40:
        player.rect.y += player.speed
        if sprite.spritecollide(player, walls, False):
            side = 'Up'
        if side == 'Up':
            print(side)
            player.rect.y -= 2
    if player.rect.x == 660 and 300 < player.rect.y < 330:
            player.rect.x , player.rect.y = 10 ,308
    if sprite.spritecollide(player, coins, True):
        coins_count += 10
    if finish != True:
        window.fill((0, 0, 0))
        for w in walls:
            w.draw_wall()
        coins.draw(window)
        player.show()
        ghost.show()
        display.update()
        clock.tick(60)

Can you say what the problem is and how I can fix it?
This is how my game looks:

My game


Solution

  • Problem is that you use while to check collision - So, in every loop of while Game it repeats until it gets a collision. This changes the value ofthe variable but doesn't change the image on the screen.

    In every while game loop, you should check collision only once. And repeat it in next loops. So you should use if instead of while.

    But this needs also other changes. You need else: to move back when it detects a collision and it should also select a new direction.

    #GHOST MOVE
    move_list = ['right', 'left', 'up', 'down']
    move_chise = random.choice(move_list)  # first direction at start.
    
    while game:
        for e in event.get():
                if e.type == QUIT:
                    exit()
    
        if move_chise == 'right':
            if not sprite.spritecollide(ghost, walls, False):
                ghost.rect.x += speed
            else:
                ghost.rect.x -= 2
                move_chise = random.choice(move_list)
        elif move_chise == 'left':
            if not sprite.spritecollide(ghost, walls, False):
                ghost.rect.x -= speed
            else:
                ghost.rect.x += 2
                move_chise = random.choice(move_list)
        elif move_chise == 'up':
            if not sprite.spritecollide(ghost, walls, False):
                ghost.rect.y -= speed
            else:
                ghost.rect.y += 2
                move_chise = random.choice(move_list)
        elif move_chise == 'down':
            if not sprite.spritecollide(ghost, walls, False):
                ghost.rect.y += speed
            else:
                ghost.rect.y -= 2
                move_chise = random.choice(move_list)
    

    EDIT:

    Full working code.

    Instead images jpg I used Surface() filled with color red - This way everyone can simply copy and run it without images jpg.

    I also changed:

    import random
    from pygame import *
    
    class GameSprite(sprite.Sprite):
        def __init__(self, image, x, y, width, height, speed):
            super().__init__()
    
            #img = image.load(image)
            img = Surface((1000, 1000))
            img.fill((255,0,0))
                                   
            self.image = transform.scale(img, (width, height))
            
            self.speed = speed
            self.rect = self.image.get_rect()
            self.rect.x = x
            self.rect.y = y
            
        def draw(self, window):
            window.blit(self.image, self.rect)
            
    class Hero(GameSprite):
        def update(self):
            print('TODO: Update Hero')
            
        def move(self, keyPressed):
            side = None
            
            if keyPressed[K_LEFT] and self.rect.left > 5:
                self.rect.x -= self.speed
                if sprite.spritecollide(self, walls, False):
                    side = 'Right'
                    self.rect.x += 2
                    
            if keyPressed[K_RIGHT] and self.rect.right < win_width:
                self.rect.x += self.speed
                if sprite.spritecollide(player, walls, False):
                    side = 'Left'
                    self.rect.x -= 2
                    
            if keyPressed[K_UP] and self.rect.top > 5:
                self.rect.y -= self.speed
                if sprite.spritecollide(self, walls, False):
                    side = 'Down'
                    self.rect.y += 2
                    
            if keyPressed[K_DOWN] and self.rect.bottom < win_height:
                self.rect.y += self.speed
                if sprite.spritecollide(self, walls, False):
                    side = 'Up'
                    self.rect.y -= 2
    
            if side:
               print('Hero collision:', side)
                    
            if self.rect.right > win_width-10 and 300 < self.rect.top < 330:
                self.rect.left = 10 
    
            elif self.rect.left < 10 and 300 < self.rect.top < 330:
                self.rect.right = win_width-10
                    
    class Enemy(GameSprite):
    
        def __init__(self, image, x, y, width, height, speed):
            super().__init__(image, x, y, width, height, speed)
            
            self.move_list = ['right', 'left', 'up', 'down']
    
            self.direction = random.choice(self.move_list)
    
        def move(self):
            if self.direction == 'right':
                if not sprite.spritecollide(self, walls, False):
                    self.rect.x += speed
                else:
                    self.rect.x -= 2
                    self.direction = random.choice(self.move_list)
            elif self.direction == 'left':
                if not sprite.spritecollide(self, walls, False):
                    self.rect.x -= speed
                else:
                    self.rect.x += 2
                    self.direction = random.choice(self.move_list)
            elif self.direction == 'up':
                if not sprite.spritecollide(self, walls, False):
                    self.rect.y -= speed
                else:
                    self.rect.y += 2
                    self.direction = random.choice(self.move_list)
            elif self.direction == 'down':
                if not sprite.spritecollide(self, walls, False):
                    self.rect.y += speed
                else:
                    self.rect.y -= 2
                    self.direction = random.choice(self.move_list)
        
    class Wall(sprite.Sprite):
        def __init__(self, color, x, y, width, height):
            super().__init__()
    
            self.color = color
            self.width = width
            self.height = height
            
            self.image = Surface((self.width, self.height))
            self.image.fill(color)
            
            self.rect = self.image.get_rect()
            self.rect.x = x
            self.rect.y = y
            
        def draw(self, window):
            window.blit(self.image, self.rect)
    
    # it keeps single coin so name `Coin` without `s` seems better        
    class Coin(sprite.Sprite):
        def __init__(self, color, x, y, width, height):
            super().__init__()
            self.color = color
            self.width = width
            self.height = height
            
            self.image = Surface((self.width, self.height))
            self.image.fill(color)
            
            self.rect = self.image.get_rect()
            
            self.rect.x = x
            self.rect.y = y
            
        def draw(self, window):
            window.blit(self.image, self.rect)
            
    
    # --- main ---
    
    win_height = 700
    win_width = 700
    
    init()  # pygame.init()       
    
    window = display.set_mode((win_width, win_height))
    display.set_caption('Pacman Game')
    
    #back = transform.scale(image.load('photo_2022-06-05_21-28-54.jpg'), (700, 700))
    player = Hero('photo_2022-06-05_20-54-50.jpg', 10, 309, 15, 15, 2)
    player.image.fill((0,255,0))
    
    ghost_chise = Enemy('photo_2022-06-05_20-56-46.jpg', 350, 309, 20, 25, 2)
    ghost_chise.image.fill((0,255,255))
    ghost_other = Enemy('photo_2022-06-05_20-56-46.jpg', 350, 309, 20, 25, 2)
    ghost_other.image.fill((255,255,0))
    ghost_third = Enemy('photo_2022-06-05_20-56-46.jpg', 350, 309, 20, 25, 2)
    ghost_third.image.fill((255,0,255))
    
    walls = [
        Wall( (169,169,169), 0, 0, 700, 31), 
        Wall( (169,169,169), 0, 20, 31, 210), 
        Wall( (169,169,169), 0, 200, 145, 31), 
        Wall( (169,169,169), 115, 200, 31, 95), 
        Wall( (169,169,169), 0, 270, 145, 31), 
        Wall( (169,169,169), 670, 20, 31, 210), 
        Wall( (169,169,169), 556, 200, 145, 31), 
        Wall( (169,169,169), 556, 200, 31, 95), 
        Wall( (169,169,169), 556, 270, 150, 31), 
        Wall( (169,169,169), 335, 0, 31, 95), 
        Wall( (169,169,169), 187, 70, 110, 31), 
        Wall( (169,169,169), 406, 70, 110, 31), 
        Wall( (169,169,169), 187, 470, 110, 31), 
        Wall( (169,169,169), 406, 470, 110, 31), 
        Wall( (169,169,169), 190, 335, 31, 95), 
        Wall( (169,169,169), 485, 335, 31, 95), 
        Wall( (169,169,169), 0, 670, 700, 31), 
        Wall( (169,169,169), 0, 400, 31, 280), 
        Wall( (169,169,169), 0, 400, 145, 31), 
        Wall( (169,169,169), 115, 340, 31, 70), 
        Wall( (169,169,169), 0, 334, 145, 31), 
        Wall( (169,169,169), 670, 400, 31, 280), 
        Wall( (169,169,169), 556, 340, 31, 70), 
        Wall( (169,169,169), 556, 334, 145, 31), 
        Wall( (169,169,169), 556, 400, 150, 31), 
        Wall( (169,169,169), 16, 531, 60, 31), 
        Wall( (169,169,169), 624, 531, 60, 31), 
        Wall( (169,169,169), 260, 340, 180, 31), 
        Wall( (169,169,169), 260, 135, 180, 31), 
        Wall( (169,169,169), 260, 531, 180, 31), 
        Wall( (169,169,169), 260, 400, 180, 31), 
        Wall( (169,169,169), 190, 135, 31, 160), 
        Wall( (169,169,169), 335, 135, 31, 95), 
        Wall( (169,169,169), 335, 405, 31, 95), 
        Wall( (169,169,169), 335, 542, 31, 95), 
        Wall( (169,169,169), 190, 535, 31, 95), 
        Wall( (169,169,169), 485, 535, 31, 95), 
        Wall( (169,169,169), 485, 135, 31, 160), 
        Wall( (169,169,169), 75, 70, 70, 31), 
        Wall( (169,169,169), 75, 133, 70, 31), 
        Wall( (169,169,169), 555, 70, 70, 31), 
        Wall( (169,169,169), 555, 133, 70, 31), 
        Wall( (169,169,169), 555, 470, 70, 31), 
        Wall( (169,169,169), 75, 470, 70, 31), 
        Wall( (169,169,169), 115, 470, 31, 95), 
        Wall( (169,169,169), 555, 470, 31, 95), 
        Wall( (169,169,169), 75, 600, 220, 31), 
        Wall( (169,169,169), 405, 600, 220, 31), 
        Wall( (169,169,169), 215, 200, 85, 31), 
        Wall( (169,169,169), 405, 200, 85, 31), 
        Wall( (169,169,169), 260, 270, 30, 31), 
        Wall( (169,169,169), 410, 270, 30, 31), 
        Wall( (169,169,169), 260, 275, 31, 95), 
        Wall( (169,169,169), 410, 275, 31, 95), 
    ]
    
    coins = sprite.Group()
    
    coins.add([
        Coin( (255,255,0), 130, 309, 5, 5), 
        Coin( (255,255,0), 240, 309, 5, 5), 
        Coin( (255,255,0), 340, 250, 5, 5), 
        Coin( (255,255,0), 460, 309, 5, 5), 
        Coin( (255,255,0), 570, 309, 5, 5), 
        Coin( (255,255,0), 240, 180, 5, 5), 
        Coin( (255,255,0), 460, 180, 5, 5), 
        Coin( (255,255,0), 310, 111, 5, 5), 
        Coin( (255,255,0), 390, 111, 5, 5), 
        Coin( (255,255,0), 60, 180, 5, 5), 
        Coin( (255,255,0), 640, 180, 5, 5), 
        Coin( (255,255,0), 60, 50, 5, 5), 
        Coin( (255,255,0), 640, 50, 5, 5), 
        Coin( (255,255,0), 160, 409, 5, 5), 
        Coin( (255,255,0), 240, 380, 5, 5), 
        Coin( (255,255,0), 340, 380, 5, 5), 
        Coin( (255,255,0), 460, 380, 5, 5), 
        Coin( (255,255,0), 530, 409, 5, 5), 
        Coin( (255,255,0), 460, 450, 5, 5), 
        Coin( (255,255,0), 240, 450, 5, 5), 
        Coin( (255,255,0), 390, 450, 5, 5), 
        Coin( (255,255,0), 310, 450, 5, 5), 
        Coin( (255,255,0), 630, 450, 5, 5), 
        Coin( (255,255,0), 50, 450, 5, 5), 
        Coin( (255,255,0), 600, 520, 5, 5), 
        Coin( (255,255,0), 90, 520, 5, 5), 
        Coin( (255,255,0), 530, 570, 5, 5), 
        Coin( (255,255,0), 160, 570, 5, 5), 
        Coin( (255,255,0), 60, 640, 5, 5), 
        Coin( (255,255,0), 640, 640, 5, 5), 
        Coin( (255,255,0), 350, 640, 5, 5), 
    ])
    
    finish = False
    game = True
    
    coins_count = 0
    count = 0
    speed = 1
    
    clock = time.Clock()
    
    while game:
    
        for e in event.get():
            if e.type == QUIT:
                exit()
    
        # GHOSTS
        ghost_chise.move()
        ghost_other.move()            
        ghost_third.move()
        
        # PACMAN
        keyPressed = key.get_pressed()
        
        player.move(keyPressed)
    
        if sprite.spritecollide(player, coins, True):
            coins_count += 10
        
        # UPDATE SCREEN    
        if not finish:
            window.fill((0, 0, 0))
            
            for w in walls:
                w.draw(window)
                
            coins.draw(window)
            
            player.draw(window)
            
            ghost_chise.draw(window)
            ghost_other.draw(window)
            ghost_third.draw(window)
    
            display.update()
            clock.tick(60)
    
        if finish:
            game = False
    

    enter image description here