Menu
CoddyTech

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 icon

Challenge

Medium

Space drops crates, and each landing adds 12 to shake. Tone it down:

  1. Change the landing so shake never goes above 18: shake = min(shake + 12, 18).
  2. Make shake_on = True before the loop; S flips it.
  3. Pick a random offset only while shake_on is true.
  4. After blitting the world, draw Shake: On or Shake: Off on 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()
quiz iconTest yourself

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