ساخت بازی Bricks با PyGame

مقدمه

بازی Bricks، که با نام‌هایی مانند Breakout یا Arkanoid نیز شناخته می‌شود، یک بازی کلاسیک آرکید است که هدف اصلی در آن شکستن تمام آجرها در بالای صفحه با استفاده از یک توپ و یک پدل (تخته) است. پدل توسط بازیکن کنترل می‌شود تا توپ را به سمت بالا برگرداند و از افتادن آن به پایین صفحه جلوگیری کند. ساخت این بازی با استفاده از کتابخانه PyGame در پایتون یک پروژه عالی برای یادگیری مفاهیم پایه توسعه بازی‌های دوبعدی است. در این مقاله به صورت جامع به مراحل و مفاهیم کلیدی برای ساخت این بازی می‌پردازیم.

چرا PyGame؟

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

پیش‌نیازها

برای شروع، شما نیاز به نصب پایتون و کتابخانه PyGame دارید. اگر پایتون را نصب کرده‌اید، می‌توانید PyGame را به سادگی با استفاده از pip نصب کنید:

pip install pygame

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

ساختار کلی بازی

هر بازی که با PyGame ساخته می‌شود، معمولاً دارای یک “حلقه بازی” (Game Loop) اصلی است. این حلقه به طور مداوم اجرا می‌شود و سه وظیفه اصلی را بر عهده دارد:

  1. دریافت ورودی کاربر: خواندن رویدادهایی مانند فشار دادن کلیدها یا حرکت ماوس.
  2. به‌روزرسانی وضعیت بازی: محاسبه موقعیت جدید اشیاء، بررسی برخوردها، به‌روزرسانی امتیاز و غیره.
  3. رسم عناصر بازی: پاک کردن صفحه و کشیدن تمام اشیاء بازی در موقعیت‌های جدیدشان.

اجزای اصلی بازی Bricks

برای ساخت بازی Bricks، به چند عنصر اصلی نیاز داریم که هر کدام ویژگی‌ها و رفتارهای خاص خود را دارند:

  1. پنجره بازی (Game Window): محیطی که بازی در آن نمایش داده می‌شود.
  2. پدل (Paddle): تخته‌ای که بازیکن کنترل می‌کند.
  3. توپ (Ball): گوی که بین پدل، دیوارها و آجرها حرکت می‌کند.
  4. آجرها (Bricks): هدف بازی که باید توسط توپ شکسته شوند.
  5. امتیاز (Score) و جان (Lives): اطلاعاتی که وضعیت بازیکن را نشان می‌دهند.

مراحل پیاده‌سازی

بیایید نگاهی دقیق‌تر به پیاده‌سازی هر بخش بیندازیم:

۱٫ راه‌اندازی PyGame و پنجره بازی

اولین قدم در هر پروژه PyGame، راه‌اندازی کتابخانه و ایجاد پنجره‌ای برای نمایش بازی است. این کار شامل وارد کردن ماژول pygame، فراخوانی تابع pygame.init()، تعریف ابعاد صفحه و ایجاد سطح نمایش (Surface) اصلی بازی است. همچنین باید عنوان پنجره را تنظیم کنید.

۲٫ تعریف و رسم اشیاء بازی

  • پدل: پدل معمولاً به صورت یک مستطیل (pygame.Rect) تعریف می‌شود. باید ابعاد (عرض و ارتفاع) و موقعیت اولیه آن (معمولاً در پایین و مرکز صفحه) مشخص شود.
  • توپ: توپ را می‌توان به صورت یک دایره یا مستطیل مربع شکل نمایش داد. برای سادگی در تشخیص برخورد، استفاده از pygame.Rect برای توپ نیز رایج است. توپ دارای موقعیت، ابعاد و سرعت در جهت افقی و عمودی است (ball_speed_x, ball_speed_y).
  • آجرها: آجرها نیز به صورت مستطیل تعریف می‌شوند. معمولاً یک چیدمان شبکه‌ای از آجرها در بالای صفحه ایجاد می‌شود. می‌توان از یک لیست پایتون برای نگهداری تمام اشیاء آجر استفاده کرد. هر آجر موقعیت و ابعاد خود را دارد.

رسم هر یک از این اشیاء در حلقه بازی با استفاده از توابعی مانند pygame.draw.rect() یا pygame.draw.circle() انجام می‌شود. قبل از رسم هر فریم جدید، صفحه باید با یک رنگ پس‌زمینه (معمولاً سیاه یا آبی تیره) پاک شود.

۳٫ کنترل پدل

حرکت پدل معمولاً با استفاده از کلیدهای جهت‌نمای چپ و راست صفحه کلید کنترل می‌شود. در حلقه بازی، رویدادهای صفحه کلید (pygame.event.get()) بررسی می‌شوند. اگر کلید چپ فشار داده شده باشد، موقعیت افقی پدل به سمت چپ کاهش می‌یابد و اگر کلید راست فشار داده شده باشد، موقعیت افقی آن به سمت راست افزایش می‌یابد. باید مطمئن شوید که پدل از کناره‌های صفحه خارج نشود.

۴٫ حرکت توپ و برخورد با دیوارها

موقعیت توپ در هر فریم بر اساس سرعت آن به‌روزرسانی می‌شود: ball.x += ball_speed_x و ball.y += ball_speed_y.

برخورد توپ با دیوارها باید بررسی شود:

  • اگر توپ به دیوار چپ یا راست (لبه‌های افقی صفحه) برخورد کند، جهت سرعت افقی آن (ball_speed_x) معکوس می‌شود.
  • اگر توپ به دیوار بالا (لبه بالایی صفحه) برخورد کند، جهت سرعت عمودی آن (ball_speed_y) معکوس می‌شود.
  • اگر توپ به لبه پایین صفحه برسد، بازیکن یک جان را از دست می‌دهد. اگر تعداد جان‌ها صفر شود، بازی به اتمام می‌رسد (Game Over).

۵٫ برخورد توپ با پدل

برخورد توپ با پدل با استفاده از متد colliderect() اشیاء pygame.Rect بررسی می‌شود. اگر ball.colliderect(paddle) درست باشد (یعنی مستطیل‌های توپ و پدل با هم همپوشانی داشته باشند)، جهت سرعت عمودی توپ (ball_speed_y) معکوس می‌شود تا توپ به سمت بالا پرتاب شود. برای واقع‌گرایی بیشتر، می‌توان جهت سرعت افقی توپ را نیز بر اساس نقطه‌ای که به پدل برخورد کرده است تغییر داد (مثلاً اگر به سمت چپ پدل برخورد کند، کمی به چپ متمایل شود)، اما برای شروع، معکوس کردن سرعت عمودی کافی است.

۶٫ ساختار آجرها و برخورد با توپ

آجرها معمولاً در یک لیست نگهداری می‌شوند. در مرحله راه‌اندازی بازی، با استفاده از حلقه‌های تودرتو (برای سطرها و ستون‌ها) می‌توان اشیاء pygame.Rect مربوط به هر آجر را ایجاد و به لیست اضافه کرد.

در حلقه بازی، برای هر آجر در لیست، برخورد آن با توپ بررسی می‌شود (ball.colliderect(brick)). اگر برخوردی رخ دهد:

  • آجر از لیست آجرها حذف می‌شود (چون شکسته شده است).
  • به امتیاز بازیکن اضافه می‌شود.
  • جهت سرعت عمودی توپ (ball_speed_y) معکوس می‌شود.
  • مهم است که پس از تشخیص برخورد با یک آجر و انجام عملیات مربوطه، از بررسی برخورد با بقیه آجرها در همان فریم برای جلوگیری از رفتارهای عجیب جلوگیری کنید. می‌توان از یک پرچم یا شکستن حلقه بررسی آجرها استفاده کرد.

۷٫ مدیریت امتیاز و وضعیت بازی

متغیرهایی برای نگهداری امتیاز (score) و تعداد جان‌ها (lives) نیاز داریم. هر بار که یک آجر شکسته می‌شود، امتیاز افزایش می‌یابد. هر بار که توپ به پایین صفحه می‌رسد و بازیکن جان دارد، یک جان از او کسر می‌شود و توپ در موقعیت اولیه (بالای پدل) قرار می‌گیرد.

برای نمایش امتیاز و تعداد جان‌ها روی صفحه، از ماژول pygame.font استفاده می‌شود. یک فونت انتخاب شده، متون مربوط به امتیاز و جان‌ها رندر (render) شده و سپس در موقعیت مناسب روی صفحه رسم می‌شوند.

شرایط پایان بازی نیز باید مدیریت شوند:

  • پیروزی: اگر لیست آجرها خالی شود (یعنی تمام آجرها شکسته شده باشند)، بازیکن برنده شده است.
  • باخت: اگر تعداد جان‌ها به صفر برسد و توپ به پایین صفحه برسد، بازیکن بازنده شده است.

در هر دو حالت پیروزی و باخت، می‌توان پیامی را روی صفحه نمایش داد و منتظر اقدام کاربر (مانند فشار دادن کلیدی برای شروع مجدد یا خروج) شد.

۸٫ حلقه اصلی بازی

تمام منطق بالا در داخل حلقه اصلی بازی قرار می‌گیرد. این حلقه تا زمانی که بازیکن بخواهد از بازی خارج شود (مثلاً با بستن پنجره یا فشار دادن کلید خاص) اجرا می‌شود. ساختار کلی حلقه به این صورت است:

running = True
clock = pygame.time.Clock() # برای کنترل فریم ریت

while running:
    # ۱٫ مدیریت رویدادها
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
        # مدیریت ورودی کیبورد برای حرکت پدل

    # ۲٫ به‌روزرسانی وضعیت بازی
    # به‌روزرسانی موقعیت توپ
    # بررسی برخورد توپ با دیوارها
    # بررسی برخورد توپ با پدل
    # بررسی برخورد توپ با آجرها (حذف آجر، افزایش امتیاز، معکوس کردن سرعت توپ)
    # بررسی شرایط پایان بازی (پیروزی/باخت)
    # به‌روزرسانی موقعیت پدل بر اساس ورودی

    # ۳٫ رسم عناصر بازی
    # پر کردن پس‌زمینه
    # رسم پدل
    # رسم توپ
    # رسم آجرها باقی‌مانده
    # رسم امتیاز و تعداد جان‌ها
    # نمایش پیام‌های پایان بازی (اگر لازم باشد)

    # به‌روزرسانی صفحه نمایش
    pygame.display.flip() # یا update()

    # کنترل فریم ریت
    clock.tick(60) # مثلاً ۶۰ فریم در ثانیه

# پس از خروج از حلقه، PyGame را خاتمه دهید
pygame.quit()

بهبودهای احتمالی

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

  • صدا: اضافه کردن جلوه‌های صوتی برای برخورد توپ با اشیاء مختلف یا شکستن آجرها.
  • مراحل مختلف: طراحی چیدمان‌های مختلفی از آجرها برای ایجاد مراحل جدید.
  • قدرت‌ها (Powerups): اضافه کردن آیتم‌هایی که از آجرها می‌افتند و توانایی‌های ویژه‌ای به بازیکن می‌دهند (مثلاً بزرگ شدن پدل، توپ‌های بیشتر، سرعت متفاوت).
  • فیزیک پیشرفته‌تر برخورد: محاسبه دقیق‌تر جهت پرتاب توپ پس از برخورد با پدل یا آجرها.
  • صفحات شروع و پایان: اضافه کردن منوها برای شروع بازی، نمایش امتیاز نهایی و غیره.

کدهای نهایی

بسیار خوب، بر اساس توضیحات ارائه شده در مقاله قبلی، در اینجا کد پایتون کامل برای ساخت بازی ساده Bricks با استفاده از PyGame آورده شده است. این کد تمام اجزای اصلی، حلقه بازی، مدیریت برخوردها و وضعیت بازی (امتیاز، جان، برد/باخت) را که در مقاله شرح داده شد، پیاده‌سازی می‌کند.

import pygame
import sys

# تنظیمات اولیه PyGame
pygame.init()

# تنظیمات صفحه نمایش
SCREEN_WIDTH = 800
SCREEN_HEIGHT = 600
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
pygame.display.set_caption("بازی Bricks")

# رنگ‌ها
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
BLUE = (0, 0, 255)
RED = (255, 0, 0)
GREEN = (0, 255, 0)

# تنظیمات پدل
PADDLE_WIDTH = 100
PADDLE_HEIGHT = 15
PADDLE_SPEED = 7
paddle = pygame.Rect((SCREEN_WIDTH - PADDLE_WIDTH) // 2, SCREEN_HEIGHT - PADDLE_HEIGHT - 10, PADDLE_WIDTH, PADDLE_HEIGHT)

# تنظیمات توپ
BALL_SIZE = 10
BALL_SPEED_X = 5
BALL_SPEED_Y = -5
ball = pygame.Rect(SCREEN_WIDTH // 2 - BALL_SIZE // 2, SCREEN_HEIGHT // 2 - BALL_SIZE // 2, BALL_SIZE, BALL_SIZE)
ball_speed_x = BALL_SPEED_X
ball_speed_y = BALL_SPEED_Y

# تنظیمات آجرها
BRICK_WIDTH = 60
BRICK_HEIGHT = 20
BRICK_GAP = 10
BRICK_ROWS = 5
BRICK_COLS = 10

bricks = []
for row in range(BRICK_ROWS):
    for col in range(BRICK_COLS):
        brick_x = col * (BRICK_WIDTH + BRICK_GAP) + BRICK_GAP
        brick_y = row * (BRICK_HEIGHT + BRICK_GAP) + BRICK_GAP * 5 # کمی پایین‌تر از بالای صفحه
        brick_rect = pygame.Rect(brick_x, brick_y, BRICK_WIDTH, BRICK_HEIGHT)
        bricks.append(brick_rect)

# تنظیمات بازی
score = 0
lives = 3
font = pygame.font.Font(None, 36) # فونت پیش‌فرض با اندازه ۳۶
game_state = 'playing' # می‌تواند 'playing', 'win', 'lose' باشد

# ساعت بازی برای کنترل فریم ریت
clock = pygame.time.Clock()
FPS = 60

# --- حلقه اصلی بازی ---
running = True
while running:
    # مدیریت رویدادها
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
        # مدیریت ورودی کیبورد برای حرکت پدل فقط وقتی بازی در حال اجراست
        if event.type == pygame.KEYDOWN and game_state == 'playing':
            if event.key == pygame.K_LEFT:
                paddle_direction = -1
            elif event.key == pygame.K_RIGHT:
                paddle_direction = 1
        if event.type == pygame.KEYUP and game_state == 'playing':
             if event.key == pygame.K_LEFT or event.key == pygame.K_RIGHT:
                paddle_direction = 0 # توقف حرکت وقتی کلید رها می‌شود

    # --- به‌روزرسانی وضعیت بازی (فقط در حالت 'playing') ---
    if game_state == 'playing':
        # حرکت پدل
        keys = pygame.key.get_pressed()
        if keys[pygame.K_LEFT]:
            paddle.x -= PADDLE_SPEED
        if keys[pygame.K_RIGHT]:
            paddle.x += PADDLE_SPEED

        # جلوگیری از خروج پدل از صفحه
        if paddle.left < 0:
            paddle.left = 0
        if paddle.right > SCREEN_WIDTH:
            paddle.right = SCREEN_WIDTH

        # حرکت توپ
        ball.x += ball_speed_x
        ball.y += ball_speed_y

        # بررسی برخورد توپ با دیوارها
        if ball.left < 0 or ball.right > SCREEN_WIDTH:
            ball_speed_x *= -1
        if ball.top < 0:
            ball_speed_y *= -1

        # بررسی برخورد توپ با پایین صفحه (از دست دادن جان)
        if ball.bottom > SCREEN_HEIGHT:
            lives -= 1
            # بازنشانی موقعیت توپ و پدل
            ball.x = SCREEN_WIDTH // 2 - BALL_SIZE // 2
            ball.y = SCREEN_HEIGHT // 2 - BALL_SIZE // 2 # موقعیت اولیه توپ
            # پدل به موقعیت اولیه برمی‌گردد
            paddle.x = (SCREEN_WIDTH - PADDLE_WIDTH) // 2
            # سرعت توپ نیز بازنشانی می‌شود (اختیاری، اما می‌تواند بازی را قابل پیش‌بینی‌تر کند)
            ball_speed_x = BALL_SPEED_X
            ball_speed_y = -BALL_SPEED_Y # همیشه به سمت بالا شروع کند

            if lives <= 0:
                game_state = 'lose'

        # بررسی برخورد توپ با پدل
        if ball.colliderect(paddle):
            # مطمئن می‌شویم که توپ از بالای پدل برخورد کرده است تا از گیر کردن جلوگیری شود
            if ball_speed_y > 0: # یعنی توپ در حال حرکت به سمت پایین بوده است
                ball_speed_y *= -1
                # می‌توان جهت افقی را بر اساس محل برخورد به پدل کمی تغییر داد
                # مثال ساده:
                # delta_x = ball.centerx - paddle.centerx
                # ball_speed_x = delta_x * 0.1 # ضریب ۰٫۱ را تنظیم کنید


        # بررسی برخورد توپ با آجرها
        hit_brick_index = ball.collidelist(bricks)
        if hit_brick_index != -1: # اگر برخوردی رخ داده است
            hit_brick = bricks.pop(hit_brick_index) # آجر را حذف کن
            score += 10 # امتیاز اضافه کن
            ball_speed_y *= -1 # جهت عمودی توپ را معکوس کن

            # بررسی شرط پیروزی
            if not bricks:
                game_state = 'win'

    # --- رسم عناصر بازی ---
    # پر کردن پس‌زمینه
    screen.fill(BLACK)

    # رسم پدل
    pygame.draw.rect(screen, BLUE, paddle)

    # رسم توپ
    pygame.draw.circle(screen, WHITE, ball.center, BALL_SIZE // 2) # توپ را به عنوان دایره رسم می‌کنیم اما برخورد با Rect آن بررسی می‌شود

    # رسم آجرها باقی‌مانده
    for brick in bricks:
        pygame.draw.rect(screen, GREEN, brick)

    # رسم امتیاز و تعداد جان‌ها
    score_text = font.render(f"Score: {score}", True, WHITE)
    lives_text = font.render(f"Lives: {lives}", True, WHITE)
    screen.blit(score_text, (10, 10))
    screen.blit(lives_text, (SCREEN_WIDTH - lives_text.get_width() - 10, 10))

    # نمایش پیام‌های پایان بازی
    if game_state == 'win':
        win_text = font.render("You Win!", True, WHITE)
        text_rect = win_text.get_rect(center=(SCREEN_WIDTH // 2, SCREEN_HEIGHT // 2))
        screen.blit(win_text, text_rect)
        # می‌توان در اینجا منطق توقف بازی و نمایش پیام را برای مدت بیشتری اضافه کرد
        # یا منتظر ورودی برای خروج یا شروع مجدد شد

    elif game_state == 'lose':
        lose_text = font.render("Game Over", True, WHITE)
        text_rect = lose_text.get_rect(center=(SCREEN_WIDTH // 2, SCREEN_HEIGHT // 2))
        screen.blit(lose_text, text_rect)
        # مشابه حالت پیروزی، منطق توقف و انتظار برای ورودی

    # به‌روزرسانی صفحه نمایش
    pygame.display.flip() # یا pygame.display.update()

    # کنترل فریم ریت
    clock.tick(FPS)

# خروج از PyGame
pygame.quit()
sys.exit()

نتیجه‌گیری

ساخت بازی Bricks با PyGame یک راه عملی و جذاب برای یادگیری اصول توسعه بازی‌های دوبعدی در پایتون است. با پیاده‌سازی اجزای اصلی مانند پدل، توپ، آجرها و مدیریت برخوردها و وضعیت بازی در یک حلقه اصلی، می‌توانید یک بازی کلاسیک و سرگرم‌کننده ایجاد کنید. PyGame ابزارهای لازم را برای کار با گرافیک، ورودی و صدا فراهم می‌کند و یک بستر عالی برای شروع پروژه‌های بزرگتر در زمینه بازی‌سازی است. با تمرین و افزودن ویژگی‌های جدید، می‌توانید بازی خود را پیچیده‌تر و جذاب‌تر کنید.

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *