2

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!

Marina
  • 81
  • 3
  • Please repeat [on topic](https://stackoverflow.com/help/on-topic) and [how to ask](https://stackoverflow.com/help/how-to-ask) from the [intro tour](https://stackoverflow.com/tour). “Show me how to solve this coding problem” is not a Stack Overflow issue. We expect you to make an honest attempt, and *then* ask a *specific* question about your algorithm or technique. Stack Overflow is not intended to replace existing documentation and tutorials. – Prune Dec 07 '20 at 21:42
  • There's a really great analysis of Pac-man's ghost movements: https://gameinternals.com/understanding-pac-man-ghost-behavior – Kingsley Dec 07 '20 at 21:51

1 Answers1

2

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()
Rabbid76
  • 202,892
  • 27
  • 131
  • 174