--- id: wiki-2026-0508-stat-injection-and-visual-render title: Stat Injection and Visual Renderer Pipeline category: 10_Wiki/Topics status: verified canonical_id: self aliases: [Stat Injection Pipeline, Visual Renderer Pipeline] duplicate_of: none source_trust_level: B confidence_score: 0.8 verification_status: applied tags: [game-engine, ecs, rendering-pipeline, data-flow] raw_sources: [] last_reinforced: 2026-05-10 github_commit: pending tech_stack: language: rust framework: bevy --- # Stat Injection and Visual Renderer Pipeline ## 매 한 줄 > **"매 simulation stats (HP, mana, status) → 매 visual layer (sprites, VFX, UI) 의 one-way injection pipeline"**. 매 game engine 의 ECS pattern + 매 render system. 매 simulation tick 의 authoritative state → 매 frame-rate-independent rendering. 2026 매 Bevy ECS, Unity DOTS, Unreal MASS 가 매 reference. ## 매 핵심 ### 매 데이터 흐름 1. **Simulation tick** (fixed 60 Hz): 매 stats mutation (Damage, Heal, StatusEffect). 2. **Stat aggregation**: 매 base + buffs + equipment modifiers. 3. **Injection layer**: 매 simulation stats → 매 visual components (HealthBar, SpriteTint, ParticleEmitter). 4. **Render pipeline**: 매 cull → batch → draw call → GPU. 5. **Frame interpolation**: 매 sim tick rate 와 매 render rate 의 mismatch 의 smooth. ### 매 layers - **Authoritative**: simulation Components (Health, Mana, Position). - **Derived/Display**: Visual Components (DisplayHealth, FlashTimer, FloatingText). - **Renderer**: Sprite, Mesh, Material, Shader. - **Pipeline stages**: Update → Late Update → PostUpdate → Render. ### 매 응용 1. RPG combat — damage number 의 popup, sprite flash on hit. 2. RTS — health bar, status icon, fog-of-war overlay. 3. Action game — hit-stop, screen shake, VFX 의 trigger. ## 💻 패턴 ### Bevy ECS (Rust 1.83) — stat → visual injection ```rust use bevy::prelude::*; #[derive(Component)] struct Health { current: f32, max: f32 } #[derive(Component)] struct HealthBar; // visual marker #[derive(Component)] struct DamageFlash { timer: Timer } fn inject_health_to_bar( actors: Query<&Health, Changed>, mut bars: Query<(&Parent, &mut Sprite), With>, ) { for (parent, mut sprite) in bars.iter_mut() { if let Ok(h) = actors.get(parent.get()) { let ratio = h.current / h.max; sprite.custom_size = Some(Vec2::new(64.0 * ratio, 6.0)); sprite.color = Color::rgb(1.0 - ratio, ratio, 0.0); } } } ``` ### Damage event → flash injection ```rust #[derive(Event)] struct DamageEvent { target: Entity, amount: f32 } fn on_damage( mut events: EventReader, mut commands: Commands, mut healths: Query<&mut Health>, ) { for ev in events.read() { if let Ok(mut h) = healths.get_mut(ev.target) { h.current -= ev.amount; commands.entity(ev.target).insert(DamageFlash { timer: Timer::from_seconds(0.15, TimerMode::Once), }); } } } fn tick_flash( time: Res