You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Pygame中实现火球完整跨屏移动?Flappy Bird类游戏开发问题

Fixing Full-Screen Fireball Movement in Your Pygame Flappy Bird Clone

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 meteor variable with a fireballs list 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_counter and spawn_interval variables let you adjust how often new fireballs appear—tweak spawn_interval to 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.09 16:07:29