最终汇总
WIDTH = 360
HEIGHT = 640
FPS = 60
SKY_COLOR = (135, 206, 235)
BIRD_COLOR = (255, 255, 0)
PIPE_COLOR = (0, 200, 0)
BIRD_X = 80
BIRD_WIDTH = 30
BIRD_HEIGHT = 30
GRAVITY = 0.5
JUMP_STRENGTH = -8
PIPE_WIDTH = 70
PIPE_GAP = 180
PIPE_SPEED = 4
PIPE_SPAWN_INTERVAL = 90
STATE_WAITING = "waiting"
STATE_PLAYING = "playing"
STATE_GAME_OVER = "game_over"
sprite.py
import pygame
import tool
class Bird(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
self.image = pygame.Surface((tool.BIRD_WIDTH, tool.BIRD_HEIGHT))
self.image.fill(tool.BIRD_COLOR)
self.rect = self.image.get_rect()
self.rect.x = tool.BIRD_X
self.rect.y = tool.HEIGHT // 2
self.velocity = 0
def jump(self):
self.velocity = tool.JUMP_STRENGTH
def update(self):
self.velocity += tool.GRAVITY
self.rect.y += self.velocity
if self.rect.top < 0:
self.rect.top = 0
self.velocity = 0
if self.rect.bottom > tool.HEIGHT:
self.rect.bottom = tool.HEIGHT
return True
return False
def reset(self):
self.rect.y = tool.HEIGHT // 2
self.velocity = 0
class Pipe(pygame.sprite.Sprite):
def __init__(self, x, y, width, height, is_top=False):
super().__init__()
self.image = pygame.Surface((width, height))
self.image.fill(tool.PIPE_COLOR)
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
self.is_top = is_top
self.scored = False
def update(self):
self.rect.x -= tool.PIPE_SPEED
def off_screen(self):
return self.rect.right < 0
screen.py
import pygame
import sys
import random
import tool
from sprite import Bird, Pipe
class Game:
def __init__(self):
pygame.init()
self.screen = pygame.display.set_mode((tool.WIDTH, tool.HEIGHT))
pygame.display.set_caption("Flappy Bird")
self.clock = pygame.time.Clock()
self.font = pygame.font.Font(None, 40)
self.all_sprites = pygame.sprite.Group()
self.pipe_group = pygame.sprite.Group()
self.bird = Bird()
self.all_sprites.add(self.bird)
self.spawn_timer = 0
self.score = 0
self.state = tool.STATE_WAITING
self.running = True
def reset(self):
self.bird.reset()
self.pipe_group.empty()
for s in list(self.all_sprites):
if isinstance(s, Pipe):
s.kill()
self.spawn_timer = 0
self.score = 0
self.state = tool.STATE_WAITING
def handle_events(self):
for event in pygame.event.get():
if event.type == pygame.QUIT:
self.running = False
elif event.type == pygame.KEYDOWN:
if event.key in (pygame.K_SPACE, pygame.K_w, pygame.K_UP):
self.handle_action()
elif event.type == pygame.MOUSEBUTTONDOWN:
self.handle_action()
def handle_action(self):
if self.state == tool.STATE_WAITING:
self.state = tool.STATE_PLAYING
self.bird.jump()
elif self.state == tool.STATE_PLAYING:
self.bird.jump()
elif self.state == tool.STATE_GAME_OVER:
self.reset()
def spawn_pipe(self):
gap_y = random.randint(80, tool.HEIGHT - tool.PIPE_GAP - 80)
top = Pipe(tool.WIDTH, 0, tool.PIPE_WIDTH, gap_y, is_top=True)
bottom = Pipe(tool.WIDTH, gap_y + tool.PIPE_GAP,
tool.PIPE_WIDTH, tool.HEIGHT - (gap_y + tool.PIPE_GAP))
self.all_sprites.add(top, bottom)
self.pipe_group.add(top, bottom)
def update(self):
if self.state != tool.STATE_PLAYING:
return
if self.bird.update():
self.state = tool.STATE_GAME_OVER
return
self.spawn_timer += 1
if self.spawn_timer > tool.PIPE_SPAWN_INTERVAL:
self.spawn_timer = 0
self.spawn_pipe()
self.all_sprites.update()
for pipe in list(self.pipe_group):
if pipe.off_screen():
pipe.kill()
if pygame.sprite.spritecollide(self.bird, self.pipe_group, False):
self.state = tool.STATE_GAME_OVER
return
for pipe in self.pipe_group:
if pipe.is_top and not pipe.scored and pipe.rect.right < self.bird.rect.left:
pipe.scored = True
self.score += 1
def draw(self):
self.screen.fill(tool.SKY_COLOR)
self.all_sprites.draw(self.screen)
score_text = self.font.render(str(self.score), True, (255, 255, 255))
self.screen.blit(score_text, (tool.WIDTH // 2, 40))
if self.state == tool.STATE_WAITING:
title = self.font.render("Flappy Bird", True, (255, 255, 255))
hint = self.font.render("Press SPACE to Start", True, (255, 255, 255))
self.screen.blit(title, (tool.WIDTH//2 - title.get_width()//2, tool.HEIGHT//2 - 60))
self.screen.blit(hint, (tool.WIDTH//2 - hint.get_width()//2, tool.HEIGHT//2 + 10))
elif self.state == tool.STATE_GAME_OVER:
over = self.font.render("Game Over", True, (255, 0, 0))
hint = self.font.render("Press SPACE to Restart", True, (255, 255, 255))
self.screen.blit(over, (tool.WIDTH//2 - over.get_width()//2, tool.HEIGHT//2 - 60))
self.screen.blit(hint, (tool.WIDTH//2 - hint.get_width()//2, tool.HEIGHT//2 + 10))
pygame.display.flip()
def run(self):
while self.running:
self.handle_events()
self.update()
self.draw()
self.clock.tick(tool.FPS)
pygame.quit()
sys.exit()
main.py
from screen import Game
if __name__ == "__main__":
game = Game()
game.run()
pyinstaller -F -w main.py