如何在Pygame中实现火球完整跨屏移动?Flappy Bird类游戏开发问题
Hey there! Let's tackle that fireball scrolling issue you're having. Your initial thought about using a list to manage multiple fireballs is exactly the right approach—let's turn that into working code. Here's how to implement smooth, continuous cross-screen fireball movement:
Step 1: Switch to a List for Fireball Management
Instead of a single meteor variable, we'll use a list to track all active fireball instances. This lets us handle spawning new fireballs, updating their positions, and removing off-screen ones seamlessly.
Step 2: Add Spawn Logic for New Fireballs
We'll trigger new fireball spawns at regular intervals (using a frame counter) and randomize their vertical position to add game variety—just like Flappy Bird's pipes.
Step 3: Update and Clean Up Off-Screen Fireballs
In each frame, we'll move every fireball, check if it's completely off the left edge of the screen, and remove it from the list to save resources.
Here's your modified code with these changes:
import pygame import sys import os import random pygame.init() path = os.getcwd() bg = pygame.transform.scale2x(pygame.image.load(f'{path}/Images/index.jpg')) char = [ pygame.transform.rotozoom(pygame.image.load(f'{path}/Images/R1.png'), 0, (14 / 18)), pygame.transform.rotozoom(pygame.image.load(f'{path}/Images/R2.png'), 0, (14 / 18)), pygame.transform.rotozoom(pygame.image.load(f'{path}/Images/R3.png'), 0, (14 / 18)), pygame.transform.rotozoom(pygame.image.load(f'{path}/Images/R4.png'), 0, (14 / 18)), pygame.transform.rotozoom(pygame.image.load(f'{path}/Images/R5.png'), 0, (14 / 18)), pygame.transform.rotozoom(pygame.image.load(f'{path}/Images/R6.png'), 0, (14 / 18)), pygame.transform.rotozoom(pygame.image.load(f'{path}/Images/R7.png'), 0, (14 / 18)), pygame.transform.rotozoom(pygame.image.load(f'{path}/Images/R8.png'), 0, (14 / 18)), pygame.transform.rotozoom(pygame.image.load(f'{path}/Images/R9.png'), 0, (14 / 18)), ] charFlipped = [ pygame.transform.flip(char[0], False, True), pygame.transform.flip(char[1], False, True), pygame.transform.flip(char[2], False, True), pygame.transform.flip(char[3], False, True), pygame.transform.flip(char[4], False, True), pygame.transform.flip(char[5], False, True), pygame.transform.flip(char[6], False, True), pygame.transform.flip(char[7], False, True), pygame.transform.flip(char[8], False, True), ] fireball = [ pygame.transform.flip(pygame.transform.rotozoom(pygame.image.load(f'{path}/Images/FB001.png'), 0, 3), True, False), pygame.transform.flip(pygame.transform.rotozoom(pygame.image.load(f'{path}/Images/FB002.png'), 0, 3), True, False), pygame.transform.flip(pygame.transform.rotozoom(pygame.image.load(f'{path}/Images/FB003.png'), 0, 3), True, False), pygame.transform.flip(pygame.transform.rotozoom(pygame.image.load(f'{path}/Images/FB004.png'), 0, 3), True, False), pygame.transform.flip(pygame.transform.rotozoom(pygame.image.load(f'{path}/Images/FB005.png'), 0, 3), True, False) ] winLength = 600 winWidth = 336 screen = pygame.display.set_mode((winLength, winWidth)) pygame.display.set_caption("Space Adventures") clock = pygame.time.Clock() running = True class Background(object): def __init__(self, speed): self.bgx1 = 0 self.bgx2 = self.bgx1 + winLength self.speed = speed def draw(self): if self.bgx1 < (0 - winLength): self.bgx1 = winLength if self.bgx2 < (0 - winLength): self.bgx2 = self.bgx1 + winLength screen.blit(bg, (self.bgx1, 0)) screen.blit(bg, (self.bgx2, 0)) def move(self): self.bgx1 -= self.speed self.bgx2 -= self.speed class Player(object): def __init__(self, x, vel, buffer): self.x = x self.y = 128 self.vel = vel self.buffer = buffer self.count = 0 self.flipped = False self.width = 64 * (14 / 18) def draw(self): if self.count + 1 >= 63: self.count = 0 self.count += 1 if self.flipped is False: screen.blit(char[self.count // 7], (self.x, self.y)) if self.flipped is True: screen.blit(charFlipped[self.count // 7], (self.x, self.y)) def move(self): if self.flipped is False and self.y < winWidth - self.buffer - self.width: self.y += self.vel if self.flipped is True and self.y > self.buffer: self.y -= self.vel class Fireball(object): def __init__(self, x, y): self.x = x self.y = y self.count = 0 self.vel = 2 self.passed = False # Store fireball width for accurate off-screen checks self.width = fireball[0].get_width() def draw(self): if self.count + 1 >= 35: self.count = 0 self.count += 1 screen.blit(fireball[self.count // 7], (self.x, self.y)) def move(self): self.x -= self.vel background = Background(0.5) character = Player(128, 2, 32) # Initialize fireballs list with one starting fireball fireballs = [Fireball(winLength, random.randint(32, winWidth - 32 - fireball[0].get_height()))] # Frame counter to control spawn frequency spawn_counter = 0 spawn_interval = 120 # Spawn new fireball every 120 frames (2 seconds at 60fps) def gameWindow(): background.draw() character.draw() # Draw all active fireballs for fb in fireballs: fb.draw() pygame.display.update() while running: clock.tick(60) keys = pygame.key.get_pressed() for event in pygame.event.get(): if event.type == pygame.QUIT or keys[pygame.K_ESCAPE]: pygame.quit() sys.exit() elif event.type == pygame.MOUSEBUTTONUP: character.flipped = not character.flipped background.move() character.move() # Update fireball positions and remove off-screen ones for fb in fireballs[:]: # Iterate over a copy to safely remove items fb.move() # Remove fireball when its right edge leaves the screen if fb.x + fb.width < 0: fireballs.remove(fb) # Spawn new fireball at regular intervals spawn_counter += 1 if spawn_counter >= spawn_interval: spawn_counter = 0 # Spawn at screen right edge with random vertical position (buffer included) new_y = random.randint(32, winWidth - 32 - fireball[0].get_height()) fireballs.append(Fireball(winLength, new_y)) gameWindow()
Key Changes Explained:
- Fireball List: Replaced the single
meteorvariable with afireballslist to track all active instances, making it easy to manage multiple fireballs. - Random Vertical Spawns: Each new fireball spawns at a random y-position (within a buffer to avoid screen edges), adding challenge like Flappy Bird's pipes.
- Off-Screen Cleanup: We iterate over a copy of the fireballs list so we can safely remove items while looping. A fireball is removed only when its entire width is off the left screen edge.
- Controlled Spawning: The
spawn_counterandspawn_intervalvariables let you adjust how often new fireballs appear—tweakspawn_intervalto make the game easier or harder.
This setup will give you smooth, continuous fireball movement: old fireballs get cleaned up when they're out of view, and new ones spawn automatically to keep the game running!
内容的提问来源于stack exchange,提问作者BambooBlackjack975

