Cards stuck at scatter positions when new game is started during win cascade #7

Closed
opened 2026-05-19 18:21:43 +00:00 by funman300 · 0 comments
Owner

Description

If the player starts a new game while the win-cascade CardAnimation is still running, the newly dealt cards can end up frozen at the cascade's off-screen scatter endpoints instead of their dealt positions.

Affected files

  • solitaire_engine/src/card_plugin.rssync_cards / update_card_entity
  • solitaire_engine/src/animation_plugin.rshandle_win_cascade

Root Cause

sync_cards checks for the curve-based CardAnimation component (used by drag-rejection returns and the win cascade). When present, has_card_animation = true and update_card_entity skips the transform / CardAnim insertion path entirely to avoid fighting the curve animation.

If a new game starts while the cascade CardAnimation is still on the card entities:

  1. sync_cards fires with the new game state.
  2. For each entity that still has CardAnimation, update_card_entity skips applying the new position.
  3. The cascade animation eventually completes and removes CardAnimation, snapping the card to its scatter endpoint (anim.end) — not the dealt position.
  4. No further StateChangedEvent fires, so sync_cards never re-runs to correct the positions.

The result is a frozen, visually broken board at the start of the new game.

Suggested Fix

When a new-game event is detected (or when sync_cards runs after a game reset), forcibly remove any in-flight CardAnimation components before processing positions. This allows update_card_entity to apply dealt positions immediately without racing the cascade.

Alternatively, have handle_win_cascade listen for a new-game event and cancel all its spawned CardAnimation components early.

## Description If the player starts a new game while the win-cascade `CardAnimation` is still running, the newly dealt cards can end up frozen at the cascade's off-screen scatter endpoints instead of their dealt positions. ## Affected files - `solitaire_engine/src/card_plugin.rs` — `sync_cards` / `update_card_entity` - `solitaire_engine/src/animation_plugin.rs` — `handle_win_cascade` ## Root Cause `sync_cards` checks for the **curve-based** `CardAnimation` component (used by drag-rejection returns and the win cascade). When present, `has_card_animation = true` and `update_card_entity` skips the transform / `CardAnim` insertion path entirely to avoid fighting the curve animation. If a new game starts while the cascade `CardAnimation` is still on the card entities: 1. `sync_cards` fires with the new game state. 2. For each entity that still has `CardAnimation`, `update_card_entity` skips applying the new position. 3. The cascade animation eventually completes and removes `CardAnimation`, snapping the card to its scatter endpoint (`anim.end`) — not the dealt position. 4. No further `StateChangedEvent` fires, so `sync_cards` never re-runs to correct the positions. The result is a frozen, visually broken board at the start of the new game. ## Suggested Fix When a new-game event is detected (or when `sync_cards` runs after a game reset), forcibly remove any in-flight `CardAnimation` components before processing positions. This allows `update_card_entity` to apply dealt positions immediately without racing the cascade. Alternatively, have `handle_win_cascade` listen for a new-game event and cancel all its spawned `CardAnimation` components early.
Sign in to join this conversation.
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: funman300/Ferrous-Solitaire#7