docs: panopticon auto-update for snow_trail

This commit is contained in:
2026-04-07 03:02:29 +02:00
parent b1f3d3be23
commit afff34fff4
4 changed files with 131 additions and 109 deletions

View File

@@ -42,16 +42,24 @@ pub struct CameraTransitionIntent {
}
// systems/camera.rs - consumer
pub fn camera_intent_system(world: &mut World) {
let transition_entities: Vec<EntityHandle> = world.camera_transition_intents.all();
pub fn camera_intent_system(
follow_player_intents: &mut Storage<FollowPlayerIntent>,
stop_following_intents: &mut Storage<StopFollowingIntent>,
camera_transition_intents: &mut Storage<CameraTransitionIntent>,
follows: &mut Storage<FollowComponent>,
transforms: &mut Storage<Transform>,
cameras: &mut Storage<CameraComponent>,
player_tags: &Storage<()>,
camera_transitions: &mut Storage<CameraTransition>,
) {
let transition_entities: Vec<EntityHandle> = camera_transition_intents.all();
for entity in transition_entities {
let duration = world
.camera_transition_intents
let duration = camera_transition_intents
.get(entity)
.map(|i| i.duration)
.unwrap_or(0.5);
start_camera_transition(world, entity, duration);
world.camera_transition_intents.remove(entity); // consumed
start_camera_transition(camera_transitions, transforms, cameras, entity, duration);
camera_transition_intents.remove(entity);
}
}
```
@@ -135,18 +143,17 @@ state_machine.add_transition::<IdleState, WalkingState>(move |world| {
```rust
// systems/spotlight_sync.rs
pub fn spotlight_sync_system(world: &World) -> Vec<Spotlight> {
let mut spotlights = Vec::new();
for entity in world.spotlights.all() {
// Closure captures immutably—safe to call multiple times
if let Some(spotlight_component) = world.spotlights.get(entity) {
if let Some(transform) = world.transforms.get(entity) {
pub fn spotlight_sync_system(spotlights: &Storage<SpotlightComponent>, transforms: &Storage<Transform>) -> Vec<Spotlight> {
let mut result = Vec::new();
for entity in spotlights.all() {
if let Some(spotlight_component) = spotlights.get(entity) {
if let Some(transform) = transforms.get(entity) {
let position = transform.position + spotlight_component.offset;
spotlights.push(Spotlight::new(position, ..));
result.push(Spotlight::new(position, ..));
}
}
}
spotlights
result
}
// With mutation
@@ -155,25 +162,46 @@ world.movements.with_mut(entity, |movement| {
});
```
### System Function Signature
**Why**: Pass only the storages (or immutable `World`) that the system needs. Makes data dependencies explicit.
### System Function Signature (Explicit Storage Parameters)
**Why**: Pass only the specific storages (or read-only `&World`) that the system needs. Makes data dependencies explicit for the reader and borrow checker. **This is the standard pattern—all systems follow this.**
```rust
// Good: explicit dependencies
pub fn camera_follow_system(world: &mut World) {
let camera_entities: Vec<_> = world.follows.all();
pub fn camera_follow_system(
follows: &mut Storage<FollowComponent>,
cameras: &Storage<CameraComponent>,
transforms: &mut Storage<Transform>,
) {
let camera_entities: Vec<_> = follows.all();
for camera_entity in camera_entities {
// Access what's needed
if let Some(follow) = world.follows.get(camera_entity) {
world.transforms.with_mut(camera_entity, |t| {
t.position = target_position + new_offset;
});
if let Some(follow) = follows.get(camera_entity) {
if let Some(camera) = cameras.get(camera_entity) {
transforms.with_mut(camera_entity, |t| {
t.position = follow.target_position + new_offset;
});
}
}
}
}
// For read-only systems
pub fn spotlight_sync_system(world: &World) -> Vec<Spotlight> { .. }
// Read-only system
pub fn spotlight_sync_system(spotlights: &Storage<SpotlightComponent>, transforms: &Storage<Transform>) -> Vec<Spotlight> { .. }
// Dialog system example
pub fn dialog_system(
entities: &mut EntityManager,
trigger_events: &[TriggerEvent],
dialog_sources: &Storage<DialogSourceComponent>,
bubble_tags: &mut Storage<()>,
dialog_bubbles: &mut Storage<DialogBubbleComponent>,
transforms: &mut Storage<Transform>,
names: &mut Storage<String>,
player_tags: &Storage<()>,
projectile_tags: &mut Storage<()>,
dialog_projectiles: &mut Storage<DialogProjectileComponent>,
dialog_outcomes: &mut Vec<DialogOutcomeEvent>,
delta: f32,
) { .. }
```
### Default Trait for Configuration Components
@@ -227,14 +255,14 @@ fn system_a(world: &mut World) {
**Do this instead:**
```rust
// ✅ Good: intent in queue, flat pipeline
pub fn system_a(world: &mut World) {
world.some_intents.insert(entity, MyIntent { .. });
pub fn system_a(cameras: &mut Storage<CameraComponent>) {
cameras.insert(entity, CameraTransitionIntent { .. });
}
pub fn system_b(world: &mut World) {
for entity in world.some_intents.all() {
pub fn system_b(camera_transitions: &mut Storage<CameraTransition>) {
for entity in camera_transitions.all() {
// process
world.some_intents.remove(entity);
camera_transitions.remove(entity);
}
}
```
@@ -273,46 +301,24 @@ use crate::physics::PhysicsManager;
let velocity = *PhysicsManager::with_rigidbody_mut(..);
```
### Global or Context-Based Component Queries
**Don't do this:**
```rust
// ❌ Bad: loses intent, repeats queries
for entity in world.meshes.all() {
if let Some(mesh) = world.meshes.get(entity) { .. }
}
for entity in world.meshes.all() {
if let Some(mesh) = world.meshes.get(entity) { .. }
}
```
**Do this instead:**
```rust
// ✅ Good: query once, iterate clearly
let entities: Vec<_> = world.meshes.all();
for entity in entities {
if let Some(mesh_comp) = world.meshes.get(entity) {
// process
}
}
```
### Overly Generic (World/&mut World) Parameters
**Don't do this:**
```rust
// ❌ Bad: implicit dependencies
fn update_position(world: &mut World, entity: EntityHandle) {
// What do we actually need?
// ❌ Bad: implicit dependencies, breaks borrow checker
pub fn camera_follow_system(world: &mut World) {
// What storages do we actually need?
}
```
**Do this instead:**
```rust
// ✅ Good: explicit dependencies
fn update_position(
// ✅ Good: explicit, focused dependencies
pub fn camera_follow_system(
follows: &mut Storage<FollowComponent>,
cameras: &Storage<CameraComponent>,
transforms: &mut Storage<Transform>,
entity: EntityHandle,
) {
transforms.with_mut(entity, |t| t.position.y += 1.0);
// Clear what data is needed
}
```
@@ -351,4 +357,6 @@ cargo test -- --nocapture # Show output
- See **CLAUDE.md** in project root for authoritative style rules (no inline comments, doc comments for public APIs only)
- See **docs/self-gating-systems.md** for detailed intent-based pipeline patterns
- See `src/states/player_states.rs` for canonical State impl examples
- See `src/bundles/player.rs` for complete Bundle pattern with state machine setup
- See `src/bundles/player.rs` for complete Bundle pattern with state machine setup
- See `src/systems/camera.rs` for canonical system function signatures with explicit storage parameters
- See `src/systems/dialog_system.rs` for complex multi-storage system example