Files
BreakEscape/docs/BREATHING_ANIMATIONS.md
Z. Cliffe Schreuders fb6e9b603c Enhance character sprite loading and animation handling
- Updated the game to support new character sprite atlases for both male and female characters, allowing for a wider variety of NPC designs.
- Improved player sprite initialization to dynamically select between atlas-based and legacy sprites, enhancing flexibility in character representation.
- Refined collision box settings based on sprite type, ensuring accurate physics interactions for both atlas (80x80) and legacy (64x64) sprites.
- Enhanced NPC behavior to utilize atlas animations, allowing for more fluid and diverse animations based on available frames.

Files modified:
- game.js: Added new character atlases and updated sprite loading logic.
- player.js: Improved player sprite handling and collision box adjustments.
- npc-behavior.js: Updated animation handling for NPCs to support atlas-based animations.
- npc-sprites.js: Enhanced NPC sprite creation to accommodate atlas detection and initial frame selection.
- scenario.json.erb: Updated player and NPC configurations to utilize new sprite sheets and animation settings.
- m01_npc_sarah.ink: Revised dialogue options to include new interactions related to NPCs.
2026-02-11 00:18:21 +00:00

7.2 KiB
Raw Blame History

Breathing Idle Animations

Overview

The PixelLab atlas sprites include "breathing-idle" animations that provide a subtle breathing effect when characters are standing still. These animations have been integrated into the game's idle state for both player and NPCs.

Animation Details

Frame Count

  • Breathing-idle: 4 frames per direction
  • Directions: All 8 directions (up, down, left, right, and 4 diagonals)
  • Total frames per character: 32 frames (4 frames × 8 directions)

Frame Rate Configuration

The breathing animation frame rate has been optimized for a natural, subtle breathing effect:

Animation Type Frame Rate Cycle Duration Notes
Idle (Breathing) 6 fps ~0.67 seconds Slower for natural breathing
Walk 10 fps ~0.6 seconds Faster for smooth walking
Attack 8 fps Variable Standard action speed

Why 6 fps for Breathing?

With 4 frames at 6 fps:

  • One complete breathing cycle = 4 frames ÷ 6 fps = 0.67 seconds
  • ~90 breaths per minute (realistic resting rate)
  • Subtle and natural-looking
  • Not distracting during gameplay

Implementation

Atlas Mapping

The system automatically maps PixelLab animations to game animations:

// Atlas format: "breathing-idle_east"
// Game format: "idle-right" (player) or "npc-{id}-idle-right" (NPCs)

const animTypeMap = {
    'breathing-idle': 'idle',  // ← Breathing animation mapped to idle
    'walk': 'walk',
    'cross-punch': 'attack',
    'lead-jab': 'jab',
    'falling-back-death': 'death'
};

Player System

File: js/core/player.js

function createAtlasPlayerAnimations(spriteSheet) {
    const playerConfig = window.scenarioConfig?.player?.spriteConfig || {};
    const idleFrameRate = playerConfig.idleFrameRate || 6; // Breathing rate
    
    // Create idle animations from breathing-idle atlas data
    for (const [atlasAnimKey, frames] of Object.entries(atlasData.animations)) {
        if (atlasType === 'breathing-idle') {
            const animKey = `idle-${direction}`;
            gameRef.anims.create({
                key: animKey,
                frames: frames.map(frameName => ({ key: spriteSheet, frame: frameName })),
                frameRate: idleFrameRate, // 6 fps
                repeat: -1 // Loop forever
            });
        }
    }
}

NPC System

File: js/systems/npc-sprites.js

function setupAtlasAnimations(scene, sprite, spriteSheet, config, npcId) {
    // Default frame rate: 6 fps for idle (breathing)
    let frameRate = config.idleFrameRate || 6;
    
    // Create NPC idle animations from breathing-idle
    const animKey = `npc-${npcId}-idle-${direction}`;
    scene.anims.create({
        key: animKey,
        frames: frames.map(frameName => ({ key: spriteSheet, frame: frameName })),
        frameRate: frameRate,
        repeat: -1
    });
}

Configuration

Scenario Configuration

Set frame rates in scenario.json.erb:

{
  "player": {
    "spriteSheet": "female_hacker_hood",
    "spriteConfig": {
      "idleFrameRate": 6,    // Breathing animation speed
      "walkFrameRate": 10    // Walking animation speed
    }
  },
  "npcs": [
    {
      "id": "sarah",
      "spriteSheet": "female_office_worker",
      "spriteConfig": {
        "idleFrameRate": 6,  // Breathing animation speed
        "walkFrameRate": 10
      }
    }
  ]
}

Adjusting Breathing Speed

To adjust the breathing effect:

Slower breathing (calmer, more relaxed):

"idleFrameRate": 4  // 1 second per cycle, ~60 bpm

Normal breathing (default):

"idleFrameRate": 6  // 0.67 seconds per cycle, ~90 bpm

Faster breathing (active, alert):

"idleFrameRate": 8  // 0.5 seconds per cycle, ~120 bpm

Animation States

When Breathing Animation Plays

The breathing-idle animation plays in these states:

  1. Standing Still: Character not moving
  2. Face Player: NPC facing the player but not moving
  3. Dwell Time: NPC waiting at a patrol waypoint
  4. Personal Space: NPC adjusting distance from player
  5. Attack Range: Hostile NPC in range but between attacks

When Other Animations Play

  • Walk: Moving in any direction
  • Attack: Performing combat actions
  • Death: Character defeated
  • Hit: Taking damage

Visual Effect

The breathing animation provides:

  • Subtle movement when idle
  • Lifelike appearance for characters
  • Visual feedback that character is active
  • Polish and professional game feel

Before (Static Idle)

  • Single frame
  • Completely still
  • Lifeless appearance

After (Breathing Idle)

  • 4-frame cycle
  • Gentle animation
  • Natural, living characters

Performance

The breathing animation has minimal performance impact:

  • Memory: Same as single-frame idle (uses same texture atlas)
  • CPU: Negligible (just frame switching)
  • GPU: No additional draw calls (same sprite)

Compatibility

Atlas Sprites (New)

  • Full 4-frame breathing animation
  • All 8 directions
  • Configurable frame rate

Legacy Sprites (Old)

  • ⚠️ Single frame idle (no breathing)
  • ⚠️ 5 directions with flipping
  • Still fully supported

Troubleshooting

Breathing Too Fast

Symptom: Characters appear to be hyperventilating
Solution: Decrease idleFrameRate to 4-5 fps

Breathing Too Slow

Symptom: Animation feels sluggish or barely noticeable
Solution: Increase idleFrameRate to 7-8 fps

No Breathing Animation

Symptom: Characters completely still when idle
Solution:

  1. Verify sprite is using atlas format (not legacy)
  2. Check that breathing-idle_* animations exist in JSON
  3. Confirm idleFrameRate is set in config
  4. Check console for animation creation logs

Animation Not Looping

Symptom: Breathing stops after one cycle
Solution: Verify repeat: -1 is set in animation creation

Future Enhancements

Potential improvements:

  • Variable breathing rate based on character state (calm vs alert)
  • Synchronized breathing for multiple characters
  • Different breathing patterns for different character types
  • Heavy breathing after running/combat
  • Breathing affected by player proximity (nervousness)

Technical Notes

Animation Format

Atlas JSON structure:

{
  "animations": {
    "breathing-idle_east": [
      "breathing-idle_east_frame_000",
      "breathing-idle_east_frame_001",
      "breathing-idle_east_frame_002",
      "breathing-idle_east_frame_003"
    ]
  }
}

Game animation structure:

{
  key: 'idle-right',
  frames: [
    { key: 'female_hacker_hood', frame: 'breathing-idle_east_frame_000' },
    { key: 'female_hacker_hood', frame: 'breathing-idle_east_frame_001' },
    { key: 'female_hacker_hood', frame: 'breathing-idle_east_frame_002' },
    { key: 'female_hacker_hood', frame: 'breathing-idle_east_frame_003' }
  ],
  frameRate: 6,
  repeat: -1
}

Performance Metrics

  • Frame switches per second: 6 (at 6 fps)
  • Memory per character: ~4KB for breathing frames (shared in atlas)
  • CPU overhead: <0.1% (Phaser handles animation efficiently)
  • Recommended max characters with breathing: 50+ (no practical limit)