Keep It Subtle
Part of the Sound and Game Feel section of Coddy's Pygame journey. Lesson 15 of 23.
Game feel is seasoning. A little shake makes a landing heavy; a lot makes the game hard to read and can make players feel sick. Two habits keep it in check.
Cap it. When effects stack, they can grow without end. Here every landing adds 12 to shake; four crates landing together push it past 40, and the view jumps 13 pixels. min() puts a ceiling on it:
shake = min(shake + 12, 18)Now the shake still lasts longer when crates keep landing, but it never moves more than 18 // 3, 6 pixels.
Let players turn it off. Some people cannot play with the screen moving. A setting costs one variable:
shake_on = True
...
if shake_on:
offset = (random.randint(-amount, amount), random.randint(-amount, amount))Draw the label after you blit the world, straight on the screen. Text that is part of the interface should stay still while the world shakes.
Challenge
MediumSpace drops crates, and each landing adds 12 to shake. Tone it down:
- Change the landing so
shakenever goes above 18:shake = min(shake + 12, 18). - Make
shake_on = Truebefore the loop; S flips it. - Pick a random offset only while
shake_onis true. - After blitting the world, draw
Shake: OnorShake: Offon the screen at(10, 10).
Try it yourself
import random
import pygame
pygame.init()
screen = pygame.display.set_mode((480, 360))
pygame.display.set_caption("Crate Drop")
clock = pygame.time.Clock()
font = pygame.font.Font(None, 28)
thud_sound = pygame.mixer.Sound("assets/sounds/thud.ogg")
falling = []
landed = []
shake = 0
world = pygame.Surface((480, 360))
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.KEYDOWN and event.key == pygame.K_SPACE:
falling.append(pygame.Rect(random.randint(140, 400), -40, 40, 40))
for crate in falling:
crate.y += 8
if crate.bottom >= 300:
crate.bottom = 300
landed.append(crate)
thud_sound.play()
shake += 12
falling = [crate for crate in falling if crate.bottom < 300]
world.fill((30, 30, 46))
pygame.draw.rect(world, (80, 80, 100), (0, 300, 480, 60))
pygame.draw.rect(world, (80, 160, 255), (60, 220, 30, 80))
for crate in falling + landed:
pygame.draw.rect(world, (170, 110, 60), crate)
offset = (0, 0)
if shake > 0:
amount = shake // 3
offset = (random.randint(-amount, amount), random.randint(-amount, amount))
shake -= 1
screen.fill((0, 0, 0))
screen.blit(world, offset)
pygame.display.flip()
clock.tick(60)
pygame.quit()
This lesson includes a short quiz. Start the lesson to answer it and track your progress.
All lessons in Sound and Game Feel
Practice on your own: Pygame playground