Compare commits
4
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5e7529a3ac | ||
|
|
b8b65e60e9 | ||
|
|
43a04e9491 | ||
|
|
cd9c39b70c |
+1
-1
@@ -1,7 +1,7 @@
|
||||
# for Linux
|
||||
[target.x86_64-unknown-linux-gnu]
|
||||
linker = "clang"
|
||||
rustflags = ["-C", "link-arg=-fuse-ld=/usr/bin/mold", "-Zshare-generics=y", ]
|
||||
rustflags = ["-C", "link-arg=-fuse-ld=/usr/bin/mold", "-Zshare-generics=y", "-D", "warnings", ]
|
||||
|
||||
[unstable]
|
||||
codegen-backend = true
|
||||
|
||||
@@ -25,6 +25,7 @@ jobs:
|
||||
- name: Cache Rust dependencies and build artifacts
|
||||
uses: Swatinem/rust-cache@779680da715d629ac1d338a641029a2f4372abb5 # v2.8.2
|
||||
with:
|
||||
prefix-key: v1-rust
|
||||
shared-key: linux-nightly
|
||||
cache-bin: false
|
||||
|
||||
@@ -45,7 +46,7 @@ jobs:
|
||||
pkg-config
|
||||
|
||||
- name: Build
|
||||
run: RUSTFLAGS="-D warnings" cargo build --locked -j 4
|
||||
run: cargo build --locked -j 4
|
||||
|
||||
- name: Run unit tests
|
||||
run: cargo test --locked --lib -j 4
|
||||
|
||||
@@ -14,6 +14,8 @@ use enum_cycling_derive::EnumCycle;
|
||||
|
||||
use crate::{AppState, player::Player, replay::StopReplayRecording};
|
||||
|
||||
mod save_state;
|
||||
|
||||
pub const PLAYER_DEBUG_ROW_COUNT: usize = 6;
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Reflect)]
|
||||
@@ -378,6 +380,9 @@ impl Plugin for DebugToolsPlugin {
|
||||
fn build(&self, app: &mut App) {
|
||||
app.init_resource::<DebugSettings>()
|
||||
.init_resource::<FrameStepState>()
|
||||
.init_resource::<save_state::DebugSaveState>()
|
||||
.add_systems(OnEnter(AppState::InMatch), save_state::clear)
|
||||
.add_systems(OnExit(AppState::InMatch), save_state::clear)
|
||||
.add_systems(
|
||||
PreUpdate,
|
||||
prepare_frame_step
|
||||
@@ -385,6 +390,13 @@ impl Plugin for DebugToolsPlugin {
|
||||
.before(RunGgrsSystems)
|
||||
.run_if(in_state(AppState::InMatch)),
|
||||
)
|
||||
.add_systems(
|
||||
PreUpdate,
|
||||
save_state::save_or_restore
|
||||
.after(InputSystems)
|
||||
.before(RunGgrsSystems)
|
||||
.run_if(in_state(AppState::InMatch)),
|
||||
)
|
||||
.add_systems(PreUpdate, restore_frame_step_time.after(RunGgrsSystems))
|
||||
.add_systems(
|
||||
Update,
|
||||
|
||||
@@ -0,0 +1,196 @@
|
||||
use bevy::prelude::*;
|
||||
|
||||
use crate::{
|
||||
camera::MatchCamera,
|
||||
fighter::{
|
||||
FighterECB, FighterFacingDirection, FighterHitboxes, FighterHitstop,
|
||||
FighterPreviousFacingDirection, FighterPreviousTranslation, FighterTranslation,
|
||||
FighterVelocity, Grounded,
|
||||
animation::FighterAnimationFrame,
|
||||
attack::{
|
||||
FighterDamage, FighterKnockbackVelocity, FighterPendingHitReaction,
|
||||
FighterReceivedAttacks, FighterSolvedHurtboxes, FighterStaleMoveQueue,
|
||||
},
|
||||
baked_animation::FighterBoneMatrices,
|
||||
state::FighterState,
|
||||
},
|
||||
input::FighterInput,
|
||||
player::Player,
|
||||
stage::line::StageCollision,
|
||||
};
|
||||
|
||||
#[derive(Resource, Default)]
|
||||
pub(super) struct DebugSaveState {
|
||||
checkpoint: Option<Checkpoint>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct Checkpoint {
|
||||
fighters: Vec<FighterCheckpoint>,
|
||||
stage_collision: StageCollision,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct FighterCheckpoint {
|
||||
entity: Entity,
|
||||
handle: usize,
|
||||
ecb: FighterECB,
|
||||
previous_ecb: crate::fighter::ecb::FighterPreviousECB,
|
||||
velocity: FighterVelocity,
|
||||
translation: FighterTranslation,
|
||||
previous_translation: FighterPreviousTranslation,
|
||||
facing: FighterFacingDirection,
|
||||
previous_facing: FighterPreviousFacingDirection,
|
||||
animation: FighterAnimationFrame,
|
||||
state: FighterState,
|
||||
input: FighterInput,
|
||||
damage: FighterDamage,
|
||||
pending_hit_reaction: FighterPendingHitReaction,
|
||||
hitstop: FighterHitstop,
|
||||
knockback_velocity: FighterKnockbackVelocity,
|
||||
stale_moves: FighterStaleMoveQueue,
|
||||
hitboxes: FighterHitboxes,
|
||||
received_attacks: FighterReceivedAttacks,
|
||||
solved_hurtboxes: FighterSolvedHurtboxes,
|
||||
bone_matrices: FighterBoneMatrices,
|
||||
grounded: bool,
|
||||
}
|
||||
|
||||
pub(super) fn save_or_restore(world: &mut World) {
|
||||
if world.resource::<super::DebugSettings>().menu_open {
|
||||
return;
|
||||
}
|
||||
|
||||
let left = world
|
||||
.query::<&Gamepad>()
|
||||
.iter(world)
|
||||
.any(|gamepad| gamepad.just_pressed(GamepadButton::DPadLeft));
|
||||
let right = world
|
||||
.query::<&Gamepad>()
|
||||
.iter(world)
|
||||
.any(|gamepad| gamepad.just_pressed(GamepadButton::DPadRight));
|
||||
|
||||
if left == right {
|
||||
return;
|
||||
}
|
||||
|
||||
let Some(roster) = world
|
||||
.get_resource::<crate::fighter::FighterRoster>()
|
||||
.map(|roster| roster.0.clone())
|
||||
else {
|
||||
return;
|
||||
};
|
||||
if roster.len() != 1 {
|
||||
warn!("Save states are only available in single-player matches");
|
||||
return;
|
||||
}
|
||||
|
||||
if left {
|
||||
let Some(stage_collision) = world.get_resource::<StageCollision>().cloned() else {
|
||||
return;
|
||||
};
|
||||
let mut checkpoint_fighters = Vec::with_capacity(roster.len());
|
||||
for entity in roster.iter().copied() {
|
||||
let Some(checkpoint) = capture_fighter(world, entity) else {
|
||||
warn!("Could not save the current fighter state");
|
||||
return;
|
||||
};
|
||||
checkpoint_fighters.push(checkpoint);
|
||||
}
|
||||
world.resource_mut::<DebugSaveState>().checkpoint = Some(Checkpoint {
|
||||
fighters: checkpoint_fighters,
|
||||
stage_collision,
|
||||
});
|
||||
info!("Saved debug game state");
|
||||
return;
|
||||
}
|
||||
|
||||
let Some(checkpoint) = world.resource::<DebugSaveState>().checkpoint.clone() else {
|
||||
warn!("No debug game state has been saved");
|
||||
return;
|
||||
};
|
||||
if checkpoint.fighters.len() != roster.len()
|
||||
|| checkpoint
|
||||
.fighters
|
||||
.iter()
|
||||
.zip(roster.iter())
|
||||
.any(|(saved, current)| saved.entity != *current)
|
||||
{
|
||||
warn!("Saved debug game state belongs to another match");
|
||||
return;
|
||||
}
|
||||
|
||||
for saved in &checkpoint.fighters {
|
||||
let Some(player) = world.entity(saved.entity).get::<Player>() else {
|
||||
warn!("Could not restore the saved fighter state");
|
||||
return;
|
||||
};
|
||||
if player.handle != saved.handle {
|
||||
warn!("Saved debug game state belongs to another match");
|
||||
return;
|
||||
}
|
||||
|
||||
let mut entity = world.entity_mut(saved.entity);
|
||||
entity.insert(saved.ecb);
|
||||
entity.insert(saved.previous_ecb);
|
||||
entity.insert(saved.velocity);
|
||||
entity.insert(saved.translation);
|
||||
entity.insert(saved.previous_translation);
|
||||
entity.insert(saved.facing);
|
||||
entity.insert(saved.previous_facing);
|
||||
entity.insert(saved.animation);
|
||||
entity.insert(saved.state.clone());
|
||||
entity.insert(saved.input);
|
||||
entity.insert(saved.damage);
|
||||
entity.insert(saved.pending_hit_reaction.clone());
|
||||
entity.insert(saved.hitstop);
|
||||
entity.insert(saved.knockback_velocity);
|
||||
entity.insert(saved.stale_moves.clone());
|
||||
entity.insert(saved.hitboxes.clone());
|
||||
entity.insert(saved.received_attacks.clone());
|
||||
entity.insert(saved.solved_hurtboxes.clone());
|
||||
entity.insert(saved.bone_matrices.clone());
|
||||
if saved.grounded {
|
||||
entity.insert(Grounded);
|
||||
} else {
|
||||
entity.remove::<Grounded>();
|
||||
}
|
||||
}
|
||||
world.insert_resource(checkpoint.stage_collision);
|
||||
for mut match_camera in world.query::<&mut MatchCamera>().iter_mut(world) {
|
||||
match_camera.needs_snap = true;
|
||||
}
|
||||
info!("Restored debug game state");
|
||||
}
|
||||
|
||||
fn capture_fighter(world: &World, entity: Entity) -> Option<FighterCheckpoint> {
|
||||
let fighter = world.entity(entity);
|
||||
Some(FighterCheckpoint {
|
||||
entity,
|
||||
handle: fighter.get::<Player>()?.handle,
|
||||
ecb: *fighter.get::<FighterECB>()?,
|
||||
previous_ecb: *fighter.get::<crate::fighter::ecb::FighterPreviousECB>()?,
|
||||
velocity: *fighter.get::<FighterVelocity>()?,
|
||||
translation: *fighter.get::<FighterTranslation>()?,
|
||||
previous_translation: *fighter.get::<FighterPreviousTranslation>()?,
|
||||
facing: *fighter.get::<FighterFacingDirection>()?,
|
||||
previous_facing: *fighter.get::<FighterPreviousFacingDirection>()?,
|
||||
animation: *fighter.get::<FighterAnimationFrame>()?,
|
||||
state: fighter.get::<FighterState>()?.clone(),
|
||||
input: *fighter.get::<FighterInput>()?,
|
||||
damage: *fighter.get::<FighterDamage>()?,
|
||||
pending_hit_reaction: fighter.get::<FighterPendingHitReaction>()?.clone(),
|
||||
hitstop: *fighter.get::<FighterHitstop>()?,
|
||||
knockback_velocity: *fighter.get::<FighterKnockbackVelocity>()?,
|
||||
stale_moves: fighter.get::<FighterStaleMoveQueue>()?.clone(),
|
||||
hitboxes: fighter.get::<FighterHitboxes>()?.clone(),
|
||||
received_attacks: fighter.get::<FighterReceivedAttacks>()?.clone(),
|
||||
solved_hurtboxes: fighter.get::<FighterSolvedHurtboxes>()?.clone(),
|
||||
bone_matrices: fighter.get::<FighterBoneMatrices>()?.clone(),
|
||||
grounded: fighter.contains::<Grounded>(),
|
||||
})
|
||||
}
|
||||
|
||||
pub(super) fn clear(mut save_state: ResMut<DebugSaveState>) {
|
||||
save_state.checkpoint = None;
|
||||
}
|
||||
@@ -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<AirCollisionWithStageResult> {
|
||||
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 {
|
||||
|
||||
+11
-3
@@ -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,
|
||||
|
||||
@@ -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<FighterState> {
|
||||
fn check_interrupt(&self, state_context: &mut InterruptContext) -> Option<FighterState> {
|
||||
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<FighterState> {
|
||||
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<FighterState> {
|
||||
pub fn check_input(state_context: &InterruptContext) -> Option<FighterState> {
|
||||
state_context
|
||||
.input
|
||||
.has_command(input::FighterCommands::Shield)
|
||||
|
||||
+16
-22
@@ -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<FighterState> {
|
||||
fn check_interrupt(&self, ctx: &mut InterruptContext) -> Option<FighterState> {
|
||||
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<FighterState> {
|
||||
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<FighterFacingDirection> {
|
||||
fn check_smash_input_with_dir(state_context: &InterruptContext) -> Option<FighterFacingDirection> {
|
||||
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<FighterState> {
|
||||
check_smash_input_with_dir(state_context)
|
||||
|
||||
@@ -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<FighterState> {
|
||||
fn check_interrupt(&self, state_context: &mut InterruptContext) -> Option<FighterState> {
|
||||
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<FighterState> {
|
||||
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<FighterState> {
|
||||
pub fn check_input(state_context: &InterruptContext) -> Option<FighterState> {
|
||||
let input_frame = state_context.input.get_last_frame();
|
||||
|
||||
if input_frame.movement.x.abs() < state_context.game_settings.input_common.stick_deadzone {
|
||||
|
||||
@@ -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<FighterState> {
|
||||
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<FighterState> {
|
||||
if let Some(state) = ground_attack::check_interrupt(state_context, &ground_common) {
|
||||
|
||||
@@ -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<FighterState> {
|
||||
fn check_interrupt(&self, state_context: &mut InterruptContext) -> Option<FighterState> {
|
||||
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<FighterState> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn check_interrupt(
|
||||
state_context: &super::FighterStateContext,
|
||||
state_context: &InterruptContext,
|
||||
grounded_common: &GroundedStateCommon,
|
||||
) -> Option<FighterState> {
|
||||
if state_context
|
||||
|
||||
@@ -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<FighterState> {
|
||||
fn check_interrupt(&self, state_context: &mut InterruptContext) -> Option<FighterState> {
|
||||
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<FighterState> {
|
||||
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();
|
||||
|
||||
+27
-53
@@ -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<FighterState> {
|
||||
fn check_interrupt(&self, state_context: &mut InterruptContext) -> Option<FighterState> {
|
||||
// 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,19 +82,18 @@ 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
|
||||
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_manifest.attributes.ground_friction
|
||||
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<FighterState> {
|
||||
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<FighterState> {
|
||||
fn check_interrupt(&self, state_context: &mut InterruptContext) -> Option<FighterState> {
|
||||
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<FighterState> {
|
||||
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<FighterState> {
|
||||
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<FighterState> {
|
||||
pub fn check_input_double_jump(state_context: &InterruptContext) -> Option<FighterState> {
|
||||
state_context
|
||||
.input
|
||||
.has_command(FighterCommands::Jump)
|
||||
|
||||
+11
-11
@@ -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<FighterState> {
|
||||
fn check_interrupt(&self, state_context: &mut InterruptContext) -> Option<FighterState> {
|
||||
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,17 +52,16 @@ 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
|
||||
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_manifest.attributes.ground_friction
|
||||
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<FighterState> {
|
||||
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);
|
||||
|
||||
+197
-96
@@ -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<FighterState> {
|
||||
pub fn check_interrupt(&self, ctx: &mut InterruptContext) -> Option<FighterState> {
|
||||
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<FighterState> {
|
||||
pub fn check_collision_interrupt(&mut self, ctx: &mut CollisionContext) -> Option<FighterState> {
|
||||
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<FighterState>;
|
||||
fn check_interrupt(&self, state_context: &mut InterruptContext) -> Option<FighterState>;
|
||||
|
||||
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<FighterState> {
|
||||
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<BakedFighterAnimations>,
|
||||
pub attack_scripts: &'a Assets<FighterAttackScript>,
|
||||
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 fn get_current_animation_frame(&self) -> u32 {
|
||||
self.animation_frame.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 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<FighterAttackScript>,
|
||||
pub attack_script_assets: &'a FighterAttackScriptAssets,
|
||||
}
|
||||
|
||||
impl UpdateContext<'_> {
|
||||
pub fn get_current_animation_frame(&self) -> u32 {
|
||||
self.animation_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::AirCollisionWithStageResult> {
|
||||
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<BakedFighterAnimations>,
|
||||
) -> 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<BakedFighterAnimations>,
|
||||
attack_scripts: &'a Assets<FighterAttackScript>,
|
||||
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<FighterAttackScript>,
|
||||
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<StatefulFighterQuery>,
|
||||
stage_collision: Res<StageCollision>,
|
||||
game_settings: Res<GameSettings>,
|
||||
baked_animations: Res<Assets<BakedFighterAnimations>>,
|
||||
attack_scripts: Res<Assets<FighterAttackScript>>,
|
||||
manifests: Res<Assets<FighterManifest>>,
|
||||
) {
|
||||
@@ -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<StatefulFighterQuery>,
|
||||
stage_collision: Res<StageCollision>,
|
||||
game_settings: Res<GameSettings>,
|
||||
baked_animations: Res<Assets<BakedFighterAnimations>>,
|
||||
fighter_manifests: Res<Assets<FighterManifest>>,
|
||||
attack_scripts: Res<Assets<FighterAttackScript>>,
|
||||
) {
|
||||
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
|
||||
let manifest = fighter_manifests
|
||||
.get(&fighter.manifest)
|
||||
.expect("Fighter manifest should be valid"),
|
||||
);
|
||||
.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<StatefulFighterQuery>,
|
||||
stage_collision: Res<StageCollision>,
|
||||
game_settings: Res<GameSettings>,
|
||||
baked_animations: Res<Assets<BakedFighterAnimations>>,
|
||||
fighter_manifests: Res<Assets<FighterManifest>>,
|
||||
attack_scripts: Res<Assets<FighterAttackScript>>,
|
||||
) {
|
||||
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,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<FighterState> {
|
||||
fn check_interrupt(&self, state_context: &mut InterruptContext) -> Option<FighterState> {
|
||||
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<FighterState> {
|
||||
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<FighterState> {
|
||||
let input_frame = state_context.input.get_last_frame();
|
||||
|
||||
+10
-11
@@ -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<FighterState> {
|
||||
fn check_interrupt(&self, state_context: &mut InterruptContext) -> Option<FighterState> {
|
||||
// State chain that results in the turn completing
|
||||
if state_context.get_current_animation_frame()
|
||||
<= state_context
|
||||
@@ -42,22 +42,21 @@ 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
|
||||
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_manifest.attributes.ground_friction
|
||||
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<FighterState> {
|
||||
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<FighterState> {
|
||||
let input_frame = state_context.input.get_last_frame();
|
||||
|
||||
+12
-11
@@ -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<FighterState> {
|
||||
fn check_interrupt(&self, state_context: &mut InterruptContext) -> Option<FighterState> {
|
||||
if let Some(state) =
|
||||
ground::grounded_movement_common_interrupts(state_context, &self.grounded_common)
|
||||
{
|
||||
@@ -31,21 +33,20 @@ 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
|
||||
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_manifest.attributes.ground_friction
|
||||
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<FighterState> {
|
||||
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<FighterState> {
|
||||
let input_frame = state_context.input.get_last_frame();
|
||||
|
||||
@@ -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<FighterState> {
|
||||
fn check_interrupt(&self, state_context: &mut InterruptContext) -> Option<FighterState> {
|
||||
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<FighterState> {
|
||||
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<FighterState> {
|
||||
let input_frame = state_context.input.get_last_frame();
|
||||
|
||||
Reference in New Issue
Block a user