diff --git a/ss_player/SpriteStudio-SDK b/ss_player/SpriteStudio-SDK index 50123d5..088d2bc 160000 --- a/ss_player/SpriteStudio-SDK +++ b/ss_player/SpriteStudio-SDK @@ -1 +1 @@ -Subproject commit 50123d5777a7ed7f1736af8b4cea78e93c9a05cd +Subproject commit 088d2bc292b54d42b2259dc7260e95d640e4d18d diff --git a/ss_player/ss_internal_player.cpp b/ss_player/ss_internal_player.cpp index e51d7cf..b2d78cf 100644 --- a/ss_player/ss_internal_player.cpp +++ b/ss_player/ss_internal_player.cpp @@ -383,6 +383,11 @@ bool SsInternalPlayer::isPlaying() const { } void SsInternalPlayer::play(float p_start_frame) { + // play() always heads out (rewinds to a start frame); "resume" is pause()'s + // toggle, not play(). So a fresh play must clear each slot's "last started + // key" memory, otherwise a re-played animation would debounce an already- + // fired independent effect/instance as the same key and never re-fire it. + _reset_slots_playback_state(); if (p_start_frame >= 0.0f) { ss_runtime_play_with_start_frame(runtime_ctx, p_start_frame); } else { @@ -1432,6 +1437,19 @@ void SsInternalPlayer::_setup_effect_slots() { } } +void SsInternalPlayer::_reset_slots_playback_state() { + for (uint32_t i = 0; i < _effect_slots.size(); i++) { + if (_effect_slots[i].effect_slot) ss_effect_slot_reset(_effect_slots[i].effect_slot); + } + for (uint32_t i = 0; i < _instance_children.size(); i++) { + InstanceChildState& st = _instance_children[i]; + if (st.instance_slot) ss_instance_slot_reset(st.instance_slot); + // Recurse so a re-play also restarts independent effects/instances + // nested inside instance children (their slots live on the child). + if (st.player) st.player->_reset_slots_playback_state(); + } +} + void SsInternalPlayer::_update_instance_children(float parent_frame_no, float delta_seconds, bool parent_looped) { if (!_currentAnimationData) { // No animation selected on the parent: keep all children hidden. diff --git a/ss_player/ss_internal_player.h b/ss_player/ss_internal_player.h index 0ce2ead..46db4bf 100644 --- a/ss_player/ss_internal_player.h +++ b/ss_player/ss_internal_player.h @@ -624,6 +624,14 @@ class SsInternalPlayer { void _clear_instance_children(); void _setup_effect_slots(); void _clear_effect_slots(); + + // Reset every effect/instance slot's "last started key" memory (and recurse + // into instance children) so an explicit head-out re-fires independent + // effects/instances from scratch instead of debouncing the first key as the + // same one the slot last started. Called from `play()`. The reset itself + // lives in the runtime (`ss_effect_slot_reset` / `ss_instance_slot_reset`); + // the host only iterates the slots it owns. + void _reset_slots_playback_state(); // Per-tick instance child driver. Runs in the sim phase (called from // `update`), before `_drawAnimation`. Per slot, queries // `ss_runtime_get_active_event_instance` (returns SS6 default semantics