From 5a71e2bc0abc40d6c88ff3109f86cf29dae5538b Mon Sep 17 00:00:00 2001 From: funman300 Date: Wed, 27 May 2026 16:01:49 -0700 Subject: [PATCH] fix(engine): ensure dragged card stack z-order is above all piles (closes #35) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- solitaire_engine/src/input_plugin.rs | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/solitaire_engine/src/input_plugin.rs b/solitaire_engine/src/input_plugin.rs index 468954e..7be9499 100644 --- a/solitaire_engine/src/input_plugin.rs +++ b/solitaire_engine/src/input_plugin.rs @@ -64,6 +64,16 @@ pub enum TouchDragSet { /// Z-depth used for cards while being dragged — above all resting cards. const DRAG_Z: f32 = 500.0; +/// Relative Z step between cards inside a dragged stack. +/// +/// Must stay at least as large as [`STACK_FAN_FRAC`], otherwise Android's +/// per-card corner overlay children (`local_z = 0.02`) can bleed above the +/// card body stacked directly above them while dragging. +const DRAG_STACK_Z_STEP: f32 = STACK_FAN_FRAC; + +fn dragged_card_z(index: usize) -> f32 { + DRAG_Z + index as f32 * DRAG_STACK_Z_STEP +} /// Solver budgets used by the H-key hint system. /// @@ -638,7 +648,7 @@ fn follow_drag( if let Some((_, mut transform, mut sprite)) = card_transforms.iter_mut().find(|(ce, _, _)| ce.card_id == id) { - transform.translation.z = DRAG_Z + i as f32 * 0.01; + transform.translation.z = dragged_card_z(i); sprite.color.set_alpha(0.85); } } @@ -904,7 +914,7 @@ fn touch_follow_drag( if let Some((_, mut transform, mut sprite)) = card_transforms.iter_mut().find(|(ce, _, _)| ce.card_id == id) { - transform.translation.z = DRAG_Z + i as f32 * 0.01; + transform.translation.z = dragged_card_z(i); sprite.color.set_alpha(0.85); } } @@ -1659,6 +1669,17 @@ mod tests { use crate::layout::compute_layout; use solitaire_core::game_state::{DrawMode, GameState}; + #[test] + fn dragged_card_z_matches_resting_stack_step() { + assert!((dragged_card_z(0) - DRAG_Z).abs() < 1e-6); + let step = dragged_card_z(1) - dragged_card_z(0); + assert!(step > 0.02, "drag step must exceed Android overlay local_z, got {step}"); + assert!( + step + 1e-4 >= STACK_FAN_FRAC, + "drag step must stay aligned with resting stack spacing, got {step}" + ); + } + #[test] fn point_in_rect_inside_returns_true() { let center = Vec2::new(10.0, 20.0);