Skip to content

Commit ac1f0b4

Browse files
committed
add 'adding sound effects to python games' tutorial
1 parent 3f5682c commit ac1f0b4

File tree

18 files changed

+269
-0
lines changed

18 files changed

+269
-0
lines changed

README.md

+1
Original file line numberDiff line numberDiff line change
@@ -340,6 +340,7 @@ This is a repository of all the tutorials of [The Python Code](https://www.thepy
340340
- [How to Create a Space Invaders Game in Python](https://thepythoncode.com/article/make-a-space-invader-game-in-python). ([code](gui-programming/space-invaders-game))
341341
- [How to Build a Sudoku Game with Python](https://thepythoncode.com/article/make-a-sudoku-game-in-python). ([code](gui-programming/sudoku-game))
342342
- [How to Make a Pacman Game with Python](https://thepythoncode.com/article/creating-pacman-game-with-python). ([code](gui-programming/pacman-game))
343+
- [How to Add Sound Effects to your Python Game](https://thepythoncode.com/article/add-sound-effects-to-python-game-with-pygame). ([code](gui-programming/adding-sound-effects-to-games))
343344

344345

345346
For any feedback, please consider pulling requests.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# [How to Add Sound Effects to your Python Game](https://thepythoncode.com/article/add-sound-effects-to-python-game-with-pygame)
Loading
Loading
Loading
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading
Loading
Loading
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import pygame
2+
from settings import import_sprite
3+
4+
class Bird(pygame.sprite.Sprite):
5+
def __init__(self, pos, size):
6+
super().__init__()
7+
# bird basic info
8+
self.frame_index = 0
9+
self.animation_delay = 3
10+
self.jump_move = -8
11+
12+
# bird animation
13+
self.bird_img = import_sprite("assets/bird")
14+
self.image = self.bird_img[self.frame_index]
15+
self.image = pygame.transform.scale(self.image, (size, size))
16+
self.rect = self.image.get_rect(topleft = pos)
17+
self.mask = pygame.mask.from_surface(self.image)
18+
19+
# bird status
20+
self.direction = pygame.math.Vector2(0, 0)
21+
self.score = 0
22+
23+
# for bird's flying animation
24+
def _animate(self):
25+
sprites = self.bird_img
26+
sprite_index = (self.frame_index // self.animation_delay) % len(sprites)
27+
self.image = sprites[sprite_index]
28+
self.frame_index += 1
29+
self.rect = self.image.get_rect(topleft=(self.rect.x, self.rect.y))
30+
self.mask = pygame.mask.from_surface(self.image)
31+
if self.frame_index // self.animation_delay > len(sprites):
32+
self.frame_index = 0
33+
34+
# to make the bird fly higher
35+
def _jump(self):
36+
self.direction.y = self.jump_move
37+
whoosh = pygame.mixer.Sound("assets/sfx/whoosh.mp3")
38+
whoosh.set_volume(0.5)
39+
whoosh.play()
40+
41+
# updates the bird's overall state
42+
def update(self, is_jump):
43+
if is_jump:
44+
self._jump()
45+
self._animate()
46+
# print(self.score)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import pygame
2+
from settings import WIDTH, HEIGHT
3+
4+
pygame.font.init()
5+
6+
class GameIndicator:
7+
def __init__(self, screen):
8+
self.screen = screen
9+
self.font = pygame.font.SysFont('Bauhaus 93', 60)
10+
self.inst_font = pygame.font.SysFont('Bauhaus 93', 30)
11+
self.color = pygame.Color("white")
12+
self.inst_color = pygame.Color("black")
13+
14+
def show_score(self, int_score):
15+
bird_score = str(int_score)
16+
score = self.font.render(bird_score, True, self.color)
17+
self.screen.blit(score, (WIDTH // 2, 50))
18+
19+
def instructions(self):
20+
inst_text1 = "Press SPACE button to Jump,"
21+
inst_text2 = "Press \"R\" Button to Restart Game."
22+
ins1 = self.inst_font.render(inst_text1, True, self.inst_color)
23+
ins2 = self.inst_font.render(inst_text2, True, self.inst_color)
24+
self.screen.blit(ins1, (95, 400))
25+
self.screen.blit(ins2, (70, 450))
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import pygame, sys
2+
from settings import WIDTH, HEIGHT
3+
from world import World
4+
5+
pygame.init()
6+
7+
screen = pygame.display.set_mode((WIDTH, HEIGHT))
8+
pygame.display.set_caption("Flappy Bird")
9+
10+
class Main:
11+
def __init__(self, screen):
12+
self.screen = screen
13+
self.bg_img = pygame.image.load('assets/terrain/bg.png')
14+
self.bg_img = pygame.transform.scale(self.bg_img, (WIDTH, HEIGHT))
15+
self.FPS = pygame.time.Clock()
16+
17+
def main(self):
18+
pygame.mixer.music.load("assets/sfx/bgm.wav")
19+
pygame.mixer.music.play(-1)
20+
pygame.mixer.music.set_volume(0.8)
21+
world = World(screen)
22+
while True:
23+
self.screen.blit(self.bg_img, (0, 0))
24+
25+
for event in pygame.event.get():
26+
if event.type == pygame.QUIT:
27+
pygame.quit()
28+
sys.exit()
29+
30+
elif event.type == pygame.KEYDOWN:
31+
if not world.playing and not world.game_over:
32+
world.playing = True
33+
if event.key == pygame.K_SPACE:
34+
world.update("jump")
35+
if event.key == pygame.K_r:
36+
world.update("restart")
37+
38+
world.update()
39+
pygame.display.update()
40+
self.FPS.tick(60)
41+
42+
if __name__ == "__main__":
43+
play = Main(screen)
44+
play.main()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import pygame
2+
3+
class Pipe(pygame.sprite.Sprite):
4+
def __init__(self, pos, width, height, flip):
5+
super().__init__()
6+
self.width = width
7+
img_path = 'assets/terrain/pipe.png'
8+
self.image = pygame.image.load(img_path)
9+
self.image = pygame.transform.scale(self.image, (width, height))
10+
if flip:
11+
flipped_image = pygame.transform.flip(self.image, False, True)
12+
self.image = flipped_image
13+
self.rect = self.image.get_rect(topleft = pos)
14+
15+
# update object position due to world scroll
16+
def update(self, x_shift):
17+
self.rect.x += x_shift
18+
19+
# removes the pipe in the game screen once it is not shown in the screen anymore
20+
if self.rect.right < (-self.width):
21+
self.kill()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
pygame==2.5.2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
WIDTH, HEIGHT = 600, 680
2+
3+
pipe_pair_sizes = [
4+
(1, 7),
5+
(2, 6),
6+
(3, 5),
7+
(4, 4),
8+
(5, 3),
9+
(6, 2),
10+
(7, 1)
11+
]
12+
pipe_size = HEIGHT // 10
13+
pipe_gap = (pipe_size * 2) + (pipe_size // 2)
14+
15+
from os import walk
16+
import pygame
17+
18+
def import_sprite(path):
19+
surface_list = []
20+
for _, __, img_file in walk(path):
21+
for image in img_file:
22+
full_path = f"{path}/{image}"
23+
img_surface = pygame.image.load(full_path).convert_alpha()
24+
surface_list.append(img_surface)
25+
return surface_list
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
import pygame
2+
from pipe import Pipe
3+
from bird import Bird
4+
from game import GameIndicator
5+
from settings import WIDTH, HEIGHT, pipe_size, pipe_gap, pipe_pair_sizes
6+
import random
7+
8+
class World:
9+
def __init__(self, screen):
10+
self.screen = screen
11+
self.world_shift = 0
12+
self.current_x = 0
13+
self.gravity = 0.5
14+
self.current_pipe = None
15+
self.pipes = pygame.sprite.Group()
16+
self.player = pygame.sprite.GroupSingle()
17+
self._generate_world()
18+
self.playing = False
19+
self.game_over = False
20+
self.passed = True
21+
self.game = GameIndicator(screen)
22+
23+
# creates the player and the obstacle
24+
def _generate_world(self):
25+
self._add_pipe()
26+
bird = Bird((WIDTH//2 - pipe_size, HEIGHT//2 - pipe_size), 30)
27+
self.player.add(bird)
28+
29+
# adds pipe once the last pipe added reached the desired pipe horizontal spaces
30+
def _add_pipe(self):
31+
pipe_pair_size = random.choice(pipe_pair_sizes)
32+
top_pipe_height, bottom_pipe_height = pipe_pair_size[0] * pipe_size, pipe_pair_size[1] * pipe_size
33+
34+
pipe_top = Pipe((WIDTH, 0 - (bottom_pipe_height + pipe_gap)), pipe_size, HEIGHT, True)
35+
pipe_bottom = Pipe((WIDTH, top_pipe_height + pipe_gap), pipe_size, HEIGHT, False)
36+
self.pipes.add(pipe_top)
37+
self.pipes.add(pipe_bottom)
38+
self.current_pipe = pipe_top
39+
40+
# for moving background/obstacle
41+
def _scroll_x(self):
42+
if self.playing:
43+
self.world_shift = -6
44+
else:
45+
self.world_shift = 0
46+
47+
# add gravity to bird for falling
48+
def _apply_gravity(self, player):
49+
if self.playing or self.game_over:
50+
player.direction.y += self.gravity
51+
player.rect.y += player.direction.y
52+
53+
# handles scoring and collision
54+
def _handle_collisions(self):
55+
bird = self.player.sprite
56+
# for collision checking
57+
if pygame.sprite.groupcollide(self.player, self.pipes, False, False) or bird.rect.bottom >= HEIGHT or bird.rect.top <= 0:
58+
if self.playing:
59+
hit = pygame.mixer.Sound("assets/sfx/hit.wav")
60+
hit.set_volume(0.7)
61+
hit.play()
62+
self.playing = False
63+
self.game_over = True
64+
# for scoring
65+
else:
66+
bird = self.player.sprite
67+
if bird.rect.x >= self.current_pipe.rect.centerx:
68+
bird.score += 1
69+
self.passed = True
70+
71+
# updates the bird's overall state
72+
def update(self, player_event = None):
73+
# new pipe adder
74+
if self.current_pipe.rect.centerx <= (WIDTH // 2) - pipe_size:
75+
self._add_pipe()
76+
77+
# updates, draws pipes
78+
self.pipes.update(self.world_shift)
79+
self.pipes.draw(self.screen)
80+
81+
# applying game physics
82+
self._apply_gravity(self.player.sprite)
83+
self._scroll_x()
84+
self._handle_collisions()
85+
86+
# configuring player actions
87+
if player_event == "jump" and not self.game_over:
88+
player_event = True
89+
elif player_event == "restart":
90+
self.game_over = False
91+
self.pipes.empty()
92+
self.player.empty()
93+
self.player.score = 0
94+
self._generate_world()
95+
else:
96+
player_event = False
97+
98+
if not self.playing:
99+
self.game.instructions()
100+
101+
# updates, draws pipes
102+
self.player.update(player_event)
103+
self.player.draw(self.screen)
104+
105+
self.game.show_score(self.player.sprite.score)

0 commit comments

Comments
 (0)