Files
BreakEscape/planning_notes/npc/npc_behaviour/QUICK_REFERENCE.md
Z. Cliffe Schreuders 1f6166ccf6 Add review changes and improvements for NPC behavior implementation
- Created CHANGES_APPLIED.md to document critical clarifications and updates based on code review findings.
- Established a new review and improvements document (REVIEW_AND_IMPROVEMENTS.md) outlining 9 critical improvements and 12 enhancement opportunities for NPC behavior.
- Updated TECHNICAL_SPEC.md, IMPLEMENTATION_PLAN.md, QUICK_REFERENCE.md, and example_scenario.json with necessary changes regarding roomId tracking, sprite storage, wall collision setup, animation creation timing, and personal space behavior.
- Clarified async import patterns and depth update requirements in the implementation plan.
- Enhanced personal space behavior design to ensure NPCs back away slowly while maintaining eye contact with players.
- Documented all changes and improvements to ensure better integration with existing systems and reduce complexity in NPC behavior implementation.
2025-11-09 02:43:17 +00:00

7.6 KiB

NPC Behavior System - Quick Reference

For Scenario Designers

Basic Setup (Face Player Only - Default)

{
  "id": "receptionist",
  "displayName": "Receptionist",
  "npcType": "person",
  "position": { "x": 5, "y": 3 },
  "spriteSheet": "hacker-red",
  "storyPath": "scenarios/ink/receptionist.json"
}

Result: NPC will automatically turn to face player when player is within 3 tiles (96px).


Add Patrol Behavior

{
  "id": "guard",
  "displayName": "Security Guard",
  "npcType": "person",
  "position": { "x": 5, "y": 3 },
  "behavior": {
    "patrol": {
      "enabled": true,
      "speed": 80,
      "changeDirectionInterval": 4000
    }
  },
  "spriteSheet": "guard",
  "storyPath": "scenarios/ink/guard.json"
}

Result: NPC will wander randomly in the room, changing direction every 4 seconds. Will still face player when approached.


Add Personal Space

{
  "id": "nervous_npc",
  "displayName": "Nervous Employee",
  "npcType": "person",
  "position": { "x": 5, "y": 3 },
  "behavior": {
    "personalSpace": {
      "enabled": true,
      "distance": 48,
      "backAwaySpeed": 30,
      "backAwayDistance": 5
    }
  },
  "spriteSheet": "hacker",
  "storyPath": "scenarios/ink/nervous.json"
}

Result: NPC will back away slowly (5px at a time) if player gets within 48px (1.5 tiles), while still facing the player. NPC remains within interaction range.


Start as Hostile

{
  "id": "enemy_agent",
  "displayName": "Enemy Agent",
  "npcType": "person",
  "position": { "x": 5, "y": 3 },
  "behavior": {
    "hostile": {
      "defaultState": true,
      "influenceThreshold": -30
    }
  },
  "spriteSheet": "hacker-red",
  "storyPath": "scenarios/ink/enemy.json"
}

Result: NPC will have red tint from start. Can be changed via Ink tags.


For Ink Story Writers

Control Hostility

=== make_hostile ===
# hostile
You've gone too far!
-> END

=== make_friendly ===
# hostile:false
Okay, I forgive you.
-> hub

Set Influence Score

=== gain_favour ===
# influence:25
I really appreciate your help!
-> hub

=== lose_favour ===
# influence:-50
I can't believe you did that.
-> hub

Toggle Patrol

=== start_rounds ===
# patrol_mode:on
I'll be making my rounds now.
-> hub

=== stop_rounds ===
# patrol_mode:off
I'll stay here for now.
-> hub

Adjust Personal Space

=== need_distance ===
# personal_space:128
Please keep your distance (4 tiles).
-> hub

=== no_personal_space ===
# personal_space:0
You can come closer now.
-> hub

For Developers

Register a Behavior

// In game.js create() phase
window.npcBehaviorManager.registerBehavior(
  'npc_id',           // NPC identifier
  npcSprite,          // Phaser sprite reference
  behaviorConfig      // Config from scenario JSON
);

Update Loop Integration

// In game.js update() function
export function update(time, delta) {
  // ... existing updates ...
  
  if (window.npcBehaviorManager) {
    window.npcBehaviorManager.update(time, delta);
  }
}

Control via Code

// Set hostile state
window.npcGameBridge.setNPCHostile('guard', true);

// Set influence
window.npcGameBridge.setNPCInfluence('receptionist', 50);

// Toggle patrol
window.npcGameBridge.setNPCPatrol('guard', false);

Configuration Defaults

Property Default Value Description
facePlayer true Turn to face player when nearby
facePlayerDistance 96 Distance (px) to start facing
patrol.enabled false Enable random patrolling
patrol.speed 100 Movement speed (px/s)
patrol.changeDirectionInterval 3000 Time (ms) between direction changes
personalSpace.enabled false Back away when player too close
personalSpace.distance 48 Min distance (px) - smaller than interaction range
personalSpace.backAwaySpeed 30 Speed when backing away (px/s) - slow
personalSpace.backAwayDistance 5 Back away distance per update (px)
hostile.defaultState false Start hostile
hostile.influenceThreshold -50 Become hostile below this influence

Personal Space Design: NPCs back away slowly (5px at a time) while facing the player. Distance is 48px (1.5 tiles), which is smaller than the interaction range (64px / 2 tiles), so NPCs remain interactive while maintaining comfort.


Distance Reference

Tiles Pixels Use Case
1 32 Very close (touching)
1.5 48 Default personal space (stays interactive)
2 64 Interaction range (player can talk to NPC)
3 96 Default face player range
4 128 Extended personal space
5 160 Hostile aggro range
10 320 One full room width

Behavior Priority

Behaviors are evaluated in priority order (highest first):

  1. Chase (5) - Hostile chase (future)
  2. Flee (4) - Hostile flee (future)
  3. Maintain Space (3) - Back away from player
  4. Patrol (2) - Random movement
  5. Face Player (1) - Turn towards player
  6. Idle (0) - Default standing

Higher priority behaviors override lower priority behaviors.


Common Patterns

Friendly NPC That Patrols

{
  "behavior": {
    "patrol": { "enabled": true, "speed": 80 }
  }
}

Skittish NPC (Personal Space)

{
  "behavior": {
    "personalSpace": { 
      "enabled": true, 
      "distance": 96 
    }
  }
}

Guard That Patrols Until Confronted

{
  "behavior": {
    "patrol": { "enabled": true, "speed": 100 },
    "hostile": { "defaultState": false }
  }
}

Ink Story:

=== confrontation ===
# patrol_mode:off
# hostile
Stop right there!
-> combat

NPC That Warms Up to Player

{
  "behavior": {
    "personalSpace": { "enabled": true, "distance": 96 },
    "hostile": { "defaultState": false }
  }
}

Ink Story:

=== start ===
# influence:0
# personal_space:96
Stay back!
-> hub

=== make_friends ===
# influence:50
# personal_space:0
Okay, I trust you now.
-> hub

Troubleshooting

NPC Not Facing Player

  • Check facePlayer: true in config
  • Verify facePlayerDistance is large enough
  • Check player is within range (use debug mode)

NPC Not Patrolling

  • Check patrol.enabled: true
  • Verify NPC has collision body (immovable: false for movement)
  • Check patrol bounds include NPC starting position
  • Wall collisions automatically set up for patrolling NPCs

NPC Not Backing Away

  • Check personalSpace.enabled: true
  • Verify distance is 48px (or custom value smaller than interaction range)
  • Note: NPC should back away slowly while still facing player
  • Ensure NPC has collision body

NPC Backs Away Too Far

  • Personal space distance should be smaller than 64px (interaction range)
  • Default is 48px - NPC stays within interaction range
  • Use backAwayDistance: 5 for subtle 5px adjustments

Hostile Tint Not Showing

  • Check hostile: true set via config or tag
  • Verify sprite exists and is visible
  • Check console for errors

Debug Mode

Enable debug logging:

// In browser console
window.NPC_BEHAVIOR_DEBUG = true;

Visualize behavior ranges (future):

// In browser console
window.NPC_BEHAVIOR_DEBUG_VISUAL = true;

Performance Tips

  1. Limit NPCs: Keep < 10 NPCs with behaviors per room
  2. Disable when not visible: Future enhancement
  3. Use lower update rates: Default 50ms is good balance
  4. Simple patrol bounds: Smaller areas = less collision checks

Last Updated: 2025-11-09 Version: 1.0