Fix ledge transitions and root motion loops (#91)
CI / build-and-test (push) Successful in 1m39s
CI / production-build (push) Successful in 12m8s

## Summary

- resolve each ledge action to the walkable segment on the stage-interior side
- preserve repeating root-motion displacement across every animation cycle
- add regression coverage for left/right ledge segments and multiple root-motion wraps
- Implement ledge intangibility

Reviewed-on: #91
Co-authored-by: Álex Román Núñez <eirexe@eirteam.moe>
This commit was merged in pull request #91.
This commit is contained in:
2026-10-12 21:38:23 +00:00
committed by EIREXE
parent 9b974d0dd6
commit f53e67d8ad
9 changed files with 93 additions and 34 deletions
+30
View File
@@ -428,6 +428,7 @@ impl StageCameraProfile {
#[cfg(test)]
mod tests {
use super::*;
use crate::stage::line::StageLineID;
fn platform(ledges: Vec<StageLedgeDefinition>) -> StagePolyDefinition {
StagePolyDefinition {
@@ -461,6 +462,35 @@ mod tests {
assert_eq!(ledges[1].position, FGVec2::lit("5", "0"));
}
#[test]
fn ledge_ground_segments_point_toward_the_stage_interior() {
let definition = platform(vec![
StageLedgeDefinition {
vertex: 0,
hang_side: StageLedgeSide::Left,
},
StageLedgeDefinition {
vertex: 1,
hang_side: StageLedgeSide::Right,
},
]);
let collision = StageCollision {
stage_polys: vec![StagePoly::build(definition.poly_type, &definition.lines)],
ledges: definition.resolved_ledges(0).collect(),
};
for vertex in [0, 1] {
let (line_id, segment) = collision
.find_ledge_ground_segment(StageVertexID { polygon: 0, vertex })
.unwrap();
assert_eq!(line_id, StageLineID { polygon: 0, segment: 0 });
assert!(matches!(
segment.segment_type,
StagePolyLineSegmentType::Floor
));
}
}
#[test]
fn invalid_and_duplicate_ledge_vertices_are_rejected() {
let missing = platform(vec![StageLedgeDefinition {