Improve ECB behaviour, add ECB interpolation, wall/ceiling support etc (#94)
Reviewed-on: #94 Co-authored-by: Álex Román Núñez <eirexe@eirteam.moe>
This commit was merged in pull request #94.
This commit is contained in:
+49
-19
@@ -12,7 +12,7 @@ use crate::fighter::attack::{
|
||||
};
|
||||
use crate::fighter::attributes::FighterAttributes;
|
||||
use crate::fighter::baked_animation::{BakedFighterAnimations, FighterBoneMatrices};
|
||||
use crate::fighter::ecb::FighterPreviousECB;
|
||||
use crate::fighter::ecb::{self, FighterDesiredECB, FighterPreviousECB};
|
||||
use crate::fighter::manifest::FighterManifest;
|
||||
use crate::fighter::state::hitstun::HitstunState;
|
||||
use crate::fighter::surface::EcbLockPolicy;
|
||||
@@ -49,14 +49,14 @@ pub mod ground_attack;
|
||||
pub mod hitstun;
|
||||
pub mod jump;
|
||||
pub mod land;
|
||||
pub mod ledge_action;
|
||||
pub mod ledge_grab;
|
||||
pub mod ledge_wait;
|
||||
pub mod platform_pass;
|
||||
pub mod run;
|
||||
pub mod turn;
|
||||
pub mod wait;
|
||||
pub mod walk;
|
||||
pub mod ledge_wait;
|
||||
pub mod ledge_action;
|
||||
pub mod ledge_grab;
|
||||
|
||||
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
|
||||
pub enum SurfacePolicy {
|
||||
@@ -192,10 +192,7 @@ impl EnterContext<'_> {
|
||||
let position = self
|
||||
.baked_animations
|
||||
.initial_root_position(self.animation_frame.kind, self.model_scale)?;
|
||||
Some(
|
||||
self.translation.0
|
||||
+ animation_position_to_gameplay(position, self.facing_direction),
|
||||
)
|
||||
Some(self.translation.0 + animation_position_to_gameplay(position, self.facing_direction))
|
||||
}
|
||||
|
||||
pub fn get_animation_duration(&self, kind: AnimKind) -> Option<usize> {
|
||||
@@ -255,6 +252,7 @@ pub struct CollisionContext<'a> {
|
||||
pub velocity: &'a mut FighterVelocity,
|
||||
pub surface: &'a mut FighterSurfaceState,
|
||||
pub ecb: &'a mut FighterECB,
|
||||
pub desired_ecb: &'a mut FighterDesiredECB,
|
||||
pub prev_ecb: &'a FighterPreviousECB,
|
||||
pub stage_collision: &'a StageCollision,
|
||||
pub leave_ground_ecb_lock_duration: u32,
|
||||
@@ -262,25 +260,42 @@ pub struct CollisionContext<'a> {
|
||||
pub ledge_info: &'a mut FighterLedgeInformation,
|
||||
pub fighter_ledge_collision_box: FGRect,
|
||||
pub downward_stick_threshold: FGi32,
|
||||
pub(crate) ecb_advanced: bool,
|
||||
}
|
||||
|
||||
impl CollisionContext<'_> {
|
||||
/// Commit the target pose before resolving this frame. The collision
|
||||
/// substep resolver can later replace this with fractional steps.
|
||||
pub fn apply_desired_ecb(&mut self) {
|
||||
ecb::interpolate_ecb(self.ecb, *self.desired_ecb, FGi32::ONE);
|
||||
self.ecb_advanced = true;
|
||||
}
|
||||
|
||||
pub fn air_collide_with_stage(
|
||||
&self,
|
||||
&mut self,
|
||||
can_ignore_soft_platforms: bool,
|
||||
) -> Option<crate::fighter::collision::AirCollisionWithStageResult> {
|
||||
let ignored_polys = self.surface.ignored_polygon_ids();
|
||||
let ignore_soft_platforms = can_ignore_soft_platforms
|
||||
&& self.input.get_last_frame().movement.y <= -self.downward_stick_threshold;
|
||||
crate::fighter::collision::air_collide_with_stage(
|
||||
let result = crate::fighter::collision::air_collide_with_stage_substepped(
|
||||
self.prev_translation,
|
||||
self.translation,
|
||||
self.prev_ecb,
|
||||
self.velocity,
|
||||
self.ecb,
|
||||
self.desired_ecb,
|
||||
self.stage_collision,
|
||||
&ignored_polys,
|
||||
ignore_soft_platforms,
|
||||
)
|
||||
);
|
||||
self.ecb_advanced = true;
|
||||
result
|
||||
}
|
||||
|
||||
fn finish_ecb_frame(&mut self) {
|
||||
if !self.ecb_advanced {
|
||||
self.apply_desired_ecb();
|
||||
}
|
||||
}
|
||||
pub fn air_collide_with_ledges(
|
||||
&self,
|
||||
@@ -330,6 +345,7 @@ pub struct FighterFrameQuery {
|
||||
pub knockback_velocity: &'static mut FighterKnockbackVelocity,
|
||||
pub stale_move_queue: &'static mut FighterStaleMoveQueue,
|
||||
pub ecb: &'static mut FighterECB,
|
||||
pub desired_ecb: &'static mut FighterDesiredECB,
|
||||
pub prev_ecb: &'static FighterPreviousECB,
|
||||
pub facing_direction: &'static mut FighterFacingDirection,
|
||||
pub animation_frame: &'static mut FighterAnimationFrame,
|
||||
@@ -477,6 +493,7 @@ impl<'w, 's> FighterFrameQueryItem<'w, 's> {
|
||||
velocity: &mut self.velocity,
|
||||
surface: &mut self.surface,
|
||||
ecb: &mut self.ecb,
|
||||
desired_ecb: &mut self.desired_ecb,
|
||||
ledge_info: &mut self.ledge_information,
|
||||
prev_ecb: &self.prev_ecb,
|
||||
stage_collision,
|
||||
@@ -485,6 +502,7 @@ impl<'w, 's> FighterFrameQueryItem<'w, 's> {
|
||||
.leave_ground_ecb_frame_lock_duration,
|
||||
downward_stick_threshold: game_settings.input_common.run_stick_threshold,
|
||||
fighter_ledge_collision_box,
|
||||
ecb_advanced: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -500,7 +518,6 @@ pub struct StatefulFighterQuery {
|
||||
pub player: &'static Player,
|
||||
pub pending_hit_reaction: &'static mut FighterPendingHitReaction,
|
||||
pub hitstop: &'static mut FighterHitstop,
|
||||
pub ledge_info: &'static mut FighterLedgeInformation,
|
||||
pub hitstop_shake: &'static mut FighterHitstopShake,
|
||||
pub pending_respawn: &'static mut FighterPendingRespawn,
|
||||
pub damage: &'static mut FighterDamage,
|
||||
@@ -710,7 +727,6 @@ pub fn state_collision_interrupt_system(
|
||||
mut pending_respawn,
|
||||
player,
|
||||
mut damage,
|
||||
mut ledge_info,
|
||||
..
|
||||
} = fighter;
|
||||
|
||||
@@ -761,7 +777,7 @@ pub fn state_collision_interrupt_system(
|
||||
*damage = FighterDamage::default();
|
||||
// reset ledge
|
||||
|
||||
*ledge_info = FighterLedgeInformation::default();
|
||||
*frame.ledge_information = FighterLedgeInformation::default();
|
||||
|
||||
transition_state(
|
||||
&mut state,
|
||||
@@ -781,9 +797,13 @@ pub fn state_collision_interrupt_system(
|
||||
continue;
|
||||
}
|
||||
|
||||
let new_state = state.check_collision_interrupt(
|
||||
&mut frame.collision_context(&stage_collision, manifest, &game_settings),
|
||||
);
|
||||
let new_state = {
|
||||
let mut collision_context =
|
||||
frame.collision_context(&stage_collision, manifest, &game_settings);
|
||||
let new_state = state.check_collision_interrupt(&mut collision_context);
|
||||
collision_context.finish_ecb_frame();
|
||||
new_state
|
||||
};
|
||||
if let Some(new_state) = new_state {
|
||||
transition_state(
|
||||
&mut state,
|
||||
@@ -840,19 +860,26 @@ mod tests {
|
||||
let mut velocity = FighterVelocity::default();
|
||||
let mut surface = FighterSurfaceState::default();
|
||||
let mut ecb = FighterECB::default();
|
||||
let mut desired_ecb = FighterDesiredECB {
|
||||
top: FGVec2::lit("0", "2"),
|
||||
bottom: FGVec2::ZERO,
|
||||
left: FGVec2::lit("-1", "1"),
|
||||
right: FGVec2::lit("1", "1"),
|
||||
};
|
||||
let mut ledge_info = FighterLedgeInformation {
|
||||
regrab_lockout_remaining_frames: 5,
|
||||
..default()
|
||||
};
|
||||
let previous_ecb = FighterPreviousECB::from(ecb);
|
||||
let mut presentation_snap = FighterPresentationSnap::default();
|
||||
let context = CollisionContext {
|
||||
let mut context = CollisionContext {
|
||||
translation: &mut translation,
|
||||
prev_translation: &previous_translation,
|
||||
input: &input,
|
||||
velocity: &mut velocity,
|
||||
surface: &mut surface,
|
||||
ecb: &mut ecb,
|
||||
desired_ecb: &mut desired_ecb,
|
||||
ledge_info: &mut ledge_info,
|
||||
prev_ecb: &previous_ecb,
|
||||
stage_collision: &stage_collision,
|
||||
@@ -863,6 +890,7 @@ mod tests {
|
||||
end: FGVec2::lit("1", "-1"),
|
||||
},
|
||||
downward_stick_threshold: FGi32::ONE,
|
||||
ecb_advanced: false,
|
||||
};
|
||||
|
||||
assert!(context.air_collide_with_ledges().is_none());
|
||||
@@ -871,5 +899,7 @@ mod tests {
|
||||
context.air_collide_with_ledges().map(|result| result.ledge),
|
||||
Some(ledge_id)
|
||||
);
|
||||
context.finish_ecb_frame();
|
||||
assert_eq!(context.ecb.top, FGVec2::lit("0", "2"));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user