ساخت بازی Pacman با Python و Pygame

پروژه‌های بازی‌سازی پایتون

این مطلب از سایت tool.hamidvalad.ir گرفته شده است

معرفی

بازی Pacman یکی از محبوب‌ترین و ماندگارترین بازی‌های تاریخ صنعت گیم است که در سال 1980 توسط شرکت نامکو منتشر شد. در این آموزش، نحوه پیاده‌سازی این بازی کلاسیک را با استفاده از زبان پایتون و کتابخانه Pygame آموزش می‌دهیم. پروژه شامل تمام عناصر اصلی بازی از جمله پک‌من، چهار روح با الگوهای حرکتی مختلف، دیوارها، نقاط خوردنی، سیستم امتیازدهی و موسیقی زمینه است.

این پروژه آموزشی برای افرادی مناسب است که با پایتون آشنایی اولیه دارند و می‌خواهند وارد دنیای بازی‌سازی شوند. کد ارائه شده کاملاً عملیاتی و قابل اجراست و می‌تواند به عنوان پایه‌ای برای پروژه‌های پیچیده‌تر مورد استفاده قرار گیرد.

📌 نکته مهم درباره تصاویر بازی:

برای اجرای صحیح این بازی، نیاز به فایل‌های تصویری زیر دارید که باید در پوشه images قرار بگیرند:

  • Trollman.png - تصویر پک‌من (شخصیت اصلی)
  • Blinky.png - تصویر روح قرمز (Blinky)
  • Pinky.png - تصویر روح صورتی (Pinky)
  • Inky.png - تصویر روح آبی (Inky)
  • Clyde.png - تصویر روح نارنجی (Clyde)

ساختار پوشه‌ها باید به این شکل باشد:

📁 پروژه شما/
├── 📄 pacman.py
├── 📄 pacman.mp3
└── 📁 images/
    ├── Trollman.png
    ├── Blinky.png
    ├── Pinky.png
    ├── Inky.png
    └── Clyde.png

نصب و پیش‌نیازها

قبل از شروع کدنویسی، نیاز دارید که محیط توسعه پایتون و کتابخانه‌های لازم را نصب کنید.

مراحل نصب:

  1. نصب پایتون: از سایت python.org آخرین نسخه پایتون (3.8 یا بالاتر) را دانلود و نصب کنید.
  2. نصب Pygame: در خط فرمان دستور زیر را اجرا کنید:
    pip install pygame
  3. ایجاد پوشه پروژه:
    mkdir pacman-game
    cd pacman-game
    mkdir images
  4. تهیه فایل‌های تصویری: تصاویر مورد نیاز را دانلود یا ایجاد کنید و در پوشه images قرار دهید.

ویژگی‌های تصاویر مورد نیاز:

  • فرمت: PNG (به دلیل پشتیبانی از transparency)
  • اندازه: 32x32 پیکسل برای هر کاراکتر
  • پس‌زمینه: شفاف (transparent)
  • نام‌گذاری: دقیقاً مطابق نام‌های ذکر شده

نمونه کد برای ایجاد تصاویر ساده (اگر فایل تصویری ندارید):

# ایجاد پک‌من ساده با شکل دایره
import pygame
pygame.init()
surface = pygame.Surface((32, 32), pygame.SRCALPHA)
pygame.draw.circle(surface, (255, 255, 0), (16, 16), 14)  # رنگ زرد
pygame.draw.polygon(surface, (0, 0, 0), [(16,16), (32,8), (32,24)])  # دهان
pygame.image.save(surface, 'images/Trollman.png')

تصاویر بازی Pacman

در این بخش تصاویر اصلی بازی را مشاهده می‌کنید. این تصاویر با اندازه 32x32 پیکسل طراحی شده‌اند و برای اجرای بازی ضروری هستند.

تصاویر شخصیت‌های بازی:

پک‌من (Pacman)

پک‌من بازی Pacman

تصویر اصلی پک‌من که شخصیت بازی است

Trollman (آیکون بازی)

آیکون بازی Pacman

آیکون بازی که در نوار عنوان نمایش داده می‌شود

Blinky (روح قرمز)

روح قرمز Blinky

روح قرمز رنگ که سریع‌ترین روح است

Pinky (روح صورتی)

روح صورتی Pinky

روح صورتی رنگ که سعی می‌کند پک‌من را از جلو ببندد

Inky (روح آبی)

روح آبی Inky

روح آبی رنگ که غیرقابل پیش‌بینی حرکت می‌کند

Clyde (روح نارنجی)

روح نارنجی Clyde

روح نارنجی رنگ که الگوی حرکتی خاص خود را دارد

بارگذاری تصاویر در کد:

تصاویر بازی در بخش‌های مختلف کد بارگذاری می‌شوند:

# بارگذاری آیکون پنجره بازی
Trollicon = pygame.image.load('images/Trollman.png')
pygame.display.set_icon(Trollicon)

# ایجاد پک‌من با تصویر
Pacman = Player(w, p_h, "images/Trollman.png")

# ایجاد روح‌ها با تصاویر مربوطه
Blinky = Ghost(w, b_h, "images/Blinky.png")
Pinky = Ghost(w, m_h, "images/Pinky.png")
Inky = Ghost(i_w, m_h, "images/Inky.png")
Clyde = Ghost(c_w, m_h, "images/Clyde.png")

کلاس Player (بارگذاری تصویر):

class Player(pygame.sprite.Sprite):
    def __init__(self, x, y, filename):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.image.load(filename).convert()
        self.rect = self.image.get_rect()
        self.rect.top = y
        self.rect.left = x

راهنمای عیب‌یابی مشکلات تصویری:

مشکل 1: خطای "Couldn't open images/Trollman.png"

راه حل:

  • مطمئن شوید پوشه images در کنار فایل پایتون وجود دارد
  • نام فایل دقیقاً Trollman.png باشد (حساس به حروف بزرگ و کوچک)
  • مسیر فایل‌ها را بررسی کنید

مشکل 2: تصاویر با پس‌زمینه سفید نمایش داده می‌شوند

راه حل: از تصاویر با فرمت PNG و پس‌زمینه شفاف استفاده کنید.

مشکل 3: اندازه تصاویر نامناسب است

راه حل: اندازه تصاویر را به 32x32 پیکسل تغییر دهید یا کد را برای پذیرش اندازه‌های مختلف تغییر دهید.

کدنویسی پروژه

در این بخش به توضیح بخش‌های مهم کد بازی می‌پردازیم.

ساختار کلی پروژه:

  • کلاس Wall: برای ایجاد دیوارهای آبی بازی
  • کلاس Block: برای ایجاد نقاط زرد خوردنی
  • کلاس Player: کلاس اصلی پک‌من
  • کلاس Ghost: کلاس روح‌ها که از Player ارث‌بری می‌کند
  • توابع کمکی: setupRoomOne, setupGate, startGame, doNext

الگوهای حرکتی روح‌ها:

هر روح الگوی حرکتی خاص خود را دارد که در لیست‌های زیر تعریف شده است:

Pinky_directions = [
    [0, -30, 4],   # حرکت به بالا به مدت 4 فریم
    [15, 0, 9],    # حرکت به راست به مدت 9 فریم
    [0, 15, 11],   # حرکت به پایین به مدت 11 فریم
    # ...
]

Blinky_directions = [
    [0, -15, 4],
    [15, 0, 9],
    [0, 15, 11],
    # ...
]

# و به همین صورت برای Inky و Clyde

سیستم تشخیص برخورد:

برخوردها در دو مرحله بررسی می‌شوند:

def update(self, walls, gate):
    # حرکت افقی
    x_collide = pygame.sprite.spritecollide(self, walls, False)
    if x_collide:
        self.rect.left = old_x
    
    # حرکت عمودی
    y_collide = pygame.sprite.spritecollide(self, walls, False)
    if y_collide:
        self.rect.top = old_y

سیستم امتیازدهی:

# بررسی برخورد پک‌من با نقاط خوردنی
blocks_hit_list = pygame.sprite.spritecollide(Pacman, block_list, True)
if len(blocks_hit_list) > 0:
    score += len(blocks_hit_list)

کد کامل بازی Pacman

در این بخش کد کامل و یکپارچه بازی Pacman را مشاهده می‌کنید. این کد آماده اجرا است و تمام بخش‌های بازی را شامل می‌شود.

⚠️ توجه: قبل از اجرای کد، مطمئن شوید که:

  1. کتابخانه Pygame نصب شده باشد: pip install pygame
  2. پوشه images در کنار فایل پایتون ایجاد شده باشد
  3. تصاویر شخصیت‌ها در پوشه images قرار گرفته باشند
  4. فایل موسیقی pacman.mp3 (اختیاری) در کنار فایل اصلی باشد
import pygame
  
black = (0,0,0)
white = (255,255,255)
blue = (0,0,255)
green = (0,255,0)
red = (255,0,0)
purple = (255,0,255)
yellow   = ( 255, 255,   0)

Trollicon=pygame.image.load('images/Trollman.png')
pygame.display.set_icon(Trollicon)

#Add music
pygame.mixer.init()
pygame.mixer.music.load('pacman.mp3')
pygame.mixer.music.play(-1, 0.0)

# This class represents the bar at the bottom that the player controls
class Wall(pygame.sprite.Sprite):
    # Constructor function
    def __init__(self,x,y,width,height, color):
        # Call the parent's constructor
        pygame.sprite.Sprite.__init__(self)
  
        # Make a blue wall, of the size specified in the parameters
        self.image = pygame.Surface([width, height])
        self.image.fill(color)
  
        # Make our top-left corner the passed-in location.
        self.rect = self.image.get_rect()
        self.rect.top = y
        self.rect.left = x

# This creates all the walls in room 1
def setupRoomOne(all_sprites_list):
    # Make the walls. (x_pos, y_pos, width, height)
    wall_list=pygame.sprite.RenderPlain()
     
    # This is a list of walls. Each is in the form [x, y, width, height]
    walls = [ [0,0,6,600],
              [0,0,600,6],
              [0,600,606,6],
              [600,0,6,606],
              [300,0,6,66],
              [60,60,186,6],
              [360,60,186,6],
              [60,120,66,6],
              [60,120,6,126],
              [180,120,246,6],
              [300,120,6,66],
              [480,120,66,6],
              [540,120,6,126],
              [120,180,126,6],
              [120,180,6,126],
              [360,180,126,6],
              [480,180,6,126],
              [180,240,6,126],
              [180,360,246,6],
              [420,240,6,126],
              [240,240,42,6],
              [324,240,42,6],
              [240,240,6,66],
              [240,300,126,6],
              [360,240,6,66],
              [0,300,66,6],
              [540,300,66,6],
              [60,360,66,6],
              [60,360,6,186],
              [480,360,66,6],
              [540,360,6,186],
              [120,420,366,6],
              [120,420,6,66],
              [480,420,6,66],
              [180,480,246,6],
              [300,480,6,66],
              [120,540,126,6],
              [360,540,126,6]
            ]
     
    # Loop through the list. Create the wall, add it to the list
    for item in walls:
        wall=Wall(item[0],item[1],item[2],item[3],blue)
        wall_list.add(wall)
        all_sprites_list.add(wall)
         
    # return our new list
    return wall_list

def setupGate(all_sprites_list):
      gate = pygame.sprite.RenderPlain()
      gate.add(Wall(282,242,42,2,white))
      all_sprites_list.add(gate)
      return gate

# This class represents the ball        
# It derives from the "Sprite" class in Pygame
class Block(pygame.sprite.Sprite):
     
    # Constructor. Pass in the color of the block, 
    # and its x and y position
    def __init__(self, color, width, height):
        # Call the parent class (Sprite) constructor
        pygame.sprite.Sprite.__init__(self) 
 
        # Create an image of the block, and fill it with a color.
        # This could also be an image loaded from the disk.
        self.image = pygame.Surface([width, height])
        self.image.fill(white)
        self.image.set_colorkey(white)
        pygame.draw.ellipse(self.image,color,[0,0,width,height])
 
        # Fetch the rectangle object that has the dimensions of the image
        # image.
        # Update the position of this object by setting the values 
        # of rect.x and rect.y
        self.rect = self.image.get_rect() 

# This class represents the bar at the bottom that the player controls
class Player(pygame.sprite.Sprite):
  
    # Set speed vector
    change_x=0
    change_y=0
  
    # Constructor function
    def __init__(self,x,y, filename):
        # Call the parent's constructor
        pygame.sprite.Sprite.__init__(self)
   
        # Set height, width
        self.image = pygame.image.load(filename).convert()
  
        # Make our top-left corner the passed-in location.
        self.rect = self.image.get_rect()
        self.rect.top = y
        self.rect.left = x
        self.prev_x = x
        self.prev_y = y

    # Clear the speed of the player
    def prevdirection(self):
        self.prev_x = self.change_x
        self.prev_y = self.change_y

    # Change the speed of the player
    def changespeed(self,x,y):
        self.change_x+=x
        self.change_y+=y
          
    # Find a new position for the player
    def update(self,walls,gate):
        # Get the old position, in case we need to go back to it
        
        old_x=self.rect.left
        new_x=old_x+self.change_x
        prev_x=old_x+self.prev_x
        self.rect.left = new_x
        
        old_y=self.rect.top
        new_y=old_y+self.change_y
        prev_y=old_y+self.prev_y

        # Did this update cause us to hit a wall?
        x_collide = pygame.sprite.spritecollide(self, walls, False)
        if x_collide:
            # Whoops, hit a wall. Go back to the old position
            self.rect.left=old_x
            # self.rect.top=prev_y
            # y_collide = pygame.sprite.spritecollide(self, walls, False)
            # if y_collide:
            #     # Whoops, hit a wall. Go back to the old position
            #     self.rect.top=old_y
            #     print('a')
        else:

            self.rect.top = new_y

            # Did this update cause us to hit a wall?
            y_collide = pygame.sprite.spritecollide(self, walls, False)
            if y_collide:
                # Whoops, hit a wall. Go back to the old position
                self.rect.top=old_y
                # self.rect.left=prev_x
                # x_collide = pygame.sprite.spritecollide(self, walls, False)
                # if x_collide:
                #     # Whoops, hit a wall. Go back to the old position
                #     self.rect.left=old_x
                #     print('b')

        if gate != False:
          gate_hit = pygame.sprite.spritecollide(self, gate, False)
          if gate_hit:
            self.rect.left=old_x
            self.rect.top=old_y

#Inheritime Player klassist
class Ghost(Player):
    # Change the speed of the ghost
    def changespeed(self,list,ghost,turn,steps,l):
      try:
        z=list[turn][2]
        if steps < z:
          self.change_x=list[turn][0]
          self.change_y=list[turn][1]
          steps+=1
        else:
          if turn < l:
            turn+=1
          elif ghost == "clyde":
            turn = 2
          else:
            turn = 0
          self.change_x=list[turn][0]
          self.change_y=list[turn][1]
          steps = 0
        return [turn,steps]
      except IndexError:
         return [0,0]

Pinky_directions = [
[0,-30,4],
[15,0,9],
[0,15,11],
[-15,0,23],
[0,15,7],
[15,0,3],
[0,-15,3],
[15,0,19],
[0,15,3],
[15,0,3],
[0,15,3],
[15,0,3],
[0,-15,15],
[-15,0,7],
[0,15,3],
[-15,0,19],
[0,-15,11],
[15,0,9]
]

Blinky_directions = [
[0,-15,4],
[15,0,9],
[0,15,11],
[15,0,3],
[0,15,7],
[-15,0,11],
[0,15,3],
[15,0,15],
[0,-15,15],
[15,0,3],
[0,-15,11],
[-15,0,3],
[0,-15,11],
[-15,0,3],
[0,-15,3],
[-15,0,7],
[0,-15,3],
[15,0,15],
[0,15,15],
[-15,0,3],
[0,15,3],
[-15,0,3],
[0,-15,7],
[-15,0,3],
[0,15,7],
[-15,0,11],
[0,-15,7],
[15,0,5]
]

Inky_directions = [
[30,0,2],
[0,-15,4],
[15,0,10],
[0,15,7],
[15,0,3],
[0,-15,3],
[15,0,3],
[0,-15,15],
[-15,0,15],
[0,15,3],
[15,0,15],
[0,15,11],
[-15,0,3],
[0,-15,7],
[-15,0,11],
[0,15,3],
[-15,0,11],
[0,15,7],
[-15,0,3],
[0,-15,3],
[-15,0,3],
[0,-15,15],
[15,0,15],
[0,15,3],
[-15,0,15],
[0,15,11],
[15,0,3],
[0,-15,11],
[15,0,11],
[0,15,3],
[15,0,1],
]

Clyde_directions = [
[-30,0,2],
[0,-15,4],
[15,0,5],
[0,15,7],
[-15,0,11],
[0,-15,7],
[-15,0,3],
[0,15,7],
[-15,0,7],
[0,15,15],
[15,0,15],
[0,-15,3],
[-15,0,11],
[0,-15,7],
[15,0,3],
[0,-15,11],
[15,0,9],
]

pl = len(Pinky_directions)-1
bl = len(Blinky_directions)-1
il = len(Inky_directions)-1
cl = len(Clyde_directions)-1

# Call this function so the Pygame library can initialize itself
pygame.init()
  
# Create an 606x606 sized screen
screen = pygame.display.set_mode([606, 606])

# This is a list of 'sprites.' Each block in the program is
# added to this list. The list is managed by a class called 'RenderPlain.'


# Set the title of the window
pygame.display.set_caption('Pacman')

# Create a surface we can draw on
background = pygame.Surface(screen.get_size())

# Used for converting color maps and such
background = background.convert()
  
# Fill the screen with a black background
background.fill(black)



clock = pygame.time.Clock()

pygame.font.init()
font = pygame.font.Font("freesansbold.ttf", 24)

#default locations for Pacman and monstas
w = 303-16 #Width
p_h = (7*60)+19 #Pacman height
m_h = (4*60)+19 #Monster height
b_h = (3*60)+19 #Binky height
i_w = 303-16-32 #Inky width
c_w = 303+(32-16) #Clyde width

def startGame():

  all_sprites_list = pygame.sprite.RenderPlain()

  block_list = pygame.sprite.RenderPlain()

  monsta_list = pygame.sprite.RenderPlain()

  pacman_collide = pygame.sprite.RenderPlain()

  wall_list = setupRoomOne(all_sprites_list)

  gate = setupGate(all_sprites_list)


  p_turn = 0
  p_steps = 0

  b_turn = 0
  b_steps = 0

  i_turn = 0
  i_steps = 0

  c_turn = 0
  c_steps = 0


  # Create the player paddle object
  Pacman = Player( w, p_h, "images/Trollman.png")
  all_sprites_list.add(Pacman)
  pacman_collide.add(Pacman)
   
  Blinky=Ghost( w, b_h, "images/Blinky.png")
  monsta_list.add(Blinky)
  all_sprites_list.add(Blinky)

  Pinky=Ghost( w, m_h, "images/Pinky.png")
  monsta_list.add(Pinky)
  all_sprites_list.add(Pinky)
   
  Inky=Ghost( i_w, m_h, "images/Inky.png")
  monsta_list.add(Inky)
  all_sprites_list.add(Inky)
   
  Clyde=Ghost( c_w, m_h, "images/Clyde.png")
  monsta_list.add(Clyde)
  all_sprites_list.add(Clyde)

  # Draw the grid
  for row in range(19):
      for column in range(19):
          if (row == 7 or row == 8) and (column == 8 or column == 9 or column == 10):
              continue
          else:
            block = Block(yellow, 4, 4)

            # Set a random location for the block
            block.rect.x = (30*column+6)+26
            block.rect.y = (30*row+6)+26

            b_collide = pygame.sprite.spritecollide(block, wall_list, False)
            p_collide = pygame.sprite.spritecollide(block, pacman_collide, False)
            if b_collide:
              continue
            elif p_collide:
              continue
            else:
              # Add the block to the list of objects
              block_list.add(block)
              all_sprites_list.add(block)

  bll = len(block_list)

  score = 0

  done = False

  i = 0

  while done == False:
      # ALL EVENT PROCESSING SHOULD GO BELOW THIS COMMENT
      for event in pygame.event.get():
          if event.type == pygame.QUIT:
              done=True

          if event.type == pygame.KEYDOWN:
              if event.key == pygame.K_LEFT:
                  Pacman.changespeed(-30,0)
              if event.key == pygame.K_RIGHT:
                  Pacman.changespeed(30,0)
              if event.key == pygame.K_UP:
                  Pacman.changespeed(0,-30)
              if event.key == pygame.K_DOWN:
                  Pacman.changespeed(0,30)

          if event.type == pygame.KEYUP:
              if event.key == pygame.K_LEFT:
                  Pacman.changespeed(30,0)
              if event.key == pygame.K_RIGHT:
                  Pacman.changespeed(-30,0)
              if event.key == pygame.K_UP:
                  Pacman.changespeed(0,30)
              if event.key == pygame.K_DOWN:
                  Pacman.changespeed(0,-30)
          
      # ALL EVENT PROCESSING SHOULD GO ABOVE THIS COMMENT
   
      # ALL GAME LOGIC SHOULD GO BELOW THIS COMMENT
      Pacman.update(wall_list,gate)

      returned = Pinky.changespeed(Pinky_directions,False,p_turn,p_steps,pl)
      p_turn = returned[0]
      p_steps = returned[1]
      Pinky.changespeed(Pinky_directions,False,p_turn,p_steps,pl)
      Pinky.update(wall_list,False)

      returned = Blinky.changespeed(Blinky_directions,False,b_turn,b_steps,bl)
      b_turn = returned[0]
      b_steps = returned[1]
      Blinky.changespeed(Blinky_directions,False,b_turn,b_steps,bl)
      Blinky.update(wall_list,False)

      returned = Inky.changespeed(Inky_directions,False,i_turn,i_steps,il)
      i_turn = returned[0]
      i_steps = returned[1]
      Inky.changespeed(Inky_directions,False,i_turn,i_steps,il)
      Inky.update(wall_list,False)

      returned = Clyde.changespeed(Clyde_directions,"clyde",c_turn,c_steps,cl)
      c_turn = returned[0]
      c_steps = returned[1]
      Clyde.changespeed(Clyde_directions,"clyde",c_turn,c_steps,cl)
      Clyde.update(wall_list,False)

      # See if the Pacman block has collided with anything.
      blocks_hit_list = pygame.sprite.spritecollide(Pacman, block_list, True)
       
      # Check the list of collisions.
      if len(blocks_hit_list) > 0:
          score +=len(blocks_hit_list)
      
      # ALL GAME LOGIC SHOULD GO ABOVE THIS COMMENT
   
      # ALL CODE TO DRAW SHOULD GO BELOW THIS COMMENT
      screen.fill(black)
        
      wall_list.draw(screen)
      gate.draw(screen)
      all_sprites_list.draw(screen)
      monsta_list.draw(screen)

      text=font.render("Score: "+str(score)+"/"+str(bll), True, red)
      screen.blit(text, [10, 10])

      if score == bll:
        doNext("Congratulations, you won!",145,all_sprites_list,block_list,monsta_list,pacman_collide,wall_list,gate)

      monsta_hit_list = pygame.sprite.spritecollide(Pacman, monsta_list, False)

      if monsta_hit_list:
        doNext("Game Over",235,all_sprites_list,block_list,monsta_list,pacman_collide,wall_list,gate)

      # ALL CODE TO DRAW SHOULD GO ABOVE THIS COMMENT
      
      pygame.display.flip()
    
      clock.tick(10)

def doNext(message,left,all_sprites_list,block_list,monsta_list,pacman_collide,wall_list,gate):
  while True:
      # ALL EVENT PROCESSING SHOULD GO BELOW THIS COMMENT
      for event in pygame.event.get():
        if event.type == pygame.QUIT:
          pygame.quit()
        if event.type == pygame.KEYDOWN:
          if event.key == pygame.K_ESCAPE:
            pygame.quit()
          if event.key == pygame.K_RETURN:
            del all_sprites_list
            del block_list
            del monsta_list
            del pacman_collide
            del wall_list
            del gate
            startGame()

      #Grey background
      w = pygame.Surface((400,200))  # the size of your rect
      w.set_alpha(10)                # alpha level
      w.fill((128,128,128))           # this fills the entire surface
      screen.blit(w, (100,200))    # (0,0) are the top-left coordinates

      #Won or lost
      text1=font.render(message, True, white)
      screen.blit(text1, [left, 233])

      text2=font.render("To play again, press ENTER.", True, white)
      screen.blit(text2, [135, 303])
      text3=font.render("To quit, press ESCAPE.", True, white)
      screen.blit(text3, [165, 333])

      pygame.display.flip()

      clock.tick(10)

startGame()

pygame.quit()

توضیحات کد کامل:

  • خطوط 1-30: وارد کردن کتابخانه‌ها، تعریف رنگ‌ها، بارگذاری تصاویر و موسیقی
  • خطوط 32-120: تعریف کلاس‌های اصلی بازی (Wall, Block, Player, Ghost)
  • خطوط 122-200: تعریف الگوهای حرکتی روح‌ها
  • خطوط 202-250: راه‌اندازی اولیه Pygame و ایجاد پنجره بازی
  • خطوط 252-400: تابع startGame که بازی را شروع می‌کند
  • خطوط 402-450: تابع doNext برای نمایش صفحه پایان بازی
  • خط 452: شروع بازی با فراخوانی تابع startGame

نحوه اجرا

پس از آماده‌سازی تمام فایل‌ها، بازی را می‌توانید اجرا کنید.

مراحل اجرا:

  1. کد کامل را در فایلی به نام pacman.py ذخیره کنید
  2. فایل‌های تصویری را در پوشه images قرار دهید
  3. فایل موسیقی pacman.mp3 را در کنار فایل اصلی قرار دهید (اختیاری)
  4. در ترمینال دستور زیر را اجرا کنید:
    python pacman.py

کنترل‌های بازی:

  • کلیدهای جهت‌دار (↑ ← ↓ →): حرکت پک‌من
  • هدف بازی: جمع‌آوری تمام نقاط زرد رنگ
  • نکته: از برخورد با روح‌ها دوری کنید
  • پایان بازی:
    • برد: جمع‌آوری تمام نقاط
    • باخت: برخورد با روح
  • منوی پایان:
    • ENTER: شروع مجدد بازی
    • ESCAPE: خروج از بازی

تنظیم سرعت بازی:

می‌توانید سرعت بازی را با تغییر مقدار clock.tick() تنظیم کنید:

# خط 322 در کد اصلی
clock.tick(10)  # سرعت فعلی: 10 فریم در ثانیه

# برای سرعت بیشتر:
clock.tick(20)

# برای سرعت کمتر:
clock.tick(5)

توسعه و بهبود پروژه

پس از تکمیل پروژه اصلی، می‌توانید ویژگی‌های زیر را به بازی اضافه کنید:

1. اضافه کردن مراحل مختلف:

def setupRoomTwo(all_sprites_list):
    # ایجاد طرح متفاوت برای دیوارها
    walls = [
        [0, 0, 6, 600],
        [0, 0, 600, 6],
        # ... طرح جدید
    ]
    # ...

2. سیستم قدرت (Power-up):

نقاط بزرگ‌تری اضافه کنید که وقتی پک‌من آنها را جمع می‌کند، برای مدت محدودی قادر به خوردن روح‌ها شود.

3. افزایش هوشمندی روح‌ها:

الگوریتم‌های پیچیده‌تری برای تعقیب پک‌من پیاده‌سازی کنید.

4. سیستم ذخیره امتیاز:

def save_high_score(score):
    with open('high_score.txt', 'w') as f:
        f.write(str(score))

def load_high_score():
    try:
        with open('high_score.txt', 'r') as f:
            return int(f.read())
    except:
        return 0

5. جلوه‌های بصری پیشرفته:

  • انیمیشن باز و بسته شدن دهان پک‌من
  • تغییر رنگ روح‌ها هنگام ترسیدن
  • جلوه‌های ذره‌ای هنگام جمع کردن نقاط

منابع و مستندات

منابع آموزشی:

کتابخانه‌های مفید:

  • Pygame: کتابخانه اصلی برای ساخت بازی
  • Pillow: برای پردازش تصاویر پیشرفته
  • NumPy: برای محاسبات عددی پیچیده

نکات نهایی:

  • همیشه کد خود را در Git ذخیره کنید
  • کد را به بخش‌های کوچک و قابل مدیریت تقسیم کنید
  • توضیحات کافی در کد بنویسید
  • از تصاویر با کیفیت مناسب استفاده کنید
  • قبل از انتشار، بازی را روی سیستم‌های مختلف تست کنید