修复跳一跳运行态方向与贴图刷新

恢复跳一跳运行态拖拽方向提交与后端方向落点计算

补齐平台六面贴图刷新签名和对应前端测试

更新跳一跳玩法链路文档与PRD方向契约说明
This commit is contained in:
kdletters
2026-06-09 17:42:24 +08:00
parent a0473771f1
commit 68dd48be42
5 changed files with 133 additions and 25 deletions

View File

@@ -64,8 +64,8 @@ pub fn start_run(
pub fn apply_jump(
run: &JumpHopRunSnapshot,
drag_distance: f32,
_drag_vector_x: Option<f32>,
_drag_vector_y: Option<f32>,
drag_vector_x: Option<f32>,
drag_vector_y: Option<f32>,
jumped_at_ms: u64,
) -> Result<JumpHopRunSnapshot, JumpHopError> {
if run.status != JumpHopRunStatus::Playing {
@@ -88,8 +88,12 @@ pub fn apply_jump(
let vector_x = target.x - current.x;
let vector_y = target.y - current.y;
let target_distance = vector_x.hypot(vector_y).max(0.0001);
let unit_x = vector_x / target_distance;
let unit_y = vector_y / target_distance;
let (unit_x, unit_y) = normalize_jump_direction(
drag_vector_x,
drag_vector_y,
vector_x / target_distance,
vector_y / target_distance,
);
let landed_x = current.x + unit_x * jump_distance;
let landed_y = current.y + unit_y * jump_distance;
let landed_on_target = is_landing_inside_platform_footprint(target, landed_x, landed_y);
@@ -138,6 +142,29 @@ fn is_landing_inside_platform_footprint(
error_x.abs() <= half_width && error_y.abs() <= half_height
}
fn normalize_jump_direction(
drag_vector_x: Option<f32>,
drag_vector_y: Option<f32>,
fallback_x: f32,
fallback_y: f32,
) -> (f32, f32) {
let Some(drag_x) = drag_vector_x.filter(|value| value.is_finite()) else {
return (fallback_x, fallback_y);
};
let Some(drag_y) = drag_vector_y.filter(|value| value.is_finite()) else {
return (fallback_x, fallback_y);
};
// 前端提交屏幕拖拽向量x 轴同向y 轴向下为正;真实起跳反向弹出,世界 y 向上为正。
let jump_x = -drag_x;
let jump_y = drag_y;
let length = jump_x.hypot(jump_y);
if length < 0.0001 {
(fallback_x, fallback_y)
} else {
(jump_x / length, jump_y / length)
}
}
pub fn restart_run(
run: &JumpHopRunSnapshot,
next_run_id: String,
@@ -450,7 +477,7 @@ mod tests {
}
#[test]
fn jump_resolution_ignores_client_drag_direction_and_targets_next_center() {
fn jump_resolution_uses_client_drag_direction_for_landing() {
let path = generate_jump_hop_path("seed-screen-axis", JumpHopDifficulty::Easy);
let run = start_run(
"run-screen-axis".to_string(),
@@ -465,9 +492,34 @@ mod tests {
let target_distance = (target.x - current.x).hypot(target.y - current.y);
let charge = (target_distance / run.path.scoring.charge_to_distance_ratio).round() as u32;
let result = apply_jump(&run, charge as f32, Some(-999.0), Some(-999.0), 200)
let result = apply_jump(&run, charge as f32, Some(999.0), Some(-999.0), 200)
.expect("jump should resolve");
assert_eq!(result.status, JumpHopRunStatus::Failed);
assert_eq!(
result.last_jump.as_ref().unwrap().result,
JumpHopJumpResultKind::Miss
);
}
#[test]
fn jump_resolution_falls_back_to_next_center_when_drag_direction_missing() {
let path = generate_jump_hop_path("seed-screen-axis", JumpHopDifficulty::Easy);
let run = start_run(
"run-screen-axis".to_string(),
"user-screen-axis".to_string(),
"profile-screen-axis".to_string(),
path,
100,
)
.expect("run should start");
let current = &run.path.platforms[0];
let target = &run.path.platforms[1];
let target_distance = (target.x - current.x).hypot(target.y - current.y);
let charge = (target_distance / run.path.scoring.charge_to_distance_ratio).round() as u32;
let result = apply_jump(&run, charge as f32, None, None, 200).expect("jump should resolve");
let last_jump = result.last_jump.as_ref().expect("last jump should exist");
assert_eq!(result.status, JumpHopRunStatus::Playing);
assert_eq!(last_jump.result, JumpHopJumpResultKind::Hit);