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:
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:
rect.bottom
, rect.top
instead of rect.y
and rect.left
, rect.right
instead of rect.x
.blit()
I use player.rect
instead of (player.rect.x, player.rect.y)
.Player.move()
and Enemy.move()
.draw(window)
instead of draw()
, show()
or draw_wall()
.x,y,width,height
instead of player_x
, wall_x
, etc.(R,G,B)
instead of separated values color1, color2, color3
.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