Code for How to Make a Flappy Bird Game in Python Tutorial


View on Github

pipe.py

import pygame

class Pipe(pygame.sprite.Sprite):
	def __init__(self, pos, width, height, flip):
		super().__init__()
		self.width = width
		img_path = 'assets/terrain/pipe.png'
		self.image = pygame.image.load(img_path)
		self.image = pygame.transform.scale(self.image, (width, height))
		if flip:
			flipped_image = pygame.transform.flip(self.image, False, True)
			self.image = flipped_image
		self.rect = self.image.get_rect(topleft = pos)

	# update object position due to world scroll
	def update(self, x_shift):
		self.rect.x += x_shift

		# removes the pipe in the game screen once it is not shown in the screen anymore
		if self.rect.right < (-self.width):
			self.kill()

game.py

import pygame
from settings import WIDTH, HEIGHT

pygame.font.init()

class GameIndicator:
	def __init__(self, screen):
		self.screen = screen
		self.font = pygame.font.SysFont('Bauhaus 93', 60)
		self.inst_font = pygame.font.SysFont('Bauhaus 93', 30)
		self.color = pygame.Color("white")
		self.inst_color = pygame.Color("black")

	def show_score(self, int_score):
		bird_score = str(int_score)
		score = self.font.render(bird_score, True, self.color)
		self.screen.blit(score, (WIDTH // 2, 50))

	def instructions(self):
		inst_text1 = "Press SPACE button to Jump,"
		inst_text2 = "Press \"R\" Button to Restart Game."
		ins1 = self.inst_font.render(inst_text1, True, self.inst_color)
		ins2 = self.inst_font.render(inst_text2, True, self.inst_color)
		self.screen.blit(ins1, (95, 400))
		self.screen.blit(ins2, (70, 450))

settings.py

from os import walk
import pygame

WIDTH, HEIGHT = 600, 650

pipe_pair_sizes = [
	(1, 7),
	(2, 6),
	(3, 5),
	(4, 4),
	(5, 3),
	(6, 2),
	(7, 1)
]
pipe_size = HEIGHT // 10
pipe_gap = (pipe_size * 2) + (pipe_size // 2)
ground_space = 50

def import_sprite(path):
	surface_list = []
	for _, __, img_file in walk(path):
		for image in img_file:
			full_path = f"{path}/{image}"
			img_surface = pygame.image.load(full_path).convert_alpha()
			surface_list.append(img_surface)
	return surface_list

main.py

import pygame, sys
from settings import WIDTH, HEIGHT, ground_space
from world import World

pygame.init()

screen = pygame.display.set_mode((WIDTH, HEIGHT + ground_space))
pygame.display.set_caption("Flappy Bird")

class Main:
	def __init__(self, screen):
		self.screen = screen
		self.bg_img = pygame.image.load('assets/terrain/bg.png')
		self.bg_img = pygame.transform.scale(self.bg_img, (WIDTH, HEIGHT))
		self.ground_img = pygame.image.load('assets/terrain/ground.png')
		self.ground_scroll = 0
		self.scroll_speed = -6
		self.FPS = pygame.time.Clock()
		self.stop_ground_scroll = False

	def main(self):
		world = World(screen)
		while True:
			self.stop_ground_scroll = world.game_over
			self.screen.blit(self.bg_img, (0, 0))

			for event in pygame.event.get():
				if event.type == pygame.QUIT:
					pygame.quit()
					sys.exit()

				elif event.type == pygame.KEYDOWN:
					if not world.playing and not world.game_over:
						world.playing = True
					if event.key == pygame.K_SPACE:
						world.update("jump")
					if event.key == pygame.K_r:
						world.update("restart")

			world.update()

			self.screen.blit(self.ground_img, (self.ground_scroll, HEIGHT))
			if not self.stop_ground_scroll:
				self.ground_scroll += self.scroll_speed
				if abs(self.ground_scroll) > 35:
					self.ground_scroll = 0

			pygame.display.update()
			self.FPS.tick(60)

if __name__ == "__main__":
	play = Main(screen)
	play.main()

bird.py

import pygame
from settings import import_sprite

class Bird(pygame.sprite.Sprite):
	def __init__(self, pos, size):
		super().__init__()
		# bird basic info
		self.frame_index = 0
		self.animation_delay = 3
		self.jump_move = -9

		# bird animation
		self.bird_img = import_sprite("assets/bird")
		self.image = self.bird_img[self.frame_index]
		self.image = pygame.transform.scale(self.image, (size, size))
		self.rect = self.image.get_rect(topleft = pos)
		self.mask = pygame.mask.from_surface(self.image)

		# bird status
		self.direction = pygame.math.Vector2(0, 0)
		self.score = 0

	# for bird's flying animation
	def _animate(self):
		sprites = self.bird_img
		sprite_index = (self.frame_index // self.animation_delay) % len(sprites)
		self.image = sprites[sprite_index]
		self.frame_index += 1
		self.rect = self.image.get_rect(topleft=(self.rect.x, self.rect.y))
		self.mask = pygame.mask.from_surface(self.image)
		if self.frame_index // self.animation_delay > len(sprites):
			self.frame_index = 0

	# to make the bird fly higher
	def _jump(self):
		self.direction.y = self.jump_move

	# updates the bird's overall state
	def update(self, is_jump):
		if is_jump:
			self._jump()
		self._animate()

world.py

import pygame
from pipe import Pipe
from bird import Bird
from game import GameIndicator
from settings import WIDTH, HEIGHT, pipe_size, pipe_gap, pipe_pair_sizes
import random

class World:
	def __init__(self, screen):
		self.screen = screen
		self.world_shift = 0
		self.current_x = 0
		self.gravity = 0.5
		self.current_pipe = None
		self.pipes = pygame.sprite.Group()
		self.player = pygame.sprite.GroupSingle()
		self._generate_world()
		self.playing = False
		self.game_over = False
		self.passed = True
		self.game = GameIndicator(screen)

	# creates the player and the obstacle
	def _generate_world(self):
		self._add_pipe()
		bird = Bird((WIDTH//2 - pipe_size, HEIGHT//2 - pipe_size), 30)
		self.player.add(bird)

	# adds pipe once the last pipe added reached the desired pipe horizontal spaces
	def _add_pipe(self):
		pipe_pair_size = random.choice(pipe_pair_sizes)
		top_pipe_height, bottom_pipe_height = pipe_pair_size[0] * pipe_size, pipe_pair_size[1] * pipe_size

		pipe_top = Pipe((WIDTH, 0 - (bottom_pipe_height + pipe_gap)), pipe_size, HEIGHT, True)
		pipe_bottom = Pipe((WIDTH, top_pipe_height + pipe_gap), pipe_size, HEIGHT, False)
		self.pipes.add(pipe_top)
		self.pipes.add(pipe_bottom)
		self.current_pipe = pipe_top

	# for moving background/obstacle
	def _scroll_x(self):
		if self.playing:
			self.world_shift = -6
		else:
			self.world_shift = 0

	# add gravity to bird for falling
	def _apply_gravity(self, player):
		if self.playing or self.game_over:
			player.direction.y += self.gravity
			player.rect.y += player.direction.y

	# handles scoring and collision
	def _handle_collisions(self):
		bird = self.player.sprite
		# for collision checking
		if pygame.sprite.groupcollide(self.player, self.pipes, False, False) or bird.rect.bottom >= HEIGHT or bird.rect.top <= 0:
			self.playing = False
			self.game_over = True
		else:
			# if player pass through the pipe gaps
			bird = self.player.sprite
			if bird.rect.x >= self.current_pipe.rect.centerx:
				bird.score += 1
				self.passed = True

	# updates the bird's overall state
	def update(self, player_event = None):
		# new pipe adder
		if self.current_pipe.rect.centerx  <= (WIDTH // 2) - pipe_size:
			self._add_pipe()
		
		# updates, draws pipes
		self.pipes.update(self.world_shift)
		self.pipes.draw(self.screen)

		# applying game physics
		self._apply_gravity(self.player.sprite)
		self._scroll_x()
		self._handle_collisions()

		# configuring player actions
		if player_event == "jump" and not self.game_over:
			player_event = True
		elif player_event == "restart":
			self.game_over = False
			self.pipes.empty()
			self.player.empty()
			self.player.score = 0
			self._generate_world()
		else:
			player_event = False

		if not self.playing:
			self.game.instructions()

		# updates, draws pipes
		self.player.update(player_event)
		self.player.draw(self.screen)

		self.game.show_score(self.player.sprite.score)


pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy