Menu
CoddyTech

Ba mạng

Thuộc phần Sprite và hình ảnh trong hành trình Pygame của Coddy. Bài học 36 trên 39.

Giờ kẻ địch có thể làm bạn mất mạng. Con tàu có ba mạng. Một kẻ địch khiến bạn mất một mạng khi nó vượt qua mép dưới, và mất một mạng khi nó đâm vào tàu:

crashes = pygame.sprite.spritecollide(player, enemies, True, pygame.sprite.collide_mask)
for enemy in crashes:
    lives -= 1
    explosions.add(Explosion(enemy.rect.center))

Con tàu cũng cần có self.mask để dùng collide_mask. Trong vòng lặp xử lý việc tiêu diệt kẻ địch khi chúng vượt qua mép dưới, hãy trừ một mạng nữa.

Hai kẻ địch có thể lấy đi hai mạng cuối cùng trong cùng một khung hình, khiến lives còn -1. Hãy hiển thị max(lives, 0), giá trị lớn hơn trong hai số, để bộ đếm không bao giờ xuống dưới 0. get_rect(topright=(x, y)) của văn bản đặt văn bản theo góc trên bên phải, nên văn bản luôn nằm sát mép phải dù rộng bao nhiêu.

challenge icon

Thử thách

Trung bình

Khiến kẻ địch làm mất mạng.

  1. Tạo lives = 3 trước vòng lặp (loop) và thêm self.mask cho Player.
  2. Khi tiêu diệt kẻ địch vượt quá cạnh dưới, hãy trừ một mạng.
  3. Mỗi kẻ địch trong spritecollide(player, enemies, True, pygame.sprite.collide_mask) sẽ làm mất một mạng và phát nổ.
  4. Vẽ f"Lives: {max(lives, 0)}" với góc trên bên phải tại (630, 10).

Nhấn Chơi và để một kẻ địch lọt qua: màn hình sẽ hiện Lives: 2. Sau đó nhấn Kiểm tra.

Tự làm thử

import random
import pygame

pygame.init()
screen = pygame.display.set_mode((640, 480))
pygame.display.set_caption("Star Patrol")
clock = pygame.time.Clock()
font = pygame.font.Font(None, 32)

ship_image = pygame.image.load("assets/images/ship.png").convert_alpha()
laser_image = pygame.image.load("assets/images/laser.png").convert_alpha()
red_image = pygame.image.load("assets/images/enemy_red.png").convert_alpha()
explosion_frames = []
for number in range(1, 5):
    explosion_frames.append(pygame.image.load(f"assets/images/explosion_{number}.png").convert_alpha())


class Player(pygame.sprite.Sprite):
    def __init__(self):
        super().__init__()
        self.image = ship_image
        self.rect = self.image.get_rect(midbottom=(320, 470))

    def update(self):
        keys = pygame.key.get_pressed()
        if keys[pygame.K_LEFT]:
            self.rect.x -= 6
        if keys[pygame.K_RIGHT]:
            self.rect.x += 6
        self.rect.clamp_ip(screen.get_rect())


class Laser(pygame.sprite.Sprite):
    def __init__(self, x, y):
        super().__init__()
        self.image = laser_image
        self.rect = self.image.get_rect(midbottom=(x, y))
        self.mask = pygame.mask.from_surface(self.image)

    def update(self):
        self.rect.y -= 10
        if self.rect.bottom < 0:
            self.kill()


class Enemy(pygame.sprite.Sprite):
    def __init__(self, image, x, y, speed):
        super().__init__()
        self.image = image
        self.rect = self.image.get_rect(center=(x, y))
        self.mask = pygame.mask.from_surface(self.image)
        self.speed = speed

    def update(self):
        self.rect.y += self.speed


class Explosion(pygame.sprite.Sprite):
    def __init__(self, center):
        super().__init__()
        self.index = 0
        self.timer = 0
        self.image = explosion_frames[0]
        self.rect = self.image.get_rect(center=center)

    def update(self):
        self.timer += 1
        if self.timer == 5:
            self.timer = 0
            self.index += 1
            if self.index == len(explosion_frames):
                self.kill()
            else:
                self.image = explosion_frames[self.index]


def spawn_wave(image, count, speed):
    for i in range(count):
        x = random.randint(40, 600)
        enemies.add(Enemy(image, x, -40 - i * 120, speed))


player = Player()
lasers = pygame.sprite.Group()
enemies = pygame.sprite.Group()
explosions = pygame.sprite.Group()
last_shot = 0
score = 0
spawn_wave(red_image, 6, 2)

running = True
while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False

    player.update()
    keys = pygame.key.get_pressed()
    now = pygame.time.get_ticks()
    if keys[pygame.K_SPACE] and now - last_shot >= 250:
        lasers.add(Laser(player.rect.centerx, player.rect.top))
        last_shot = now
    lasers.update()
    enemies.update()
    for enemy in enemies:
        if enemy.rect.top > 480:
            enemy.kill()
    hits = pygame.sprite.groupcollide(enemies, lasers, True, True, pygame.sprite.collide_mask)
    for enemy in hits:
        score += 10
        explosions.add(Explosion(enemy.rect.center))
    explosions.update()

    screen.fill((12, 14, 30))
    enemies.draw(screen)
    lasers.draw(screen)
    screen.blit(player.image, player.rect)
    explosions.draw(screen)
    score_text = font.render(f"Score: {score}", True, (240, 240, 240))
    screen.blit(score_text, (10, 10))
    pygame.display.flip()
    clock.tick(60)

pygame.quit()

Tất cả bài học trong Sprite và hình ảnh

Tự luyện tập: Playground Pygame