نمایش مرحله و تعداد سفینه‌ها

نمایش دادن مرحله

برای نمایش مرحله‌ای از بازی که بازیکن در آن قرار دارد، باید ابتدا شاخصه‌ای به GameStats اضافه کنیم که بیانگر مرحله‌ی فعلی باشد. برای بازنشانی مرحله در ابتدای هر بازی جدید آن را در reset_stats() مقداردهی اوّلیّه می‌کنیم:

1
2
3
4
5
6
def reset_stats(self):
    """Initialize statistics that can change during the game."""
    self.ships_left = self.settings.ship_limit

    self.score = 0
    self.level = 1

برای این که Scoreboard مرحله‌ی فعلی را نمایش دهد تابعی جدید را به نام prep_level() از __init__() صدا می‌کنیم:

1
2
3
4
5
def __init__(self, ai_game):
    --snip--

    self.prep_high_score()
    self.prep_level()

این متد prep_level() است:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
def prep_level(self):
    """Turn the level into a rendered image."""
    level_str = str(self.stats.level)
    self.level_image = self.font.render(level_str, True,
        self.text_color, self.settings.bg_color)

    # Position the level below the score.
    self.level_rect = self.level_image.get_rect()
    self.level_rect.right = self.score_rect.right
    self.level_rect.top = self.score_rect.bottom + 10

متد prep_level() تصویری از مقدار ذخیره‌شده در stats.level می‌سازد و مقدار مشخّصه‌ی right آن را متناسب با مشخّصه‌ی right امتیازها تعیین می‌کند. سپس مشخّصه‌ی top تصویر را ۱۰ پیکسل پایین‌تر از انتهای تصویر امتیاز قرار می‌دهد تا بین امتیاز و مرحله فاصله‌ای بیفتد.

باید show_score() را هم به‌روز کنیم:

1
2
3
4
5
def show_score(self):
    """Draw scores and level to the screen."""
    self.screen.blit(self.score_image, self.score_rect)
    self.screen.blit(self.high_score_image, self.high_score_rect)
    self.screen.blit(self.level_image, self.level_rect)

خطّی که به تازگی اضافه شده تصویر مرحله را روی صفحه نشان می‌دهد.

در _check_bullet_alien_collisions() مقدار stats.level را افزایش داده و تصویر مرحله را به‌روز می‌کنیم:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
def _check_bullet_alien_collisions(self):
    --snip--

    if not self.aliens:
        # Destroy existing bullets and create new fleet.
        self.bullets.empty()
        self._create_fleet()
        self.settings.increase_speed()

        # Increase level.
        self.stats.level += 1
        self.sb.prep_level()

اگر ناوگانی نابود شود مقدار stats.level را افزایش می‌دهیم و prep_level() را فرامی‌خوانیم تا مطمئن شویم که مرحله‌ی جدید به درستی نمایش داده می‌شود.

برای اطمینان از به‌روزرسانی درست تصویر مرحله در آغاز یک بازی جدید، هنگامی که بازیکن دکمه‌ی Play را فشار می‌دهد نیز یک بار متد prep_level() را صدا می‌کنیم:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
def _check_play_button(self, mouse_pos):
    --snip--

    if button_clicked and not self.stats.game_active:
        --snip--

        self.sb.prep_score()
        self.sb.prep_level()

    --snip--

prep_level() را درست پس از فراخوانی prep_score() صدا می‌کنیم.

حال تعداد مراحلی را که به پایان رسانده‌اید خواهید دید، مانند شکل ۱۴-۵.

شکل ۱۴-۵

شکل ۱۴-۵: مرحله‌ی فعلی درست زیر امتیاز فعلی نمایان می‌شود.

نکته
در برخی بازی‌های کلاسیک امتیازها برچسب دارند مانند امتیاز، بالاترین امتیاز و مرحله. چون معنای هر عدد به محض این که بازیکن بازی را شروع می‌کند معلوم می‌شود ما این برچسب‌ها را حذف کرده‌ایم. برای افزودن آن‌ها، آن‌ها را به رشته‌های مربوط به امتیازها درست پیش از فراخوانی font.render() در Scoreboard اضافه کنید.

نمایش تعداد سفینه‌ها

در نهایت تعداد سفینه‌هایی را که برای بازیکن باقی مانده نمایش می‌دهیم امّا این بار از تصویرهای گرافیکی استفاده می‌کنیم. برای چنین کاری، همانند بسیاری از بازی‌های آرکید، سفینه‌ها را در گوشه‌ی بالا-چپ صفحه می‌کشیم تا بیانگر تعداد سفینه‌های باقی‌مانده باشد.

ابتدا باید کاری کنیم که Ship از Sprite ارث ببرد تا بتوانیم گروهی از سفینه‌ها بسازیم:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
import pygame
from pygame.sprite import Sprite

class Ship(Sprite):
    """A class to manage the ship."""

    def __init__(self, ai_game):
        """Initialize the ship and set its starting position."""
        super().__init__()

        --snip--

اینجا Sprite را وارد می‌کنیم، مطمئن می‌شویم که Ship از Sprite ارث می‌برد و super() را در ابتدای __init__() فرامی‌خوانیم.

سپس باید Scoreboard را طوری تغییر دهیم تا گروهی از سفینه‌ها برای نمایش بسازد. این عبارت‌های import در Scoreboard است:

1
2
3
4
import pygame.font
from pygame.sprite import Group

from ship import Ship

چون گروهی از سفینه‌ها می‌سازیم Group و Ship را وارد می‌کنیم.

این __init__() است:

1
2
3
4
5
6
7
8
def __init__(self, ai_game):
    """Initialize scorekeeping attributes."""
    self.ai_game = ai_game
    self.screen = ai_game.screen
    --snip--

    self.prep_level()
    self.prep_ships()

نمونه‌ی بازی را به یک مشخّصه نسبت می‌دهیم زیرا آن را برای ساختن چند سفینه نیاز داریم. prep_ships() را پس از فراخوانی prep_level() صدا می‌کنیم.

این prep_ships() است:

1
2
3
4
5
6
7
8
9
def prep_ships(self):
    """Show how many ships are left."""
    self.ships = Group()

    for ship_number in range(self.stats.ships_left):
        ship = Ship(self.ai_game)
        ship.rect.x = 10 + ship_number * ship.rect.width
        ship.rect.y = 10
        self.ships.add(ship)

متد prep_ships() گروهی خالی به نام self.ships می‌سازد تا نمونه‌های سفینه را در آن نگه دارد. برای پر کردن این گروه حلقه‌ای یک بار برای هر کدام از سفینه‌های باقیمانده اجرا می‌شود. داخل حلقه سفینه جدیدی می‌سازیم و مقدار مختصّه‌ی x آن را طوری تنظیم می‌کنیم تا سفینه‌ها کنار یکدیگر و با یک حاشیه‌ی ۱۰ پیکسلی از سمت چپ گروه سفینه‌ها دیده شوند. مقدار مختصّه‌ی y را ده پیکسل پایین‌تر از بالای صفحه می‌گذاریم تا سفینه‌ها در گوشه‌ی بالا-چپ صفحه دیده شوند. سپس هر سفینه جدید را به گروه ships اضافه می‌کنیم.

حال باید سفینه‌ها را روی صفحه بکشیم:

1
2
3
4
5
6
def show_score(self):
    """Draw scores, level, and ships to the screen."""
    self.screen.blit(self.score_image, self.score_rect)
    self.screen.blit(self.high_score_image, self.high_score_rect)
    self.screen.blit(self.level_image, self.level_rect)
    self.ships.draw(self.screen)

برای نمایش سفینه‌ها روی صفحه draw() را روی هر گروه اعمال می‌کنیم و پای‌گیم هر سفینه را رسم می‌کند.

برای این که به بازیکن نشان دهیم که چند سفینه برای شروع بازی در اختیار دارد، prep_ships() را هنگام شروع یک بازی جدید فرامی‌خوانیم. این کار را در _check_play_button() در AlienInvasion انجام می‌دهیم:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
def _check_play_button(self, mouse_pos):
    --snip--

    if button_clicked and not self.stats.game_active:
        --snip--

        self.sb.prep_score()
        self.sb.prep_level()
        self.sb.prep_ships()

    --snip--

این متد را هنگام مورد اصابت قرار گرفتن یک سفینه هم صدا می‌کنیم تا تصویر سفینه‌ها را هنگام از دست رفتن یک سفینه به‌روز کنیم:

1
2
3
4
5
6
7
8
9
def _ship_hit(self):
    """Respond to ship being hit by alien."""
    if self.stats.ships_left > 0:
        # Decrement ships_left, and update scoreboard.
        self.stats.ships_left -= 1

        self.sb.prep_ships()

    --snip--

متد prep_ships() را پس از کاهش دادن مقدار ships_left صدا می‌کنیم تا هنگام نابود شدن هر سفینه تعداد درست سفینه‌ها نمایش داده شود.

شکل ۱۴-۶ نظام امتیازدهی کامل را به همراه تعداد سفینه‌های باقیمانده در گوشه‌ی بالا-چپ تصویر نشان می‌دهد.

شکل ۱۴-۶

شکل ۱۴-۶: نظام کامل امتیازدهی برای هجوم بیگانگان