Improve ECB behaviour, add ECB interpolation, wall/ceiling support etc
CI / build-and-test (pull_request) Successful in 1m42s
CI / production-build (pull_request) Successful in 10m56s

This commit is contained in:
2026-10-13 19:35:44 +02:00
parent f1da5c1172
commit a18acb6775
7 changed files with 874 additions and 163 deletions
+43 -17
View File
@@ -10,6 +10,7 @@ pub mod animation;
pub mod attack;
pub mod attributes;
pub mod baked_animation;
pub mod blast_zones;
pub mod collision;
pub mod debug;
pub mod ecb;
@@ -21,7 +22,6 @@ pub mod push;
pub mod state;
pub mod surface;
pub mod visual;
pub mod blast_zones;
// The fighter components are re-exported so the rest of the crate can say
// `fighter::FighterVelocity` without caring which file it lives in. Named
@@ -37,13 +37,25 @@ pub use motion::{
pub use surface::FighterSurfaceState;
use crate::{
AppState, fighter::{
AppState,
fighter::{
attack::{
AttackKind, FighterAttackPlugin, FighterAttackScriptAssets, FighterDamage,
FighterKnockbackVelocity, FighterPendingHitReaction, FighterSolvedHurtboxes,
FighterStaleMoveQueue,
}, baked_animation::FighterBoneIndexMap, ecb::FighterECBBoneIndices, manifest::FighterManifest, state::{FighterState, air::AirborneStateCommon, fall::FallState}, visual::{FighterAnimations, FighterInvulnerabilityVisualState},
}, game_settings::GameSettings, input::FighterInput, math::{int::FGi32, vec::FGVec2}, player::Player, schedule::GameplaySet, scripting::FighterAttackScript,
},
baked_animation::FighterBoneIndexMap,
ecb::{FighterDesiredECB, FighterECBBoneIndices},
manifest::FighterManifest,
state::{FighterState, air::AirborneStateCommon, fall::FallState},
visual::{FighterAnimations, FighterInvulnerabilityVisualState},
},
game_settings::GameSettings,
input::FighterInput,
math::{int::FGi32, vec::FGVec2},
player::Player,
schedule::GameplaySet,
scripting::FighterAttackScript,
};
use state::state_interrupt_system;
@@ -102,7 +114,8 @@ impl FighterLedgeInformation {
}
fn tick(&mut self) {
self.regrab_lockout_remaining_frames = self.regrab_lockout_remaining_frames.saturating_sub(1);
self.regrab_lockout_remaining_frames =
self.regrab_lockout_remaining_frames.saturating_sub(1);
}
}
@@ -135,8 +148,12 @@ mod ledge_grab_lockout_tests {
pub enum FighterInvulnerabilityState {
#[default]
Vulnerable,
Invulnerable { frames_remaining: Option<u32> },
Intangible { frames_remaining: Option<u32> }
Invulnerable {
frames_remaining: Option<u32>,
},
Intangible {
frames_remaining: Option<u32>,
},
}
impl FighterFacingDirection {
@@ -197,7 +214,7 @@ pub struct FighterPendingRespawn(bool);
FighterKnockbackVelocity,
FighterTranslation,
FighterInvulnerabilityState,
FighterInvulnerabilityVisualState,
FighterInvulnerabilityVisualState
)]
pub struct Fighter {
pub manifest: Handle<FighterManifest>,
@@ -226,7 +243,11 @@ impl Plugin for FighterPlugin {
)
.add_systems(
GgrsSchedule,
(state::state_update_system, decay_hitstop, decay_invulnerability)
(
state::state_update_system,
decay_hitstop,
decay_invulnerability,
)
.chain()
.in_set(GameplaySet::StateUpdate),
)
@@ -241,11 +262,12 @@ impl Plugin for FighterPlugin {
(
(
blast_zones::apply_blast_zones,
ecb::update_ecb,
ecb::decrement_ecb_lockout,
ecb::update_ecb,
state::state_collision_interrupt_system,
decay_ledge_grab_lockout,
).chain(),
)
.chain(),
baked_animation::resample_fighter_bone_matrices,
)
.chain()
@@ -272,6 +294,8 @@ impl Plugin for FighterPlugin {
// is a desync waiting to happen.
.rollback_component_with_copy::<FighterECB>()
.checksum_component_with_hash::<FighterECB>()
.rollback_component_with_copy::<FighterDesiredECB>()
.checksum_component_with_hash::<FighterDesiredECB>()
.rollback_component_with_clone::<FighterStaleMoveQueue>()
.checksum_component_with_hash::<FighterStaleMoveQueue>()
.rollback_component_with_copy::<ecb::FighterPreviousECB>()
@@ -335,8 +359,9 @@ impl Plugin for FighterPlugin {
.run_if(crate::debug_tools::attack_hitboxes_enabled)
.run_if(in_state(AppState::InMatch)),
)
.add_systems(FixedPostUpdate,
visual::update_status_colors.run_if(resource_exists::<GameSettings>)
.add_systems(
FixedPostUpdate,
visual::update_status_colors.run_if(resource_exists::<GameSettings>),
)
.add_systems(
FixedPostUpdate,
@@ -396,10 +421,11 @@ pub fn spawn_fighter(
Transform::from_scale(Vec3::splat(model_scale.to_num())),
(
FighterECB::default(),
FighterDesiredECB::default(),
FighterHitboxes::default(),
FighterECBBoneIndices {
indices: ecb_bone_indices
}
indices: ecb_bone_indices,
},
),
(
FighterVelocity::default(),
@@ -449,7 +475,7 @@ pub fn decay_invulnerability(query: Query<&mut FighterInvulnerabilityState>) {
} else {
None
}
},
}
FighterInvulnerabilityState::Intangible { frames_remaining } => {
if let Some(frames_remaining) = frames_remaining {
*frames_remaining = frames_remaining.saturating_sub(1);
@@ -457,7 +483,7 @@ pub fn decay_invulnerability(query: Query<&mut FighterInvulnerabilityState>) {
} else {
None
}
},
}
};
if let Some(frames_remaining) = frames_remaining {