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.
Thử thách
Trung bìnhKhiến kẻ địch làm mất mạng.
- Tạo
lives = 3trước vòng lặp (loop) và thêmself.maskchoPlayer. - Khi tiêu diệt kẻ địch vượt quá cạnh dưới, hãy trừ một mạng.
- 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ổ. - 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
7Tuần tra giữa các vì sao
Tàu tuần traBắn laser5Va chạm chính xác đến từng pixel
Hình chữ nhật thật bất côngMặt nạSprite chính xác đến từng pixelVùng va chạm hình tròn3Lớp cho đối tượng trong trò chơi
Lớp đầu tiên của bạnPhương thứcSelf là đối tượngDanh sách đối tượngĐối tượng có hình ảnhDanh sách kẻ địchLớp con6Hoạt ảnh từ sprite sheet
Cắt sprite sheetBộ đếm khung hìnhTạo hoạt ảnh theo thời gianHiệu ứng nổ chỉ chạy một lầnTự luyện tập: Playground Pygame