Initial work on ledge & improved baking of root motion. (#90)
CI / build-and-test (push) Successful in 2m15s
CI / production-build (push) Successful in 12m24s

Reviewed-on: #90
Co-authored-by: Álex Román Núñez <eirexe@eirteam.moe>
This commit was merged in pull request #90.
This commit is contained in:
2026-10-12 20:58:27 +00:00
committed by EIREXE
parent 0642a9234b
commit 9b974d0dd6
22 changed files with 1094 additions and 141 deletions
+64 -1
View File
@@ -86,6 +86,50 @@ pub struct FighterHitstop {
pub remaining_frames: u32,
}
#[derive(Component, Default, Copy, Clone, Hash, Debug, PartialEq, Eq)]
pub struct FighterLedgeGrabLockout {
pub remaining_frames: u32,
}
impl FighterLedgeGrabLockout {
pub fn start(&mut self, duration_frames: u32) {
self.remaining_frames = duration_frames;
}
pub fn is_active(&self) -> bool {
self.remaining_frames > 0
}
fn tick(&mut self) {
self.remaining_frames = self.remaining_frames.saturating_sub(1);
}
}
#[cfg(test)]
mod ledge_grab_lockout_tests {
use super::FighterLedgeGrabLockout;
#[test]
fn lockout_expires_after_the_requested_number_of_ticks() {
let mut lockout = FighterLedgeGrabLockout::default();
lockout.start(2);
assert!(lockout.is_active());
lockout.tick();
assert!(lockout.is_active());
lockout.tick();
assert!(!lockout.is_active());
}
#[test]
fn zero_duration_does_not_enable_lockout() {
let mut lockout = FighterLedgeGrabLockout::default();
lockout.start(0);
assert!(!lockout.is_active());
}
}
#[derive(Component, Default, Copy, Clone, Hash)]
pub enum FighterInvulnerabilityState {
#[default]
@@ -148,6 +192,7 @@ pub struct FighterPendingRespawn(bool);
FighterPendingHitReaction,
FighterPendingRespawn,
FighterHitstop,
FighterLedgeGrabLockout,
FighterKnockbackVelocity,
FighterTranslation,
FighterInvulnerabilityState,
@@ -193,7 +238,13 @@ impl Plugin for FighterPlugin {
.add_systems(
GgrsSchedule,
(
(blast_zones::apply_blast_zones, ecb::update_ecb, ecb::decrement_ecb_lockout, state::state_collision_interrupt_system).chain(),
(
blast_zones::apply_blast_zones,
ecb::update_ecb,
ecb::decrement_ecb_lockout,
state::state_collision_interrupt_system,
decay_ledge_grab_lockout,
).chain(),
baked_animation::resample_fighter_bone_matrices,
)
.chain()
@@ -247,6 +298,8 @@ impl Plugin for FighterPlugin {
.checksum_component_with_hash::<FighterPendingRespawn>()
.rollback_component_with_copy::<FighterHitstop>()
.checksum_component_with_hash::<FighterHitstop>()
.rollback_component_with_copy::<FighterLedgeGrabLockout>()
.checksum_component_with_hash::<FighterLedgeGrabLockout>()
.rollback_component_with_copy::<FighterInvulnerabilityState>()
.checksum_component_with_hash::<FighterInvulnerabilityState>()
.rollback_component_with_copy::<FighterKnockbackVelocity>()
@@ -258,6 +311,10 @@ impl Plugin for FighterPlugin {
FixedPostUpdate,
debug::debug_draw_ecb.run_if(crate::debug_tools::ecb_enabled),
)
.add_systems(
FixedPostUpdate,
debug::ledge_grab_debug.run_if(crate::debug_tools::ledge_grab_enabled),
)
.add_systems(
EguiPrimaryContextPass,
debug::fighter_debug.run_if(crate::debug_tools::fighter_info_enabled),
@@ -373,6 +430,12 @@ pub fn decay_hitstop(query: Query<(&mut FighterHitstop, &mut FighterHitstopShake
}
}
pub fn decay_ledge_grab_lockout(query: Query<&mut FighterLedgeGrabLockout>) {
for mut lockout in query {
lockout.tick();
}
}
pub fn decay_invulnerability(query: Query<&mut FighterInvulnerabilityState>) {
for invuln_state in query {
let invuln_state = invuln_state.into_inner();