pythonpygamepacman

How do I randomly move objects in a maze using pygame?


This is a code for Pac-Man. I already have a moving Pac-man and the collision w/ the ghosts, but I don't know how to make them randomly move on the map. I don't need them to chase the Pac-Man, just to slide randomly through the map and change direction when they hit on the wall. I also wanted to know how could I make Pac-Man die when he collides w/ a ghost.

import pygame

pygame.init()
tela = pygame.display.set_mode((1000, 560))
jogo = True


class Tabuleiro:
    def __init__(self, tela, x, y):
        self.x = x
        self.y = y
        self.tela = tela
        self.maze = [[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
                     [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1],
                     [1, 0, 1, 1, 0, 1, 3, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1],
                     [1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 3, 1],
                     [1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1],
                     [1, 0, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1],
                     [1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1],
                     [1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1],
                     [1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1],
                     [1, 0, 0, 0, 3, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1],
                     [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]]

    def show(self):
        for col in range(20):
            for lin in range(11):
                if self.maze[lin][col] == 1:
                    self.tela.fill((255, 255, 255), rect=[self.x + col * 50, self.y + lin * 50, 50, 50])
                if self.maze[lin][col] == 2:
                    self.tela.fill((255, 255, 0), rect=[self.x + col * 50 + 12, self.y + lin * 50 + 12, 25, 25])
                if self.maze[lin][col] == 3:
                    self.tela.fill((255, 0, 0), rect=[self.x + col * 50 + 12, self.y + lin * 50 + 12, 25, 25])

    def findFirst(self, number):
        for row, rowlist in enumerate(self.maze):
            for col, cell in enumerate(rowlist):
                if cell == number:
                    return row, col
        return None, None

    def testIndex(self, row, col):
        if row == None or col == None:
            return False
        if 0 <= row < len(self.maze) and 0 <= col < len(self.maze[row]):
            return True
        return False

    def isFieldEqual(self, row, col, number):
        if self.testIndex(row, col):
            return self.maze[row][col] == number
        return False

    def swapFileds(self, row1, col1, row2, col2):
        if self.testIndex(row1, col1) and self.testIndex(row2, col2):
            self.maze[row1][col1], self.maze[row2][col2] = self.maze[row2][col2], self.maze[row1][col1]


maze = Tabuleiro(tela, 10, 10)

while jogo:

    row, col = maze.findFirst(2)

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            jogo = False

        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_LEFT:
                if maze.isFieldEqual(row, col - 1, 0):
                    maze.swapFileds(row, col - 1, row, col)
            if event.key == pygame.K_RIGHT:
                if maze.isFieldEqual(row, col + 1, 0):
                    maze.swapFileds(row, col + 1, row, col)
            if event.key == pygame.K_UP:
                if maze.isFieldEqual(row - 1, col, 0):
                    maze.swapFileds(row, col, row - 1, col)
            if event.key == pygame.K_DOWN:
                if maze.isFieldEqual(row + 1, col, 0):
                    maze.swapFileds(row + 1, col, row, col)

    tela.fill(0)
    maze.show()
    pygame.display.update()

It's for a school project, so it doesn't have to be so complex. Thank you!


Solution

  • Add a method that can find all field with a specific number in the grid:

    class Tabuleiro:
        # [...]
    
        def findAll(self, number):
            result = []
            for row, rowlist in enumerate(self.maze):
                for col, cell in enumerate(rowlist):
                    if cell == number:
                        result.append((row, col))
            return result
    

    Find all the neighboring positions that can be move to. Use random.choice() to select a random position:

    while jogo:
        # [...]
    
        for row, col in maze.findAll(3):
            new_pos = [(row-1, col), (row+1, col), (row, col-1), (row, col+1)]
            new_pos = [(r, c) for r, c in new_pos if maze.isFieldEqual(r, c, 0)]
            if new_pos:
                new_row, new_col = random.choice(new_pos)
                maze.swapFileds(row, col, new_row, new_col)
    

    Use pygame.time.get_ticks() to return the number of milliseconds since pygame.init() was called. Set the time for the first move of the enemy. When the time exceeds move the enemy and set the time for the next move:

    next_move_time = 0
    jogo = True
    while jogo:
        current_time = pygame.time.get_ticks()
    
        # [...]
    
        if next_move_time < current_time:
            next_move_time = current_time + 500 # 500 milliseconds = 0.5 seconds
            for row, col in maze.findAll(3):
                # [...]
    

    Complete example:

    import pygame
    import random
    pygame.init()
    tela = pygame.display.set_mode((1000, 560))
    
    class Tabuleiro:
        def __init__(self, tela, x, y):
            self.x = x
            self.y = y
            self.tela = tela
            self.maze = [[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
                         [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1],
                         [1, 0, 1, 1, 0, 1, 3, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1],
                         [1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 3, 1],
                         [1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1],
                         [1, 0, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1],
                         [1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1],
                         [1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1],
                         [1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1],
                         [1, 0, 0, 0, 3, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1],
                         [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]]
    
        def show(self):
            for col in range(20):
                for lin in range(11):
                    if self.maze[lin][col] == 1:
                        self.tela.fill((255, 255, 255), rect=[self.x + col * 50, self.y + lin * 50, 50, 50])
                    if self.maze[lin][col] == 2:
                        self.tela.fill((255, 255, 0), rect=[self.x + col * 50 + 12, self.y + lin * 50 + 12, 25, 25])
                    if self.maze[lin][col] == 3:
                        self.tela.fill((255, 0, 0), rect=[self.x + col * 50 + 12, self.y + lin * 50 + 12, 25, 25])
    
        def findFirst(self, number):
            for row, rowlist in enumerate(self.maze):
                for col, cell in enumerate(rowlist):
                    if cell == number:
                        return row, col
            return None, None
    
        def findAll(self, number):
            result = []
            for row, rowlist in enumerate(self.maze):
                for col, cell in enumerate(rowlist):
                    if cell == number:
                        result.append((row, col))
            return result
    
        def testIndex(self, row, col):
            if row == None or col == None:
                return False
            if 0 <= row < len(self.maze) and 0 <= col < len(self.maze[row]):
                return True
            return False
    
        def isFieldEqual(self, row, col, number):
            if self.testIndex(row, col):
                return self.maze[row][col] == number
            return False 
        
        def swapFileds(self, row1, col1, row2, col2):
            if self.testIndex(row1, col1) and self.testIndex(row2, col2):
                self.maze[row1][col1], self.maze[row2][col2] = self.maze[row2][col2], self.maze[row1][col1]
    
    
    maze = Tabuleiro(tela, 10, 10)
    
    next_move_time = 0
    jogo = True
    while jogo:
        current_time = pygame.time.get_ticks()
        row, col = maze.findFirst(2)
    
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                jogo = False
    
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_LEFT:
                    if maze.isFieldEqual(row, col-1, 0):
                        maze.swapFileds(row, col-1, row, col)
                if event.key == pygame.K_RIGHT:
                    if maze.isFieldEqual(row, col+1, 0):
                        maze.swapFileds(row, col+1, row, col)
                if event.key == pygame.K_UP:
                    if maze.isFieldEqual(row-1, col, 0):
                        maze.swapFileds(row, col, row-1, col)
                if event.key == pygame.K_DOWN:
                    if maze.isFieldEqual(row+1, col, 0):
                        maze.swapFileds(row+1, col, row, col)
    
        if next_move_time < current_time:
            next_move_time = current_time + 500 # 500 milliseconds = 0.5 seconds
            for row, col in maze.findAll(3):
                new_pos = [(row-1, col), (row+1, col), (row, col-1), (row, col+1)]
                new_pos = [(r, c) for r, c in new_pos if maze.isFieldEqual(r, c, 0)]
                if new_pos:
                    new_row, new_col = random.choice(new_pos)
                    maze.swapFileds(row, col, new_row, new_col)
    
    
        tela.fill(0)
        maze.show()
        pygame.display.update()