component initialization

Guide for component initialization

Component Initialization Patterns

Overview

This document describes the pattern for initializing player components when spawning the player entity.

Component Categories

1. Marker Components

Components that identify the entity type.
Player  // Marker component for player entity
Purpose: Used in queries to filter for player-specific systems.

2. Spatial Components

Components that define the entity's position and visibility in the world.
SpatialBundle {
    transform: Transform::from_xyz(0.0, 0.5, 0.0),
    ..default()
}
Includes:
  • Transform: Local position, rotation, scale
  • GlobalTransform: World-space position (computed)
  • Visibility: Whether entity is visible
  • InheritedVisibility: Visibility inherited from parent (computed)
Why SpatialBundle: Provides all spatial components in one bundle, ensuring consistency.

3. Gameplay State Components

Components that track player progression and state.
crate::systems::player::skills::Skills::default()
crate::systems::player::inventory::Inventory::new(28)
crate::systems::player::inventory::Equipment::default()
crate::systems::player::bank::Bank::default()
crate::systems::player::prayer::PrayerPoints::new(1) // Based on Prayer level
Initialization Patterns:
  • Skills: Uses Default trait (all skills start at level 1, XP 0)
  • Inventory: Requires capacity parameter (28 slots for player)
  • Equipment: Uses Default trait (all slots empty)
  • Bank: Uses Default trait (empty bank)
  • PrayerPoints: Should use new(level) constructor, not default()

4. Movement Components

Components that control entity movement and pathfinding.
MovementTarget(Vec3::new(0.0, 0.5, 0.0))
crate::systems::ai::pathfinding::PathAgent::default() // ❌ Module not found
Purpose:
  • MovementTarget: Destination for movement system
  • PathAgent: Pathfinding state and configuration
Issue: PathAgent is not found in crate::systems::ai::pathfinding. Need to verify correct path or remove if not needed.

5. Debug Components

Components for debugging and identification.
Name::new("Hero")
Purpose: Human-readable name for entity inspector and logs.

Component Initialization Best Practices

1. Use Constructors Over Default

Some components have specific initialization requirements:
❌ Bad:
PrayerPoints::default() // Compilation error: no Default trait
✅ Good:
PrayerPoints::new(prayer_level) // Uses Prayer level to calculate max points

2. Verify Module Paths

Ensure all component types are accessible:
❌ Bad:
crate::systems::ai::pathfinding::PathAgent::default() // Module not found
✅ Good:
// Option 1: Fix the path
crate::systems::player::pathfinding::PathAgent::default()

// Option 2: Remove if not needed
// (PathAgent might not be necessary for player movement)
Use bundles for groups of related components:
SpatialBundle {
    transform: Transform::from_xyz(0.0, 0.5, 0.0),
    ..default()
}
This is better than:
Transform::from_xyz(0.0, 0.5, 0.0),
GlobalTransform::default(),
Visibility::default(),
InheritedVisibility::default(),

4. Defer Optional Components

Not all components need to be added at spawn time. Some can be added later by systems:
Spawn Time (required for basic functionality):
  • Player marker
  • SpatialBundle (position/visibility)
  • Skills (gameplay state)
  • Inventory (gameplay state)
Deferred (added by ensure_player_components or other systems):
  • CombatBonuses (added by ensure_player_components)
  • AttackStyle (added by ensure_player_components)
  • Luck (added by ensure_player_components)
  • Visual mesh (added by ensure_player_visuals)

Component Dependencies

Some components depend on others being present:
Player (marker)
├── SpatialBundle (required for position)
├── Skills (required for level-based calculations)
│   └── PrayerPoints (depends on Prayer level)
├── Inventory (required for item storage)
└── Equipment (required for equipped items)
Initialization Order:
  1. Spawn entity with all components in one commands.spawn() call
  2. Bevy processes the spawn in the next frame
  3. Systems like ensure_player_components add missing components
  4. Systems like ensure_player_visuals add visual representation

Example: Complete Player Spawn

pub fn spawn_player(
    mut commands: Commands,
    query: Query<Entity, With<Player>>,
) {
    if !query.is_empty() {
        return; // Player already exists
    }

    info!("Spawning Player Entity...");
    
    // Get initial Prayer level from Skills (or default to 1)
    let initial_prayer_level = 1;
    
    commands.spawn((
        // Marker
        Player,
        
        // Spatial
        SpatialBundle {
            transform: Transform::from_xyz(0.0, 0.5, 0.0),
            ..default()
        },
        
        // Gameplay State
        crate::systems::player::skills::Skills::default(),
        crate::systems::player::inventory::Inventory::new(28),
        crate::systems::player::inventory::Equipment::default(),
        crate::systems::player::bank::Bank::default(),
        crate::systems::player::prayer::PrayerPoints::new(initial_prayer_level),
        
        // Movement
        MovementTarget(Vec3::new(0.0, 0.5, 0.0)),
        
        // Debug
        Name::new("Hero"),
    ));
}

Testing Component Initialization

After spawning, verify all components are present:
fn verify_player_components(
    player_query: Query<(
        &Player,
        &Transform,
        &Skills,
        &Inventory,
        &Equipment,
        &Bank,
        &PrayerPoints,
    )>,
) {
    if let Ok((_, transform, skills, inventory, equipment, bank, prayer)) = player_query.get_single() {
        info!("Player spawned at: {:?}", transform.translation);
        info!("Skills: {:?}", skills);
        info!("Inventory slots: {}", inventory.items.len());
        info!("Prayer points: {}/{}", prayer.current, prayer.max);
    } else {
        warn!("Player entity missing required components!");
    }
}
This system can run on Update to verify the player is properly initialized.