feat(vfx): Phase E.3 particle system + hook wiring + registry
Full runtime particle pipeline consuming Phase E.1's animation hooks.
13 motion integrators, per-emitter particle pools with overwrite-oldest
eviction, colour / scale / alpha interpolation over life, and a
ParticleHookSink routing CreateParticle / DestroyParticle / StopParticle /
CreateBlockingParticle hooks from the animation-hook router.
Core layer:
- ParticleSystem: handle-based emitter pool, per-tick emission
accumulator (retail Birthrate = time-between-spawns → our emit rate
via 1/B), 13 integrators covering the full ParticleType enum:
Still, LocalVelocity, GlobalVelocity, 7 Parabolic variants (all
apply Gravity * dt to velocity), Swarm (orbital drift),
Explode (outward from anchor), Implode (inward to anchor, dies at
convergence).
- EmitterDescRegistry: id-keyed EmitterDesc cache with fallback-to-
default for unknown ids. Replaces the dat-loaded path until
Chorizite.DatReaderWriter exposes ParticleEmitterInfo (v2.1.7 does
not; upgraded from 2.1.4 anyway for future types).
- ParticleHookSink: wires the full hook family:
- CreateParticleHook → SpawnEmitterById at entity pose + hook offset
- CreateBlockingParticleHook → marker only (blocking semantics live
in the sequencer not here)
- DestroyParticleHook → StopEmitter(handle, fadeOut=false)
- StopParticleHook → StopEmitter(handle, fadeOut=true)
- (Default/CallPES deferred until PhysicsScript dat is loadable)
GameWindow integration:
- ParticleSystem created eagerly (no driver dep), sink registered with
hook router, Tick advanced per OnRender frame after animation tick so
hooks fired this frame get integrated.
Tests (11 new): spawn-handle, emit-over-time steady state, lifetime
death curve, LocalVelocity movement, Parabolic gravity arc, Explode
outward trajectory, StopEmitter instant kill vs fadeOut, MaxParticles
cap enforcement, registry default fallback, registry custom
registration.
Upgraded Chorizite.DatReaderWriter 2.1.4 → 2.1.7 across Core + Cli.
Build green, 508 tests pass (up from 497).
Ref: r04 §2 (CParticleManager), §3 (13 integrators), §6 (PhysicsScript).
Renderer (instanced billboarded quads in translucent pass) ships next
commit; this one covers the data / logic / wiring layer in full.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
351723928f
commit
d3165f99d7
7 changed files with 820 additions and 2 deletions
|
|
@ -136,6 +136,11 @@ public sealed class GameWindow : IDisposable
|
|||
private AcDream.App.Audio.DictionaryEntitySoundTable? _entitySoundTables;
|
||||
private AcDream.App.Audio.AudioHookSink? _audioSink;
|
||||
|
||||
// Phase E.3 particles.
|
||||
private readonly AcDream.Core.Vfx.EmitterDescRegistry _emitterRegistry = new();
|
||||
private AcDream.Core.Vfx.ParticleSystem? _particleSystem;
|
||||
private AcDream.Core.Vfx.ParticleHookSink? _particleSink;
|
||||
|
||||
// Phase B.2: player movement mode.
|
||||
private AcDream.App.Input.PlayerMovementController? _playerController;
|
||||
private AcDream.App.Rendering.ChaseCamera? _chaseCamera;
|
||||
|
|
@ -566,6 +571,14 @@ public sealed class GameWindow : IDisposable
|
|||
_dats = new DatCollection(_datDir, DatAccessType.Read);
|
||||
_animLoader = new AcDream.Core.Physics.DatCollectionLoader(_dats);
|
||||
|
||||
// Phase E.3 particles: always-on, no driver dependency. Registered
|
||||
// with the hook router so CreateParticle / DestroyParticle /
|
||||
// StopParticle hooks fired from motion tables produce visible
|
||||
// spawns. The Tick call is driven from OnRender.
|
||||
_particleSystem = new AcDream.Core.Vfx.ParticleSystem(_emitterRegistry);
|
||||
_particleSink = new AcDream.Core.Vfx.ParticleHookSink(_particleSystem);
|
||||
_hookRouter.Register(_particleSink);
|
||||
|
||||
// Phase E.2 audio: init OpenAL + hook sink. Suppressible via
|
||||
// ACDREAM_NO_AUDIO=1 for headless tests / broken audio drivers.
|
||||
if (Environment.GetEnvironmentVariable("ACDREAM_NO_AUDIO") != "1")
|
||||
|
|
@ -2724,6 +2737,10 @@ public sealed class GameWindow : IDisposable
|
|||
if (_animatedEntities.Count > 0)
|
||||
TickAnimations((float)deltaSeconds);
|
||||
|
||||
// Phase E.3: advance live particle emitters AFTER animation tick
|
||||
// so emitters spawned by hooks fired this frame get integrated.
|
||||
_particleSystem?.Tick((float)deltaSeconds);
|
||||
|
||||
int visibleLandblocks = 0;
|
||||
int totalLandblocks = 0;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue