From 371c3e6a844f1df9476d6ed9d1b2e8214c7fbaee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lex=20Rom=C3=A1n=20N=C3=BA=C3=B1ez?= Date: Tue, 15 Sep 2026 19:10:57 +0200 Subject: [PATCH] Spread state context architecture (Fixes #18) --- src/fighter/collision.rs | 17 +- src/fighter/mod.rs | 14 +- src/fighter/state/air_dodge.rs | 20 +- src/fighter/state/dash.rs | 38 ++-- src/fighter/state/fall.rs | 22 +-- src/fighter/state/ground.rs | 12 +- src/fighter/state/ground_attack.rs | 20 +- src/fighter/state/hitstun.rs | 18 +- src/fighter/state/jump.rs | 92 ++++----- src/fighter/state/land.rs | 34 ++-- src/fighter/state/mod.rs | 291 +++++++++++++++++++---------- src/fighter/state/run.rs | 20 +- src/fighter/state/turn.rs | 33 ++-- src/fighter/state/wait.rs | 35 ++-- src/fighter/state/walk.rs | 20 +- 15 files changed, 384 insertions(+), 302 deletions(-) diff --git a/src/fighter/collision.rs b/src/fighter/collision.rs index 827be14..f6cc379 100644 --- a/src/fighter/collision.rs +++ b/src/fighter/collision.rs @@ -1,9 +1,10 @@ //! Resolving an integrated fighter position against the stage. -use crate::fighter::state::FighterStateContext; +use crate::fighter::ecb::FighterPreviousECB; +use crate::fighter::{FighterECB, FighterPreviousTranslation, FighterTranslation}; use crate::math::segment::FGSegment2d; use crate::math::vec::FGVec2; -use crate::stage::line::StageLineID; +use crate::stage::line::{StageCollision, StageLineID}; /* pub fn collide_fighter_with_scene( fighters: Query<(&FighterECB, &mut FighterVelocity, &mut FighterTranslation)>, @@ -38,16 +39,20 @@ pub struct AirCollisionWithStageResult { } pub fn air_collide_with_stage( - state_context: &FighterStateContext, + prev_translation: &FighterPreviousTranslation, + translation: &FighterTranslation, + prev_ecb: &FighterPreviousECB, + ecb: &FighterECB, + stage_collision: &StageCollision, ) -> Option { let ray_segment = FGSegment2d::new( - state_context.prev_translation.0 + state_context.prev_ecb.get_bottom_point(), - state_context.translation.0 + state_context.ecb.get_bottom_point(), + prev_translation.0 + prev_ecb.get_bottom_point(), + translation.0 + ecb.get_bottom_point(), ); let mut intersect_results = vec![]; - for (poly_idx, poly) in state_context.stage_collision.stage_polys.iter().enumerate() { + for (poly_idx, poly) in stage_collision.stage_polys.iter().enumerate() { if let Some(intersect_result) = poly.intersect_ray(ray_segment) { intersect_results.push(( AirCollisionWithStageResult { diff --git a/src/fighter/mod.rs b/src/fighter/mod.rs index 7db4ffd..e34ad1a 100644 --- a/src/fighter/mod.rs +++ b/src/fighter/mod.rs @@ -33,7 +33,8 @@ pub use motion::{ }; use crate::{ - AppState, fighter::{ + AppState, + fighter::{ attack::{ AttackKind, FighterAttackPlugin, FighterAttackScriptAssets, FighterDamage, FighterKnockbackVelocity, FighterPendingHitReaction, FighterReceivedAttacks, @@ -43,7 +44,13 @@ use crate::{ manifest::FighterManifest, state::{FighterState, fall::FallState}, visual::FighterAnimations, - }, input::FighterInput, math::{int::FGi32, vec::FGVec2}, player::Player, schedule::GameplaySet, scripting::FighterAttackScript, stage::line::StageCollision, + }, + input::FighterInput, + math::{int::FGi32, vec::FGVec2}, + player::Player, + schedule::GameplaySet, + scripting::FighterAttackScript, + stage::line::StageCollision, }; use state::state_interrupt_system; @@ -216,7 +223,8 @@ impl Plugin for FighterPlugin { .after(debug::attack_debug_gather), ) .chain() - .run_if(crate::debug_tools::attack_hitboxes_enabled).run_if(in_state(AppState::InMatch)), + .run_if(crate::debug_tools::attack_hitboxes_enabled) + .run_if(in_state(AppState::InMatch)), ) .add_systems( FixedPostUpdate, diff --git a/src/fighter/state/air_dodge.rs b/src/fighter/state/air_dodge.rs index 2399059..8a177cc 100644 --- a/src/fighter/state/air_dodge.rs +++ b/src/fighter/state/air_dodge.rs @@ -1,9 +1,9 @@ use crate::{ fighter::{ animation::AnimKind, - collision, state::{ - FighterState, FighterStateContext, FighterStateImpl, air, + CollisionContext, EnterContext, FighterState, FighterStateImpl, InterruptContext, + UpdateContext, air, fall::FallState, ground::GroundedStateCommon, land::{LandingState, LandingType}, @@ -21,7 +21,7 @@ pub struct AirDodgeState { impl FighterStateImpl for AirDodgeState { const NAME: &'static str = "AirDodge"; - fn check_interrupt(&self, state_context: &mut FighterStateContext) -> Option { + fn check_interrupt(&self, state_context: &mut InterruptContext) -> Option { if state_context.is_current_animation_finished() { Some(FighterState::Fall(FallState)) } else { @@ -29,8 +29,8 @@ impl FighterStateImpl for AirDodgeState { } } - fn update(&mut self, state_context: &mut FighterStateContext) { - state_context.velocity.0 *= state_context.fighter_manifest.attributes.air_dodge_decay; + fn update(&mut self, state_context: &mut UpdateContext) { + state_context.velocity.0 *= state_context.fighter_attributes.air_dodge_decay; air::apply_air_motion( state_context.velocity, @@ -41,9 +41,9 @@ impl FighterStateImpl for AirDodgeState { fn check_collision_interrupt( &mut self, - state_context: &mut FighterStateContext, + state_context: &mut CollisionContext, ) -> Option { - if let Some(res) = collision::air_collide_with_stage(state_context) { + if let Some(res) = state_context.air_collide_with_stage() { // Adjust translation state_context.translation.0 = res.hit_position - state_context.ecb.get_bottom_point(); let grounded_common = GroundedStateCommon { @@ -58,15 +58,15 @@ impl FighterStateImpl for AirDodgeState { } } - fn on_enter(&mut self, state_context: &mut FighterStateContext) { + fn on_enter(&mut self, state_context: &mut EnterContext) { state_context.play_animation(AnimKind::AirDodge, false); state_context.velocity.0 = - self.direction * state_context.fighter_manifest.attributes.air_dodge_velocity; + self.direction * state_context.fighter_attributes.air_dodge_velocity; } } -pub fn check_input(state_context: &FighterStateContext) -> Option { +pub fn check_input(state_context: &InterruptContext) -> Option { state_context .input .has_command(input::FighterCommands::Shield) diff --git a/src/fighter/state/dash.rs b/src/fighter/state/dash.rs index 71b9b2a..591ad82 100644 --- a/src/fighter/state/dash.rs +++ b/src/fighter/state/dash.rs @@ -1,6 +1,9 @@ use std::hash::Hasher; -use super::{FighterStateContext, FighterStateImpl, ground, run, wait, walk}; +use super::{ + CollisionContext, EnterContext, FighterStateImpl, InterruptContext, UpdateContext, ground, run, + wait, walk, +}; use crate::fighter::FighterFacingDirection; use crate::fighter::animation::AnimKind; use crate::fighter::state::FighterState; @@ -31,9 +34,9 @@ impl DashState { impl FighterStateImpl for DashState { const NAME: &'static str = "Dash"; - fn check_interrupt(&self, ctx: &mut FighterStateContext) -> Option { + fn check_interrupt(&self, ctx: &mut InterruptContext) -> Option { let ground = &self.ground_common; - let attributes = ctx.fighter_manifest.attributes; + let attributes = ctx.fighter_attributes; // A reverse dash can interrupt before IASA if let Some(direction) = @@ -62,13 +65,10 @@ impl FighterStateImpl for DashState { None } - fn on_enter(&mut self, state_context: &mut FighterStateContext) { + fn on_enter(&mut self, state_context: &mut EnterContext) { *state_context.facing_direction = self.direction; - state_context.velocity.x = state_context - .fighter_manifest - .attributes - .dash_initial_velocity - * self.direction.to_sign(); + state_context.velocity.x = + state_context.fighter_attributes.dash_initial_velocity * self.direction.to_sign(); state_context.play_animation(AnimKind::Dash, false); @@ -86,24 +86,20 @@ impl FighterStateImpl for DashState { } } - fn update(&mut self, state_context: &mut FighterStateContext) { + fn update(&mut self, state_context: &mut UpdateContext) { if state_context.get_current_animation_frame() - < state_context - .fighter_manifest - .attributes - .dash_acceleration_duration + < state_context.fighter_attributes.dash_acceleration_duration {} let last_frame = state_context.input.get_last_frame(); let (accel, target_vel) = state_context - .fighter_manifest - .attributes + .fighter_attributes .get_accel_and_target_dashrun(&last_frame, self.direction.to_sign()); let accel = ground::compute_ground_accel( accel, target_vel, state_context.velocity.x, - &state_context.fighter_manifest.attributes, + state_context.fighter_attributes, state_context.game_settings, ); state_context.velocity.x += accel; @@ -117,7 +113,7 @@ impl FighterStateImpl for DashState { fn check_collision_interrupt( &mut self, - state_context: &mut FighterStateContext, + state_context: &mut CollisionContext, ) -> Option { if let GroundedMotionResult::InAir = ground::collide_with_stage_grounded(state_context, &mut self.ground_common, true) @@ -129,9 +125,7 @@ impl FighterStateImpl for DashState { } } -fn check_smash_input_with_dir( - state_context: &FighterStateContext, -) -> Option { +fn check_smash_input_with_dir(state_context: &InterruptContext) -> Option { if state_context.input.has_command(SmashMoveLeft) { return Some(FighterFacingDirection::Left); } else if state_context.input.has_command(SmashMoveRight) { @@ -142,7 +136,7 @@ fn check_smash_input_with_dir( } pub fn check_input( - state_context: &FighterStateContext, + state_context: &InterruptContext, ground_common: &GroundedStateCommon, ) -> Option { check_smash_input_with_dir(state_context) diff --git a/src/fighter/state/fall.rs b/src/fighter/state/fall.rs index 5c02437..08f42ae 100644 --- a/src/fighter/state/fall.rs +++ b/src/fighter/state/fall.rs @@ -1,6 +1,5 @@ -use super::{FighterStateContext, FighterStateImpl}; +use super::{CollisionContext, EnterContext, FighterStateImpl, InterruptContext, UpdateContext}; use crate::fighter::animation::AnimKind; -use crate::fighter::collision; use crate::fighter::state::ground::GroundedStateCommon; use crate::fighter::state::land::{LandingState, LandingType}; use crate::fighter::state::{FighterState, air, jump}; @@ -10,22 +9,19 @@ pub struct FallState; impl FighterStateImpl for FallState { const NAME: &'static str = "Fall"; - fn check_interrupt(&self, state_context: &mut FighterStateContext) -> Option { + fn check_interrupt(&self, state_context: &mut InterruptContext) -> Option { jump::check_input_double_jump(state_context) } - fn on_enter(&mut self, state_context: &mut super::FighterStateContext) { + fn on_enter(&mut self, state_context: &mut EnterContext) { state_context.play_animation(AnimKind::Fall, true); } - fn update(&mut self, state_context: &mut super::FighterStateContext) { - air::integrate_gravity( - state_context.velocity, - &state_context.fighter_manifest.attributes, - ); + fn update(&mut self, state_context: &mut UpdateContext) { + air::integrate_gravity(state_context.velocity, state_context.fighter_attributes); air::apply_air_drift( state_context.velocity, - &state_context.fighter_manifest.attributes, + state_context.fighter_attributes, state_context.input, ); air::apply_air_motion( @@ -37,9 +33,9 @@ impl FighterStateImpl for FallState { fn check_collision_interrupt( &mut self, - state_context: &mut FighterStateContext, + state_context: &mut CollisionContext, ) -> Option { - if let Some(res) = collision::air_collide_with_stage(state_context) { + if let Some(res) = state_context.air_collide_with_stage() { // Adjust translation state_context.translation.0 = res.hit_position - state_context.ecb.get_bottom_point(); let grounded_common = GroundedStateCommon { @@ -55,7 +51,7 @@ impl FighterStateImpl for FallState { } } -pub fn check_input(state_context: &FighterStateContext) -> Option { +pub fn check_input(state_context: &InterruptContext) -> Option { let input_frame = state_context.input.get_last_frame(); if input_frame.movement.x.abs() < state_context.game_settings.input_common.stick_deadzone { diff --git a/src/fighter/state/ground.rs b/src/fighter/state/ground.rs index 38ff64f..c784b47 100644 --- a/src/fighter/state/ground.rs +++ b/src/fighter/state/ground.rs @@ -3,7 +3,7 @@ //! bit-for-bit deterministic for rollback. use crate::fighter::state::{ - FighterState, FighterStateContext, dash, ground_attack, turn, wait, walk, + CollisionContext, FighterState, InterruptContext, dash, ground_attack, turn, wait, walk, }; use crate::fighter::{ FighterAttributes, FighterPreviousTranslation, FighterTranslation, FighterVelocity, @@ -164,13 +164,13 @@ pub fn apply_grounded_motion( } pub fn collide_with_stage_grounded( - state_context: &mut FighterStateContext, + state_context: &mut CollisionContext, ground_common: &mut GroundedStateCommon, can_walk_off: bool, ) -> GroundedMotionResult { let translation = &mut state_context.translation; - let ecb = &state_context.ecb; - let stage_collision = &state_context.stage_collision; + let ecb = state_context.ecb; + let stage_collision = state_context.stage_collision; let stage_poly = stage_collision .stage_polys @@ -322,14 +322,14 @@ mod tests { } pub fn grounded_movement_common_interrupts( - state_context: &FighterStateContext, + state_context: &InterruptContext, ground_common: &GroundedStateCommon, ) -> Option { super::jump::check_input(state_context, ground_common) } pub fn grounded_movement_standstill_common_interrupts( - state_context: &FighterStateContext, + state_context: &InterruptContext, ground_common: &GroundedStateCommon, ) -> Option { if let Some(state) = ground_attack::check_interrupt(state_context, &ground_common) { diff --git a/src/fighter/state/ground_attack.rs b/src/fighter/state/ground_attack.rs index 046b0db..119eb8a 100644 --- a/src/fighter/state/ground_attack.rs +++ b/src/fighter/state/ground_attack.rs @@ -1,6 +1,9 @@ use crate::fighter::{ attack::{AttackKind, update_active_hitbox_list}, - state::{FighterState, FighterStateImpl, ground::GroundedStateCommon, wait::WaitState}, + state::{ + CollisionContext, EnterContext, ExitContext, FighterState, FighterStateImpl, + InterruptContext, UpdateContext, ground::GroundedStateCommon, wait::WaitState, + }, }; #[derive(Clone, Debug, Hash)] @@ -12,10 +15,7 @@ pub struct GroundAttackState { impl FighterStateImpl for GroundAttackState { const NAME: &'static str = "GroundAttack"; - fn check_interrupt( - &self, - state_context: &mut super::FighterStateContext, - ) -> Option { + fn check_interrupt(&self, state_context: &mut InterruptContext) -> Option { if state_context.is_current_animation_finished() { Some(FighterState::Wait(WaitState { grounded_common: self.grounded_common.clone(), @@ -25,7 +25,7 @@ impl FighterStateImpl for GroundAttackState { } } - fn update(&mut self, state_context: &mut super::FighterStateContext) { + fn update(&mut self, state_context: &mut UpdateContext) { let animation_frame = state_context.get_current_animation_frame(); let script = state_context .attack_scripts @@ -44,7 +44,7 @@ impl FighterStateImpl for GroundAttackState { } } - fn on_enter(&mut self, state_context: &mut super::FighterStateContext) { + fn on_enter(&mut self, state_context: &mut EnterContext) { state_context.play_animation(self.attack_kind.get_animation(), false); let script = state_context.attack_script_assets.scripts[&self.attack_kind].clone(); state_context.stale_move_queue.push(self.attack_kind); @@ -57,20 +57,20 @@ impl FighterStateImpl for GroundAttackState { }); } - fn on_exit(&mut self, state_context: &mut super::FighterStateContext) { + fn on_exit(&mut self, state_context: &mut ExitContext) { state_context.hitboxes.0 = None; } fn check_collision_interrupt( &mut self, - _state_context: &mut super::FighterStateContext, + _state_context: &mut CollisionContext, ) -> Option { None } } pub fn check_interrupt( - state_context: &super::FighterStateContext, + state_context: &InterruptContext, grounded_common: &GroundedStateCommon, ) -> Option { if state_context diff --git a/src/fighter/state/hitstun.rs b/src/fighter/state/hitstun.rs index 2e0af3a..cbcd879 100644 --- a/src/fighter/state/hitstun.rs +++ b/src/fighter/state/hitstun.rs @@ -2,9 +2,9 @@ use crate::{ fighter::{ animation::AnimKind, attack::FighterHitReaction, - collision, state::{ - FighterState, FighterStateContext, FighterStateImpl, air, + CollisionContext, EnterContext, ExitContext, FighterState, FighterStateImpl, + InterruptContext, UpdateContext, air, fall::FallState, ground::{GroundedMotionResult, GroundedStateCommon, collide_with_stage_grounded}, land::{LandingState, LandingType}, @@ -43,7 +43,7 @@ impl FighterStateImpl for HitstunState { format!("Hitstun ({hitstop_kind}, {hit_reaction_type})") } - fn check_interrupt(&self, state_context: &mut FighterStateContext) -> Option { + fn check_interrupt(&self, state_context: &mut InterruptContext) -> Option { if state_context.get_current_animation_frame() > self.hit_reaction.hitstun_frames { match &self.hitstop_kind { HitstopStateKind::Grounded(grounded_state_common) => { @@ -58,8 +58,8 @@ impl FighterStateImpl for HitstunState { } } - fn update(&mut self, ctx: &mut FighterStateContext) { - air::integrate_gravity(ctx.velocity, &ctx.fighter_manifest.attributes); + fn update(&mut self, ctx: &mut UpdateContext) { + air::integrate_gravity(ctx.velocity, ctx.fighter_attributes); let speed = ctx.knockback_velocity.length(); let next_speed = speed @@ -71,7 +71,7 @@ impl FighterStateImpl for HitstunState { ctx.translation.0 += ctx.velocity.0 + ctx.knockback_velocity.0; } - fn on_enter(&mut self, state_context: &mut FighterStateContext) { + fn on_enter(&mut self, state_context: &mut EnterContext) { let animation = match self.hitstop_kind { HitstopStateKind::Grounded(_) => AnimKind::FlinchGround, HitstopStateKind::Airborne => AnimKind::FlinchAir, @@ -80,11 +80,11 @@ impl FighterStateImpl for HitstunState { state_context.knockback_velocity.0 = self.hit_reaction.launch_velocity; } - fn on_exit(&mut self, _state_context: &mut FighterStateContext) {} + fn on_exit(&mut self, _state_context: &mut ExitContext) {} fn check_collision_interrupt( &mut self, - state_context: &mut FighterStateContext, + state_context: &mut CollisionContext, ) -> Option { match &mut self.hitstop_kind { HitstopStateKind::Grounded(grounded_state_common) => { @@ -97,7 +97,7 @@ impl FighterStateImpl for HitstunState { } } HitstopStateKind::Airborne => { - if let Some(res) = collision::air_collide_with_stage(state_context) { + if let Some(res) = state_context.air_collide_with_stage() { // Adjust translation state_context.translation.0 = res.hit_position - state_context.ecb.get_bottom_point(); diff --git a/src/fighter/state/jump.rs b/src/fighter/state/jump.rs index 5aa6449..a6d5e03 100644 --- a/src/fighter/state/jump.rs +++ b/src/fighter/state/jump.rs @@ -3,9 +3,9 @@ use bevy::prelude::*; use crate::{ fighter::{ animation::AnimKind, - collision, state::{ - FighterState, FighterStateContext, FighterStateImpl, air, + CollisionContext, EnterContext, FighterState, FighterStateImpl, InterruptContext, + UpdateContext, air, air_dodge::{self, AirDodgeState}, fall::FallState, ground::{self, GroundedMotionResult, GroundedStateCommon}, @@ -45,7 +45,7 @@ impl JumpSquatState { impl FighterStateImpl for JumpSquatState { const NAME: &'static str = "JumpSquat"; - fn check_interrupt(&self, state_context: &mut FighterStateContext) -> Option { + fn check_interrupt(&self, state_context: &mut InterruptContext) -> Option { // Special handling for wavedash from jump squat if state_context.input.has_command(FighterCommands::Shield) { // If aiming sideways and in the deadzone, do a perfect wavedash @@ -69,9 +69,7 @@ impl FighterStateImpl for JumpSquatState { Some(FighterState::AirDodge(AirDodgeState { direction: wavedash_dir.normalize_or_zero(), })) - } else if self.duration_counter - >= state_context.fighter_manifest.attributes.jumpsquat_duration - { + } else if self.duration_counter >= state_context.fighter_attributes.jumpsquat_duration { info!("Jump {}", state_context.input.get_last_frame().jump); let jump_type = if state_context.input.get_last_frame().jump { JumpType::LongJump @@ -84,20 +82,19 @@ impl FighterStateImpl for JumpSquatState { } } - fn update(&mut self, state_context: &mut FighterStateContext) { + fn update(&mut self, state_context: &mut UpdateContext) { self.duration_counter += 1; - let friction = if state_context.velocity.x.abs() - > state_context.fighter_manifest.attributes.max_walk_vel - { - state_context.fighter_manifest.attributes.ground_friction - * state_context - .game_settings - .fighter_common - .ground_friction_over_walk_speed_multiplier - } else { - state_context.fighter_manifest.attributes.ground_friction - }; + let friction = + if state_context.velocity.x.abs() > state_context.fighter_attributes.max_walk_vel { + state_context.fighter_attributes.ground_friction + * state_context + .game_settings + .fighter_common + .ground_friction_over_walk_speed_multiplier + } else { + state_context.fighter_attributes.ground_friction + }; let ground_velocity = state_context.velocity.x; @@ -112,7 +109,7 @@ impl FighterStateImpl for JumpSquatState { fn check_collision_interrupt( &mut self, - state_context: &mut FighterStateContext, + state_context: &mut CollisionContext, ) -> Option { if let GroundedMotionResult::InAir = ground::collide_with_stage_grounded(state_context, &mut self.grounded_common, false) @@ -123,7 +120,7 @@ impl FighterStateImpl for JumpSquatState { } } - fn on_enter(&mut self, state_context: &mut FighterStateContext) { + fn on_enter(&mut self, state_context: &mut EnterContext) { state_context.play_animation(AnimKind::JumpSquat, false); state_context.input.clear_command(FighterCommands::Jump); } @@ -131,7 +128,7 @@ impl FighterStateImpl for JumpSquatState { impl FighterStateImpl for JumpState { const NAME: &'static str = "Jump"; - fn check_interrupt(&self, state_context: &mut FighterStateContext) -> Option { + fn check_interrupt(&self, state_context: &mut InterruptContext) -> Option { if state_context.input.has_command(FighterCommands::Jump) { Some(FighterState::Jump(JumpState { jump_type: JumpType::DoubleJump, @@ -141,14 +138,11 @@ impl FighterStateImpl for JumpState { } } - fn update(&mut self, state_context: &mut FighterStateContext) { - air::integrate_gravity( - state_context.velocity, - &state_context.fighter_manifest.attributes, - ); + fn update(&mut self, state_context: &mut UpdateContext) { + air::integrate_gravity(state_context.velocity, state_context.fighter_attributes); air::apply_air_drift( state_context.velocity, - &state_context.fighter_manifest.attributes, + state_context.fighter_attributes, state_context.input, ); air::apply_air_motion( @@ -158,7 +152,7 @@ impl FighterStateImpl for JumpState { ); } - fn on_enter(&mut self, state_context: &mut FighterStateContext) { + fn on_enter(&mut self, state_context: &mut EnterContext) { if let JumpType::DoubleJump = self.jump_type { state_context.input.clear_command(FighterCommands::Jump); } @@ -185,42 +179,22 @@ impl FighterStateImpl for JumpState { } let vertical_vel = match self.jump_type { - JumpType::ShortHop => { - state_context - .fighter_manifest - .attributes - .short_hop_vertical_velocity - } - JumpType::LongJump => { - state_context - .fighter_manifest - .attributes - .full_jump_vertical_velocity - } + JumpType::ShortHop => state_context.fighter_attributes.short_hop_vertical_velocity, + JumpType::LongJump => state_context.fighter_attributes.full_jump_vertical_velocity, JumpType::DoubleJump => { - state_context - .fighter_manifest - .attributes - .full_jump_vertical_velocity - * state_context - .fighter_manifest - .attributes - .air_jump_multiplier + state_context.fighter_attributes.full_jump_vertical_velocity + * state_context.fighter_attributes.air_jump_multiplier } }; match self.jump_type { JumpType::ShortHop | JumpType::LongJump => { - state_context.velocity.x += state_context - .fighter_manifest - .attributes - .jump_horizontal_velocity - * movement_stick_x; + state_context.velocity.x += + state_context.fighter_attributes.jump_horizontal_velocity * movement_stick_x; } JumpType::DoubleJump => { state_context.velocity.x = state_context - .fighter_manifest - .attributes + .fighter_attributes .air_jump_horizontal_velocity * movement_stick_x; } @@ -231,9 +205,9 @@ impl FighterStateImpl for JumpState { fn check_collision_interrupt( &mut self, - state_context: &mut FighterStateContext, + state_context: &mut CollisionContext, ) -> Option { - if let Some(res) = collision::air_collide_with_stage(state_context) { + if let Some(res) = state_context.air_collide_with_stage() { // Adjust translation state_context.translation.0 = res.hit_position - state_context.ecb.get_bottom_point(); let grounded_common = GroundedStateCommon { @@ -250,7 +224,7 @@ impl FighterStateImpl for JumpState { } pub fn check_input( - state_context: &FighterStateContext, + state_context: &InterruptContext, ground_common: &GroundedStateCommon, ) -> Option { state_context @@ -259,7 +233,7 @@ pub fn check_input( .then(|| FighterState::JumpSquat(JumpSquatState::create(ground_common.clone()))) } -pub fn check_input_double_jump(state_context: &FighterStateContext) -> Option { +pub fn check_input_double_jump(state_context: &InterruptContext) -> Option { state_context .input .has_command(FighterCommands::Jump) diff --git a/src/fighter/state/land.rs b/src/fighter/state/land.rs index 195c920..e4df973 100644 --- a/src/fighter/state/land.rs +++ b/src/fighter/state/land.rs @@ -1,7 +1,8 @@ use crate::fighter::{ animation::AnimKind, state::{ - FighterState, FighterStateContext, FighterStateImpl, dash, + CollisionContext, EnterContext, FighterState, FighterStateImpl, InterruptContext, + UpdateContext, dash, fall::FallState, ground::{ self, GroundedMotionResult, GroundedStateCommon, @@ -35,11 +36,11 @@ impl LandingState { impl FighterStateImpl for LandingState { const NAME: &'static str = "Landing"; - fn check_interrupt(&self, state_context: &mut FighterStateContext) -> Option { + fn check_interrupt(&self, state_context: &mut InterruptContext) -> Option { if state_context.is_current_animation_finished() { grounded_movement_standstill_common_interrupts(state_context, &self.grounded_common) } else if state_context.get_current_animation_frame() - >= state_context.fighter_manifest.attributes.landing_iasa + >= state_context.fighter_attributes.landing_iasa && let LandingType::Normal = self.landing_type { dash::check_input(state_context, &self.grounded_common).or_else(|| { @@ -51,18 +52,17 @@ impl FighterStateImpl for LandingState { } } - fn update(&mut self, state_context: &mut FighterStateContext) { - let friction = if state_context.velocity.x.abs() - > state_context.fighter_manifest.attributes.max_walk_vel - { - state_context.fighter_manifest.attributes.ground_friction - * state_context - .game_settings - .fighter_common - .ground_friction_over_walk_speed_multiplier - } else { - state_context.fighter_manifest.attributes.ground_friction - }; + fn update(&mut self, state_context: &mut UpdateContext) { + let friction = + if state_context.velocity.x.abs() > state_context.fighter_attributes.max_walk_vel { + state_context.fighter_attributes.ground_friction + * state_context + .game_settings + .fighter_common + .ground_friction_over_walk_speed_multiplier + } else { + state_context.fighter_attributes.ground_friction + }; let ground_velocity = state_context.velocity.x; @@ -77,7 +77,7 @@ impl FighterStateImpl for LandingState { fn check_collision_interrupt( &mut self, - state_context: &mut FighterStateContext, + state_context: &mut CollisionContext, ) -> Option { if let GroundedMotionResult::InAir = ground::collide_with_stage_grounded(state_context, &mut self.grounded_common, true) @@ -88,7 +88,7 @@ impl FighterStateImpl for LandingState { } } - fn on_enter(&mut self, state_context: &mut FighterStateContext) { + fn on_enter(&mut self, state_context: &mut EnterContext) { match self.landing_type { LandingType::Normal => { state_context.play_animation(AnimKind::Landing, false); diff --git a/src/fighter/state/mod.rs b/src/fighter/state/mod.rs index b68118b..65adbfa 100644 --- a/src/fighter/state/mod.rs +++ b/src/fighter/state/mod.rs @@ -10,6 +10,7 @@ use crate::fighter::attack::{ FighterAttackScriptAssets, FighterKnockbackVelocity, FighterPendingHitReaction, FighterStaleMoveQueue, }; +use crate::fighter::attributes::FighterAttributes; use crate::fighter::baked_animation::BakedFighterAnimations; use crate::fighter::ecb::FighterPreviousECB; use crate::fighter::manifest::FighterManifest; @@ -47,22 +48,22 @@ macro_rules! fighter_states { pub fn name(&self) -> &'static str { match self { $(Self::$variant(_) => <$ty>::NAME),* } } - pub fn check_interrupt(&self, ctx: &mut FighterStateContext) -> Option { + pub fn check_interrupt(&self, ctx: &mut InterruptContext) -> Option { match self { $(Self::$variant(s) => s.check_interrupt(ctx)),* } } - pub fn update(&mut self, ctx: &mut FighterStateContext) { + pub fn update(&mut self, ctx: &mut UpdateContext) { match self { $(Self::$variant(s) => s.update(ctx)),* } } - pub fn on_enter(&mut self, ctx: &mut FighterStateContext) { + pub fn on_enter(&mut self, ctx: &mut EnterContext) { match self { $(Self::$variant(s) => s.on_enter(ctx)),* } } - pub fn on_exit(&mut self, ctx: &mut FighterStateContext) { + pub fn on_exit(&mut self, ctx: &mut ExitContext) { match self { $(Self::$variant(s) => s.on_exit(ctx)),* } } - pub fn check_collision_interrupt(&mut self, ctx: &mut FighterStateContext) -> Option { + pub fn check_collision_interrupt(&mut self, ctx: &mut CollisionContext) -> Option { match self { $(Self::$variant(s) => s.check_collision_interrupt(ctx)),* } } } @@ -75,62 +76,108 @@ macro_rules! fighter_states { pub trait FighterStateImpl: Sized { const NAME: &'static str; - fn check_interrupt(&self, state_context: &mut FighterStateContext) -> Option; + fn check_interrupt(&self, state_context: &mut InterruptContext) -> Option; - fn on_enter(&mut self, _state_context: &mut FighterStateContext) {} - fn on_exit(&mut self, _state_context: &mut FighterStateContext) {} + fn on_enter(&mut self, _state_context: &mut EnterContext) {} + fn on_exit(&mut self, _state_context: &mut ExitContext) {} fn name(&self) -> String { Self::NAME.to_owned() } - fn update(&mut self, _state_context: &mut FighterStateContext); + fn update(&mut self, _state_context: &mut UpdateContext); fn check_collision_interrupt( &mut self, - _state_context: &mut FighterStateContext, + _state_context: &mut CollisionContext, ) -> Option { None } } -pub struct FighterStateContext<'a> { - pub translation: &'a mut FighterTranslation, - pub prev_translation: &'a mut FighterPreviousTranslation, +pub struct AnimationStatus { + pub frame: u32, + pub finished: bool, +} + +pub struct InterruptContext<'a> { + pub input: &'a FighterInput, + pub facing_direction: &'a mut FighterFacingDirection, + pub game_settings: &'a GameSettings, + pub fighter_attributes: &'a FighterAttributes, + pub animation: AnimationStatus, +} + +impl InterruptContext<'_> { + pub fn get_current_animation_frame(&self) -> u32 { + self.animation.frame + } + + pub fn is_current_animation_finished(&self) -> bool { + self.animation.finished + } +} + +pub struct EnterContext<'a> { pub input: &'a mut FighterInput, pub hitboxes: &'a mut FighterHitboxes, pub velocity: &'a mut FighterVelocity, pub knockback_velocity: &'a mut FighterKnockbackVelocity, pub stale_move_queue: &'a mut FighterStaleMoveQueue, - pub ecb: &'a mut FighterECB, - pub prev_ecb: &'a mut FighterPreviousECB, pub facing_direction: &'a mut FighterFacingDirection, - pub game_settings: &'a GameSettings, - pub stage_collision: &'a StageCollision, - pub animations: &'a FighterAnimations, pub animation_frame: &'a mut FighterAnimationFrame, - pub baked_animations: &'a Assets, - pub attack_scripts: &'a Assets, - pub fighter_manifest: &'a FighterManifest, + pub fighter_attributes: &'a FighterAttributes, pub attack_script_assets: &'a FighterAttackScriptAssets, } -impl FighterStateContext<'_> { +impl EnterContext<'_> { pub fn play_animation(&mut self, kind: AnimKind, repeat: bool) { self.animation_frame.reset(kind, repeat); } +} +pub struct ExitContext<'a> { + pub hitboxes: &'a mut FighterHitboxes, +} + +pub struct UpdateContext<'a> { + pub translation: &'a mut FighterTranslation, + pub prev_translation: &'a mut FighterPreviousTranslation, + pub input: &'a FighterInput, + pub hitboxes: &'a mut FighterHitboxes, + pub velocity: &'a mut FighterVelocity, + pub knockback_velocity: &'a mut FighterKnockbackVelocity, + pub game_settings: &'a GameSettings, + pub animation_frame: u32, + pub fighter_attributes: &'a FighterAttributes, + pub attack_scripts: &'a Assets, + pub attack_script_assets: &'a FighterAttackScriptAssets, +} + +impl UpdateContext<'_> { pub fn get_current_animation_frame(&self) -> u32 { - self.animation_frame.frame + self.animation_frame } +} - pub fn is_current_animation_finished(&self) -> bool { - let anims_data = self - .baked_animations - .get(&self.animations.baked) - .expect("Animation should exist"); - anims_data - .frame_count(self.animation_frame.kind) - .expect("Current animation should have baked frames") - <= self.animation_frame.frame +pub struct CollisionContext<'a> { + pub translation: &'a mut FighterTranslation, + pub prev_translation: &'a FighterPreviousTranslation, + pub velocity: &'a mut FighterVelocity, + pub ecb: &'a FighterECB, + pub prev_ecb: &'a FighterPreviousECB, + pub stage_collision: &'a StageCollision, +} + +impl CollisionContext<'_> { + pub fn air_collide_with_stage( + &self, + ) -> Option { + crate::fighter::collision::air_collide_with_stage( + self.prev_translation, + self.translation, + self.prev_ecb, + self.ecb, + self.stage_collision, + ) } } @@ -159,43 +206,104 @@ pub struct FighterFrameQuery { pub velocity: &'static mut FighterVelocity, pub knockback_velocity: &'static mut FighterKnockbackVelocity, pub stale_move_queue: &'static mut FighterStaleMoveQueue, - pub ecb: &'static mut FighterECB, - pub prev_ecb: &'static mut FighterPreviousECB, + pub ecb: &'static FighterECB, + pub prev_ecb: &'static FighterPreviousECB, pub facing_direction: &'static mut FighterFacingDirection, pub animation_frame: &'static mut FighterAnimationFrame, pub fighter: &'static Fighter, } impl<'w, 's> FighterFrameQueryItem<'w, 's> { - fn context<'a>( + fn animation_status( + &self, + animations: &FighterAnimations, + baked_animations: &Assets, + ) -> AnimationStatus { + let baked = baked_animations + .get(&animations.baked) + .expect("Animation should exist"); + let frame = self.animation_frame.frame; + let finished = baked + .frame_count(self.animation_frame.kind) + .expect("Current animation should have baked frames") + <= frame; + AnimationStatus { frame, finished } + } + + fn interrupt_context<'a>( &'a mut self, game_settings: &'a GameSettings, - stage_collision: &'a StageCollision, animations: &'a FighterAnimations, baked_animations: &'a Assets, - attack_scripts: &'a Assets, + attributes: &'a FighterAttributes, + ) -> InterruptContext<'a> { + let animation = self.animation_status(animations, baked_animations); + InterruptContext { + input: &self.input, + facing_direction: &mut self.facing_direction, + game_settings, + fighter_attributes: attributes, + animation, + } + } + + fn enter_context<'a>( + &'a mut self, + attributes: &'a FighterAttributes, attack_script_assets: &'a FighterAttackScriptAssets, - manifest: &'a FighterManifest, - ) -> FighterStateContext<'a> { - FighterStateContext { - translation: &mut self.translation, - prev_translation: &mut self.prev_translation, + ) -> EnterContext<'a> { + EnterContext { input: &mut self.input, hitboxes: &mut self.hitboxes, velocity: &mut self.velocity, knockback_velocity: &mut self.knockback_velocity, stale_move_queue: &mut self.stale_move_queue, - ecb: &mut self.ecb, - prev_ecb: &mut self.prev_ecb, facing_direction: &mut self.facing_direction, - game_settings, - stage_collision, - animations, animation_frame: &mut self.animation_frame, - baked_animations, + fighter_attributes: attributes, + attack_script_assets, + } + } + + fn exit_context(&mut self) -> ExitContext<'_> { + ExitContext { + hitboxes: &mut self.hitboxes, + } + } + + fn update_context<'a>( + &'a mut self, + game_settings: &'a GameSettings, + attributes: &'a FighterAttributes, + attack_scripts: &'a Assets, + attack_script_assets: &'a FighterAttackScriptAssets, + ) -> UpdateContext<'a> { + UpdateContext { + translation: &mut self.translation, + prev_translation: &mut self.prev_translation, + input: &self.input, + hitboxes: &mut self.hitboxes, + velocity: &mut self.velocity, + knockback_velocity: &mut self.knockback_velocity, + game_settings, + animation_frame: self.animation_frame.frame, + fighter_attributes: attributes, attack_scripts, attack_script_assets, - fighter_manifest: manifest, + } + } + + fn collision_context<'a>( + &'a mut self, + stage_collision: &'a StageCollision, + ) -> CollisionContext<'a> { + CollisionContext { + translation: &mut self.translation, + prev_translation: &self.prev_translation, + velocity: &mut self.velocity, + ecb: &self.ecb, + prev_ecb: &self.prev_ecb, + stage_collision, } } } @@ -214,9 +322,7 @@ pub struct StatefulFighterQuery { pub fn state_update_system( mut query: Query, - stage_collision: Res, game_settings: Res, - baked_animations: Res>, attack_scripts: Res>, manifests: Res>, ) { @@ -224,7 +330,6 @@ pub fn state_update_system( let StatefulFighterQueryItem { mut state, mut frame, - animations, hitstop, .. } = fighter; @@ -233,16 +338,14 @@ pub fn state_update_system( continue; } - let mut update_ctx = frame.context( + let manifest = manifests + .get(&fighter.fighter.manifest) + .expect("Fighter manifest should be valid"); + let mut update_ctx = frame.update_context( &game_settings, - &stage_collision, - animations, - &baked_animations, + &manifest.attributes, &attack_scripts, &fighter.attack_script_assets, - &manifests - .get(&(fighter.fighter.manifest)) - .expect("Fighter manifest should be valid"), ); state.update(&mut update_ctx); } @@ -251,24 +354,24 @@ pub fn state_update_system( fn transition_state( current: &mut FighterState, mut next: FighterState, - ctx: &mut FighterStateContext, + frame: &mut FighterFrameQueryItem, + attributes: &FighterAttributes, + attack_script_assets: &FighterAttackScriptAssets, ) { let old_name = current.name(); let new_name = next.name(); - current.on_exit(ctx); - next.on_enter(ctx); + current.on_exit(&mut frame.exit_context()); + next.on_enter(&mut frame.enter_context(attributes, attack_script_assets)); *current = next; info!("{} -> {}", old_name, new_name); } pub fn state_interrupt_system( mut query: Query, - stage_collision: Res, game_settings: Res, baked_animations: Res>, fighter_manifests: Res>, - attack_scripts: Res>, ) { for fighter in &mut query { let StatefulFighterQueryItem { @@ -280,17 +383,9 @@ pub fn state_interrupt_system( mut pending_hit_reaction, mut hitstop, } = fighter; - let mut state_context = frame.context( - &game_settings, - &stage_collision, - animations, - &baked_animations, - &attack_scripts, - attack_script_assets, - fighter_manifests - .get(&fighter.manifest) - .expect("Fighter manifest should be valid"), - ); + let manifest = fighter_manifests + .get(&fighter.manifest) + .expect("Fighter manifest should be valid"); let new_state = if let Some(reaction) = pending_hit_reaction.take() { hitstop.remaining_frames = *reaction.hitstop_frames; @@ -322,11 +417,22 @@ pub fn state_interrupt_system( } else if hitstop.remaining_frames > 0 { None } else { - state.check_interrupt(&mut state_context) + state.check_interrupt(&mut frame.interrupt_context( + &game_settings, + animations, + &baked_animations, + &manifest.attributes, + )) }; if let Some(new_state) = new_state { - transition_state(&mut state, new_state, &mut state_context); + transition_state( + &mut state, + new_state, + &mut frame, + &manifest.attributes, + attack_script_assets, + ); }; } } @@ -334,39 +440,34 @@ pub fn state_interrupt_system( pub fn state_collision_interrupt_system( mut query: Query, stage_collision: Res, - game_settings: Res, - baked_animations: Res>, fighter_manifests: Res>, - attack_scripts: Res>, ) { for fighter in &mut query { let StatefulFighterQueryItem { mut state, mut frame, - animations, fighter, attack_script_assets, hitstop, .. } = fighter; - let mut state_context = frame.context( - &game_settings, - &stage_collision, - animations, - &baked_animations, - &attack_scripts, - &attack_script_assets, - fighter_manifests - .get(&fighter.manifest) - .expect("Fighter manifest should be valid"), - ); - if hitstop.remaining_frames > 0 { continue; } - if let Some(new_state) = state.check_collision_interrupt(&mut state_context) { - transition_state(&mut state, new_state, &mut state_context); + let manifest = fighter_manifests + .get(&fighter.manifest) + .expect("Fighter manifest should be valid"); + let new_state = + state.check_collision_interrupt(&mut frame.collision_context(&stage_collision)); + if let Some(new_state) = new_state { + transition_state( + &mut state, + new_state, + &mut frame, + &manifest.attributes, + &attack_script_assets, + ); } } } diff --git a/src/fighter/state/run.rs b/src/fighter/state/run.rs index e3fcedf..8510fa7 100644 --- a/src/fighter/state/run.rs +++ b/src/fighter/state/run.rs @@ -1,6 +1,9 @@ use bevy::prelude::*; -use super::{FighterStateContext, FighterStateImpl, ground, wait, walk}; +use super::{ + CollisionContext, EnterContext, FighterStateImpl, InterruptContext, UpdateContext, ground, + wait, walk, +}; use crate::fighter::animation::AnimKind; use crate::fighter::state::FighterState; use crate::fighter::state::fall::FallState; @@ -14,7 +17,7 @@ pub struct RunState { impl FighterStateImpl for RunState { const NAME: &'static str = "Run"; - fn check_interrupt(&self, state_context: &mut FighterStateContext) -> Option { + fn check_interrupt(&self, state_context: &mut InterruptContext) -> Option { if let Some(state) = ground::grounded_movement_common_interrupts(state_context, &self.grounded_common) { @@ -32,21 +35,20 @@ impl FighterStateImpl for RunState { } } - fn on_enter(&mut self, state_context: &mut super::FighterStateContext) { + fn on_enter(&mut self, state_context: &mut EnterContext) { state_context.play_animation(AnimKind::Run, true); } - fn update(&mut self, state_context: &mut super::FighterStateContext) { + fn update(&mut self, state_context: &mut UpdateContext) { let last_frame = state_context.input.get_last_frame(); let (accel, target_vel) = state_context - .fighter_manifest - .attributes + .fighter_attributes .get_accel_and_target_dashrun(&last_frame, FGi32::ONE); let accel = ground::compute_ground_accel( accel, target_vel, state_context.velocity.x, - &state_context.fighter_manifest.attributes, + state_context.fighter_attributes, state_context.game_settings, ); state_context.velocity.x += accel; @@ -60,7 +62,7 @@ impl FighterStateImpl for RunState { fn check_collision_interrupt( &mut self, - state_context: &mut FighterStateContext, + state_context: &mut CollisionContext, ) -> Option { if let GroundedMotionResult::InAir = ground::collide_with_stage_grounded(state_context, &mut self.grounded_common, false) @@ -73,7 +75,7 @@ impl FighterStateImpl for RunState { } pub fn check_input( - state_context: &FighterStateContext, + state_context: &InterruptContext, ground_state_common: &GroundedStateCommon, ) -> Option { let input_frame = state_context.input.get_last_frame(); diff --git a/src/fighter/state/turn.rs b/src/fighter/state/turn.rs index 9b660e1..a24d242 100644 --- a/src/fighter/state/turn.rs +++ b/src/fighter/state/turn.rs @@ -1,4 +1,4 @@ -use super::{FighterStateContext, FighterStateImpl}; +use super::{CollisionContext, EnterContext, FighterStateImpl, InterruptContext, UpdateContext}; use crate::fighter::animation::AnimKind; use crate::fighter::state::fall::FallState; use crate::fighter::state::ground::{self, GroundedMotionResult, GroundedStateCommon}; @@ -12,7 +12,7 @@ pub struct TurnState { impl FighterStateImpl for TurnState { const NAME: &'static str = "Turn"; - fn check_interrupt(&self, state_context: &mut FighterStateContext) -> Option { + fn check_interrupt(&self, state_context: &mut InterruptContext) -> Option { // State chain that results in the turn completing if state_context.get_current_animation_frame() <= state_context @@ -42,23 +42,22 @@ impl FighterStateImpl for TurnState { } } - fn on_enter(&mut self, state_context: &mut super::FighterStateContext) { + fn on_enter(&mut self, state_context: &mut EnterContext) { state_context.play_animation(AnimKind::Turn, false); *state_context.facing_direction = state_context.facing_direction.reverse(); } - fn update(&mut self, state_context: &mut super::FighterStateContext) { - let friction = if state_context.velocity.x.abs() - > state_context.fighter_manifest.attributes.max_walk_vel - { - state_context.fighter_manifest.attributes.ground_friction - * state_context - .game_settings - .fighter_common - .ground_friction_over_walk_speed_multiplier - } else { - state_context.fighter_manifest.attributes.ground_friction - }; + fn update(&mut self, state_context: &mut UpdateContext) { + let friction = + if state_context.velocity.x.abs() > state_context.fighter_attributes.max_walk_vel { + state_context.fighter_attributes.ground_friction + * state_context + .game_settings + .fighter_common + .ground_friction_over_walk_speed_multiplier + } else { + state_context.fighter_attributes.ground_friction + }; let ground_velocity = state_context.velocity.x; @@ -73,7 +72,7 @@ impl FighterStateImpl for TurnState { fn check_collision_interrupt( &mut self, - state_context: &mut FighterStateContext, + state_context: &mut CollisionContext, ) -> Option { if let GroundedMotionResult::InAir = ground::collide_with_stage_grounded(state_context, &mut self.grounded_common, false) @@ -86,7 +85,7 @@ impl FighterStateImpl for TurnState { } pub fn check_input( - state_context: &FighterStateContext, + state_context: &InterruptContext, grounded_common: &GroundedStateCommon, ) -> Option { let input_frame = state_context.input.get_last_frame(); diff --git a/src/fighter/state/wait.rs b/src/fighter/state/wait.rs index 8bf11fd..6b0bf57 100644 --- a/src/fighter/state/wait.rs +++ b/src/fighter/state/wait.rs @@ -1,4 +1,6 @@ -use super::{FighterStateContext, FighterStateImpl, ground}; +use super::{ + CollisionContext, EnterContext, FighterStateImpl, InterruptContext, UpdateContext, ground, +}; use crate::fighter::animation::AnimKind; use crate::fighter::state::FighterState; use crate::fighter::state::fall::FallState; @@ -11,7 +13,7 @@ pub struct WaitState { impl FighterStateImpl for WaitState { const NAME: &'static str = "Wait"; - fn check_interrupt(&self, state_context: &mut FighterStateContext) -> Option { + fn check_interrupt(&self, state_context: &mut InterruptContext) -> Option { if let Some(state) = ground::grounded_movement_common_interrupts(state_context, &self.grounded_common) { @@ -31,22 +33,21 @@ impl FighterStateImpl for WaitState { } } - fn on_enter(&mut self, state_context: &mut super::FighterStateContext) { + fn on_enter(&mut self, state_context: &mut EnterContext) { state_context.play_animation(AnimKind::Wait, true); } - fn update(&mut self, state_context: &mut super::FighterStateContext) { - let friction = if state_context.velocity.x.abs() - > state_context.fighter_manifest.attributes.max_walk_vel - { - state_context.fighter_manifest.attributes.ground_friction - * state_context - .game_settings - .fighter_common - .ground_friction_over_walk_speed_multiplier - } else { - state_context.fighter_manifest.attributes.ground_friction - }; + fn update(&mut self, state_context: &mut UpdateContext) { + let friction = + if state_context.velocity.x.abs() > state_context.fighter_attributes.max_walk_vel { + state_context.fighter_attributes.ground_friction + * state_context + .game_settings + .fighter_common + .ground_friction_over_walk_speed_multiplier + } else { + state_context.fighter_attributes.ground_friction + }; let ground_velocity = state_context.velocity.x; @@ -61,7 +62,7 @@ impl FighterStateImpl for WaitState { fn check_collision_interrupt( &mut self, - state_context: &mut FighterStateContext, + state_context: &mut CollisionContext, ) -> Option { if let GroundedMotionResult::InAir = ground::collide_with_stage_grounded(state_context, &mut self.grounded_common, false) @@ -74,7 +75,7 @@ impl FighterStateImpl for WaitState { } pub fn check_input( - state_context: &FighterStateContext, + state_context: &InterruptContext, ground_state_common: &GroundedStateCommon, ) -> Option { let input_frame = state_context.input.get_last_frame(); diff --git a/src/fighter/state/walk.rs b/src/fighter/state/walk.rs index 693b3dc..8fa2f42 100644 --- a/src/fighter/state/walk.rs +++ b/src/fighter/state/walk.rs @@ -1,4 +1,7 @@ -use super::{FighterStateContext, FighterStateImpl, dash, ground, wait}; +use super::{ + CollisionContext, EnterContext, FighterStateImpl, InterruptContext, UpdateContext, dash, + ground, wait, +}; use crate::fighter::animation::AnimKind; use crate::fighter::state::FighterState; use crate::fighter::state::fall::FallState; @@ -11,7 +14,7 @@ pub struct WalkState { impl FighterStateImpl for WalkState { const NAME: &'static str = "Walk"; - fn check_interrupt(&self, state_context: &mut FighterStateContext) -> Option { + fn check_interrupt(&self, state_context: &mut InterruptContext) -> Option { if let Some(state) = ground::grounded_movement_common_interrupts(state_context, &self.grounded_common) { @@ -21,22 +24,21 @@ impl FighterStateImpl for WalkState { .or_else(|| dash::check_input(state_context, &self.grounded_common)) } - fn on_enter(&mut self, state_context: &mut FighterStateContext) { + fn on_enter(&mut self, state_context: &mut EnterContext) { state_context.play_animation(AnimKind::Walk, true); } - fn update(&mut self, state_context: &mut FighterStateContext) { + fn update(&mut self, state_context: &mut UpdateContext) { let last_frame = state_context.input.get_last_frame(); let (accel, target_vel) = state_context - .fighter_manifest - .attributes + .fighter_attributes .get_accel_and_target_walk(&last_frame); let accel = ground::compute_ground_accel( accel, target_vel, state_context.velocity.x, - &state_context.fighter_manifest.attributes, + state_context.fighter_attributes, &state_context.game_settings, ); @@ -51,7 +53,7 @@ impl FighterStateImpl for WalkState { fn check_collision_interrupt( &mut self, - state_context: &mut FighterStateContext, + state_context: &mut CollisionContext, ) -> Option { if let GroundedMotionResult::InAir = ground::collide_with_stage_grounded(state_context, &mut self.grounded_common, false) @@ -64,7 +66,7 @@ impl FighterStateImpl for WalkState { } pub fn check_input( - state_context: &FighterStateContext, + state_context: &InterruptContext, ground_state_common: &GroundedStateCommon, ) -> Option { let input_frame = state_context.input.get_last_frame();