Menu
CoddyTech

Hit Stop

Part of the Sound and Game Feel section of Coddy's Pygame journey. Lesson 14 of 23.

A big hit lands harder if the game stops for a split second. Fighting and action games do it all the time: on a strong blow, everything freezes for a few frames, then goes on. It is called hit stop.

Use a counter again, the frames left to freeze. While it is above 0, count it down and skip the whole update. Keep drawing, so the frozen moment stays on the screen:

if freeze > 0:
    freeze -= 1
else:
    enemy.x += enemy_speed
    # ... the rest of the update

Set it only on the hits that matter. Here the third hit defeats the enemy, so that hit sets freeze = 12, a fifth of a second. Freezing on every small hit makes a game feel sticky instead of strong.

The flash counter is part of the update, so it waits too: the enemy stays white for the whole freeze, the explosion sound rings, and then the game goes on. Events still run during the freeze, so a player who presses a key then is not ignored; here Space only hits while hp > 0.

challenge icon

Challenge

Medium

The enemy walks left and right; three hits with Space defeat it. Freeze the game on the defeating hit:

  1. Make freeze = 0 before the loop.
  2. Where the hit brings hp to 0, set freeze = 12.
  3. In the update, while freeze is above 0, lower it by 1 and skip everything else in the update. Keep the drawing as it is.

Try it yourself

import pygame

pygame.init()
screen = pygame.display.set_mode((480, 360))
pygame.display.set_caption("Training Dummy")
clock = pygame.time.Clock()
font = pygame.font.Font(None, 32)

hit_sound = pygame.mixer.Sound("assets/sounds/hit.ogg")
explosion_sound = pygame.mixer.Sound("assets/sounds/explosion.ogg")
enemy = pygame.Rect(100, 150, 60, 60)
enemy_speed = 2
hp = 3
flash = 0
defeated = 0

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 and hp > 0:
            hp -= 1
            flash = 6
            if hp == 0:
                explosion_sound.play()
            else:
                hit_sound.play()

    enemy.x += enemy_speed
    if enemy.left < 40 or enemy.right > 440:
        enemy_speed = -enemy_speed
    if flash > 0:
        flash -= 1
    if hp == 0:
        defeated += 1
        hp = 3
        enemy.x = 100

    screen.fill((30, 30, 46))
    if flash > 0:
        pygame.draw.rect(screen, (255, 255, 255), enemy)
    else:
        pygame.draw.rect(screen, (220, 80, 80), enemy)
    label = font.render(f"HP: {hp}   Defeated: {defeated}", True, (240, 240, 240))
    screen.blit(label, (20, 20))
    pygame.display.flip()
    clock.tick(60)

pygame.quit()

All lessons in Sound and Game Feel

Practice on your own: Pygame playground