import pygame
import sys
import random
import math
# Initialize pygame
pygame.init()
# Game constants
SCREEN_WIDTH = 800
SCREEN_HEIGHT = 600
GRAVITY = 0.5
JUMP_FORCE = -8
PIPE_SPEED = 3
PIPE_GAP = 200
PIPE_FREQUENCY = 1800 # milliseconds
FLOOR_HEIGHT = 100
BIRD_RADIUS = 20
# Colors
SKY_BLUE = (113, 197, 207)
GREEN = (111, 196, 69)
DARK_GREEN = (76, 145, 65)
BROWN = (160, 120, 40)
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
YELLOW = (255, 221, 45)
ORANGE = (255, 148, 31)
RED = (231, 76, 60)
# Set up display
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
pygame.display.set_caption("Flappy Bird Clone")
clock = pygame.time.Clock()
# Font setup
font = pygame.font.SysFont(None, 48)
small_font = pygame.font.SysFont(None, 32)
class Bird:
def __init__(self):
self.x = SCREEN_WIDTH // 4
self.y = SCREEN_HEIGHT // 2
self.velocity = 0
self.alive = True
self.angle = 0
def jump(self):
self.velocity = JUMP_FORCE
self.angle = -30 # Tilt up when jumping
def update(self):
# Apply gravity
self.velocity += GRAVITY
self.y += self.velocity
# Rotate bird based on velocity
if self.velocity < 0:
self.angle = max(-30, self.angle - 3)
else:
self.angle = min(70, self.angle + 2)
# Floor collision
if self.y >= SCREEN_HEIGHT - FLOOR_HEIGHT - BIRD_RADIUS:
self.y = SCREEN_HEIGHT - FLOOR_HEIGHT - BIRD_RADIUS
self.velocity = 0
self.alive = False
# Ceiling collision
if self.y <= BIRD_RADIUS:
self.y = BIRD_RADIUS
self.velocity = 0
def draw(self):
# Save the current transformation matrix
original_surface = screen.copy()
# Draw the bird body
pygame.draw.circle(screen, YELLOW, (self.x, self.y), BIRD_RADIUS)
# Draw the bird eye
pygame.draw.circle(screen, WHITE, (self.x + 8, self.y - 5), 8)
pygame.draw.circle(screen, BLACK, (self.x + 10, self.y - 5), 4)
# Draw the bird beak
beak_points = [
(self.x + 15, self.y),
(self.x + 35, self.y - 5),
(self.x + 35, self.y + 5)
]
pygame.draw.polygon(screen, ORANGE, beak_points)
# Draw the wing
wing_points = [
(self.x - 10, self.y),
(self.x - 15, self.y - 15),
(self.x, self.y - 5)
]
pygame.draw.polygon(screen, ORANGE, wing_points)
# Create a rotated surface for the bird
rotated_bird = pygame.Surface((BIRD_RADIUS * 2, BIRD_RADIUS * 2), pygame.SRCALPHA)
rotated_bird.blit(screen, (0, 0), (self.x - BIRD_RADIUS, self.y - BIRD_RADIUS, BIRD_RADIUS * 2, BIRD_RADIUS * 2))
rotated_bird = pygame.transform.rotate(rotated_bird, -self.angle)
# Clear the original bird
screen.blit(original_surface, (0, 0))
# Draw the rotated bird
rotated_rect = rotated_bird.get_rect(center=(self.x, self.y))
screen.blit(rotated_bird, rotated_rect)
def get_mask(self):
# Return a simple collision mask (circle)
return pygame.Rect(self.x - BIRD_RADIUS, self.y - BIRD_RADIUS, BIRD_RADIUS * 2, BIRD_RADIUS * 2)
class Pipe:
def __init__(self):
self.x = SCREEN_WIDTH
self.gap_y = random.randint(150, SCREEN_HEIGHT - FLOOR_HEIGHT - 150)
self.width = 70
self.passed = False
def update(self):
self.x -= PIPE_SPEED
def draw(self):
# Draw top pipe
pygame.draw.rect(screen, GREEN, (self.x, 0, self.width, self.gap_y - PIPE_GAP // 2))
pygame.draw.rect(screen, DARK_GREEN, (self.x - 5, self.gap_y - PIPE_GAP // 2 - 20, self.width + 10, 20))
# Draw bottom pipe
pipe_top = self.gap_y + PIPE_GAP // 2
pygame.draw.rect(screen, GREEN, (self.x, pipe_top, self.width, SCREEN_HEIGHT - pipe_top))
pygame.draw.rect(screen, DARK_GREEN, (self.x - 5, pipe_top, self.width + 10, 20))
def collide(self, bird):
bird_mask = bird.get_mask()
# Top pipe collision
top_pipe = pygame.Rect(self.x, 0, self.width, self.gap_y - PIPE_GAP // 2)
# Bottom pipe collision
bottom_pipe = pygame.Rect(self.x, self.gap_y + PIPE_GAP // 2, self.width, SCREEN_HEIGHT)
if bird_mask.colliderect(top_pipe) or bird_mask.colliderect(bottom_pipe):
return True
return False
class Cloud:
def __init__(self):
self.x = SCREEN_WIDTH + random.randint(0, 100)
self.y = random.randint(50, SCREEN_HEIGHT // 2)
self.speed = random.uniform(0.5, 1.5)
self.size = random.randint(40, 80)
def update(self):
self.x -= self.speed
if self.x < -self.size * 2:
self.x = SCREEN_WIDTH + 50
self.y = random.randint(50, SCREEN_HEIGHT // 2)
def draw(self):
# Draw a fluffy cloud
pygame.draw.circle(screen, WHITE, (self.x, self.y), self.size // 2)
pygame.draw.circle(screen, WHITE, (self.x + self.size // 2, self.y - self.size // 4), self.size // 2)
pygame.draw.circle(screen, WHITE, (self.x + self.size // 2, self.y + self.size // 4), self.size // 2)
pygame.draw.circle(screen, WHITE, (self.x + self.size, self.y), self.size // 2)
def draw_floor():
pygame.draw.rect(screen, BROWN, (0, SCREEN_HEIGHT - FLOOR_HEIGHT, SCREEN_WIDTH, FLOOR_HEIGHT))
# Draw grass on top of the floor
pygame.draw.rect(screen, GREEN, (0, SCREEN_HEIGHT - FLOOR_HEIGHT, SCREEN_WIDTH, 20))
# Draw some grass details
for i in range(0, SCREEN_WIDTH, 20):
height = random.randint(5, 15)
pygame.draw.line(screen, DARK_GREEN, (i, SCREEN_HEIGHT - FLOOR_HEIGHT), (i, SCREEN_HEIGHT - FLOOR_HEIGHT - height), 2)
def draw_background():
# Sky
screen.fill(SKY_BLUE)
# Sun
pygame.draw.circle(screen, YELLOW, (700, 80), 50)
# Draw clouds
for cloud in clouds:
cloud.draw()
def draw_game_over(score):
overlay = pygame.Surface((SCREEN_WIDTH, SCREEN_HEIGHT), pygame.SRCALPHA)
overlay.fill((0, 0, 0, 150))
screen.blit(overlay, (0, 0))
game_over_text = font.render("Game Over", True, WHITE)
score_text = font.render(f"Score: {score}", True, WHITE)
restart_text = small_font.render("Press SPACE to Restart", True, WHITE)
screen.blit(game_over_text, (SCREEN_WIDTH // 2 - game_over_text.get_width() // 2, SCREEN_HEIGHT // 2 - 60))
screen.blit(score_text, (SCREEN_WIDTH // 2 - score_text.get_width() // 2, SCREEN_HEIGHT // 2))
screen.blit(restart_text, (SCREEN_WIDTH // 2 - restart_text.get_width() // 2, SCREEN_HEIGHT // 2 + 60))
def draw_score(score):
score_text = font.render(f"Score: {score}", True, WHITE)
screen.blit(score_text, (20, 20))
def draw_start_screen():
screen.fill(SKY_BLUE)
# Title
title_text = font.render("Flappy Bird Clone", True, WHITE)
screen.blit(title_text, (SCREEN_WIDTH // 2 - title_text.get_width() // 2, 100))
# Bird
pygame.draw.circle(screen, YELLOW, (SCREEN_WIDTH // 2, SCREEN_HEIGHT // 2), 40)
pygame.draw.circle(screen, WHITE, (SCREEN_WIDTH // 2 + 15, SCREEN_HEIGHT // 2 - 10), 15)
pygame.draw.circle(screen, BLACK, (SCREEN_WIDTH // 2 + 20, SCREEN_HEIGHT // 2 - 10), 7)
pygame.draw.polygon(screen, ORANGE, [
(SCREEN_WIDTH // 2 + 30, SCREEN_HEIGHT // 2),
(SCREEN_WIDTH // 2 + 60, SCREEN_HEIGHT // 2 - 10),
(SCREEN_WIDTH // 2 + 60, SCREEN_HEIGHT // 2 + 10)
])
# Instructions
instruction_text = small_font.render("Press SPACE to Start", True, WHITE)
screen.blit(instruction_text, (SCREEN_WIDTH // 2 - instruction_text.get_width() // 2, SCREEN_HEIGHT - 150))
# Draw some pipes
pipe_width = 70
pipe_gap = 200
gap_y = SCREEN_HEIGHT // 2
# Left pipe
pygame.draw.rect(screen, GREEN, (SCREEN_WIDTH // 2 - 200, 0, pipe_width, gap_y - pipe_gap // 2))
pygame.draw.rect(screen, DARK_GREEN, (SCREEN_WIDTH // 2 - 205, gap_y - pipe_gap // 2 - 20, pipe_width + 10, 20))
pygame.draw.rect(screen, GREEN, (SCREEN_WIDTH // 2 - 200, gap_y + pipe_gap // 2, pipe_width, SCREEN_HEIGHT))
pygame.draw.rect(screen, DARK_GREEN, (SCREEN_WIDTH // 2 - 205, gap_y + pipe_gap // 2, pipe_width + 10, 20))
# Right pipe
pygame.draw.rect(screen, GREEN, (SCREEN_WIDTH // 2 + 130, 0, pipe_width, gap_y - pipe_gap // 2))
pygame.draw.rect(screen, DARK_GREEN, (SCREEN_WIDTH // 2 + 125, gap_y - pipe_gap // 2 - 20, pipe_width + 10, 20))
pygame.draw.rect(screen, GREEN, (SCREEN_WIDTH // 2 + 130, gap_y + pipe_gap // 2, pipe_width, SCREEN_HEIGHT))
pygame.draw.rect(screen, DARK_GREEN, (SCREEN_WIDTH // 2 + 125, gap_y + pipe_gap // 2, pipe_width + 10, 20))
# Draw floor
draw_floor()
# Game setup
bird = Bird()
pipes = []
clouds = [Cloud() for _ in range(5)]
score = 0
game_state = "start" # "start", "playing", "game_over"
last_pipe = pygame.time.get_ticks()
# Main game loop
while True:
# Event handling
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
if game_state == "start":
game_state = "playing"
elif game_state == "playing":
bird.jump()
elif game_state == "game_over":
# Reset game
bird = Bird()
pipes = []
score = 0
game_state = "playing"
last_pipe = pygame.time.get_ticks()
# Draw background
draw_background()
# Update and draw clouds
for cloud in clouds:
cloud.update()
cloud.draw()
# Draw floor
draw_floor()
if game_state == "start":
draw_start_screen()
elif game_state == "playing":
# Update bird
bird.update()
# Generate new pipes
current_time = pygame.time.get_ticks()
if current_time - last_pipe > PIPE_FREQUENCY:
pipes.append(Pipe())
last_pipe = current_time
# Update pipes and check for score
for pipe in pipes:
pipe.update()
# Check if bird passed the pipe
if not pipe.passed and pipe.x + pipe.width < bird.x:
pipe.passed = True
score += 1
# Check for collisions
if pipe.collide(bird):
bird.alive = False
game_state = "game_over"
# Remove pipes that are off screen
pipes = [pipe for pipe in pipes if pipe.x > -pipe.width]
# Draw pipes
for pipe in pipes:
pipe.draw()
# Draw bird
bird.draw()
# Draw score
draw_score(score)
# Check if bird hit the ground or ceiling
if not bird.alive:
game_state = "game_over"
elif game_state == "game_over":
# Draw pipes
for pipe in pipes:
pipe.draw()
# Draw bird
bird.draw()
# Draw score
draw_score(score)
# Draw game over screen
draw_game_over(score)
# Update display
pygame.display.flip()
# Cap the frame rate
clock.tick(60)
Comments
Post a Comment