Implement hitstop shake (#42)
CI / build-and-test (push) Successful in 1m22s

Reviewed-on: #42
Co-authored-by: Álex Román Núñez <eirexe@eirteam.moe>
This commit was merged in pull request #42.
This commit is contained in:
2026-09-18 11:56:53 +00:00
committed by EIREXE
parent b9f1a52bbc
commit 2b5af49e15
19 changed files with 201 additions and 57 deletions
+28 -9
View File
@@ -5,6 +5,8 @@ use bevy::prelude::*;
use bevy_ggrs::GgrsFrameTiming;
use crate::debug_tools::PresentationMotionMode;
use crate::fighter::{FighterHitstopShake};
use crate::game_settings::GameSettings;
use crate::{
fighter::{FighterECB, FighterFacingDirection, baked_animation::FixedMat4},
math::{int::FGi32, vec::FGVec2, vec3::FGVec3},
@@ -58,13 +60,15 @@ pub fn apply_fighter_translation_to_visuals(
&FighterTranslation,
&FighterPreviousTranslation,
&FighterECB,
&FighterHitstopShake,
&mut Transform,
)>,
timing: Res<GgrsFrameTiming>,
debug_settings: Res<crate::debug_tools::DebugSettings>,
game_settings: Res<GameSettings>,
) {
let overstep_fraction = timing.overstep_fraction();
for (translation, previous_translation, ecb, mut transform) in query {
for (translation, previous_translation, ecb, hitstop_shake, mut transform) in query {
let translation = sample_presentation_translation(
*previous_translation,
*translation,
@@ -77,6 +81,28 @@ pub fn apply_fighter_translation_to_visuals(
translation.y + bottom.y.to_num::<f32>(),
0.0,
);
if hitstop_shake.remaining_frames > 0 && hitstop_shake.total_frames > 0 && !game_settings.fighter_common.visual_shake_table.is_empty() {
let total = hitstop_shake.total_frames as f32;
let curr = hitstop_shake.remaining_frames as f32;
let elapsed = 1.0 - curr / total;
let access_index = (hitstop_shake.remaining_frames as usize) % game_settings.fighter_common.visual_shake_table.len();
let shake_multiplier = match hitstop_shake.role {
super::FighterHitstopShakeRole::Attacker => game_settings.fighter_common.attacker_visual_shake_multiplier,
super::FighterHitstopShakeRole::Receiver => 1.0,
};
let shake_amount: f32 = 1.0 - EaseFunction::QuinticIn.sample(elapsed).unwrap_or_default();
let shake_amount = game_settings.fighter_common.visual_shake_table[access_index] * shake_amount * shake_multiplier;
let shake_offset = match hitstop_shake.kind {
super::FighterHitstopShakeKind::Horizontal => Vec3::new(shake_amount, 0.0, 0.0),
super::FighterHitstopShakeKind::Vertical => Vec3::new(0.0, shake_amount, 0.0),
};
transform.translation += shake_offset;
}
}
}
@@ -85,22 +111,15 @@ pub fn apply_air_motion(
&FighterVelocity,
&mut FighterTranslation,
&mut FighterPreviousTranslation,
&mut Transform,
)>,
_time: Res<Time<Fixed>>,
) {
for (velocity, mut translation, mut prev_translation, _transform) in fighters {
for (velocity, mut translation, mut prev_translation) in fighters {
prev_translation.0 = translation.0;
translation.0 += velocity.0;
}
}
pub fn copy_fighter_transform_to_visuals(fighters: Query<(&FighterTranslation, &mut Transform)>) {
for (translation, mut transform) in fighters {
transform.translation = Vec3::new(translation.x.to_num(), translation.y.to_num(), 0.0);
}
}
pub fn fighter_movement() {}
pub fn snapshot_fighter_motion(