Fix match state remaining mutable after and of match and implement initial work on aerials (#77)
Reviewed-on: #77 Co-authored-by: Álex Román Núñez <eirexe@eirteam.moe>
This commit was merged in pull request #77.
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
use crate::fighter::state::jump::{JumpState, JumpType};
|
||||
use crate::fighter::state::land::{LandingState, LandingType};
|
||||
use crate::fighter::state::{CollisionContext, FighterState};
|
||||
use crate::fighter::state::{CollisionContext, FighterState, InterruptContext, air_attack, air_dodge};
|
||||
use crate::fighter::*;
|
||||
use crate::input::FighterCommands;
|
||||
|
||||
@@ -112,6 +113,17 @@ pub fn update_standard_motion(
|
||||
);
|
||||
}
|
||||
|
||||
pub fn air_interrupts_common(ctx: &mut InterruptContext, airborne_state_common: &AirborneStateCommon) -> Option<FighterState> {
|
||||
if ctx.input.has_command(FighterCommands::Jump) {
|
||||
Some(FighterState::Jump(JumpState {
|
||||
jump_type: JumpType::DoubleJump,
|
||||
airborne_state_common: AirborneStateCommon::default(),
|
||||
}))
|
||||
} else {
|
||||
air_dodge::check_input(ctx).or_else(|| air_attack::check_interrupt(ctx, airborne_state_common))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn collision_interrupt(
|
||||
ctx: &mut CollisionContext,
|
||||
landing_type: LandingType,
|
||||
|
||||
@@ -0,0 +1,124 @@
|
||||
use bevy::log::error;
|
||||
|
||||
use crate::fighter::{
|
||||
attack::{AttackKind, FighterAttackScriptAssets, update_active_hitbox_list}, state::{
|
||||
CollisionContext, EnterContext, ExitContext, FighterState, FighterStateImpl, InterruptContext, UpdateContext, air::{self, AirborneStateCommon}, fall::FallState,
|
||||
},
|
||||
};
|
||||
|
||||
#[derive(Clone, Debug, Hash)]
|
||||
pub struct AirAttackState {
|
||||
pub attack_kind: AttackKind,
|
||||
pub airborne_state_common: AirborneStateCommon
|
||||
}
|
||||
|
||||
impl FighterStateImpl for AirAttackState {
|
||||
const NAME: &'static str = "AirAttack";
|
||||
|
||||
fn check_interrupt(&self, state_context: &mut InterruptContext) -> Option<FighterState> {
|
||||
if state_context.is_current_animation_finished() {
|
||||
Some(FighterState::Fall(FallState::new(self.airborne_state_common)))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn update(&mut self, state_context: &mut UpdateContext) {
|
||||
let animation_frame = state_context.get_current_animation_frame();
|
||||
let script = state_context
|
||||
.attack_scripts
|
||||
.get(&state_context.attack_script_assets.scripts[&self.attack_kind]);
|
||||
if let Some(script) = script {
|
||||
update_active_hitbox_list(
|
||||
script,
|
||||
&mut state_context
|
||||
.hitboxes
|
||||
.0
|
||||
.as_mut()
|
||||
.expect("ground attack must have active hitboxes")
|
||||
.active_hitboxes,
|
||||
animation_frame,
|
||||
);
|
||||
}
|
||||
|
||||
air::update_standard_motion(state_context, &mut self.airborne_state_common);
|
||||
}
|
||||
|
||||
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.hitboxes.0 = Some(crate::fighter::FighterActiveAttack {
|
||||
kind: self.attack_kind,
|
||||
script,
|
||||
active_hitboxes: Vec::new(),
|
||||
solved_hitboxes: Vec::new(),
|
||||
hit_fighters: Vec::new(),
|
||||
stalled: false,
|
||||
});
|
||||
}
|
||||
|
||||
fn on_exit(&mut self, state_context: &mut ExitContext) {
|
||||
state_context.hitboxes.0 = None;
|
||||
}
|
||||
|
||||
fn check_collision_interrupt(
|
||||
&mut self,
|
||||
state_context: &mut CollisionContext,
|
||||
) -> Option<FighterState> {
|
||||
air::collision_interrupt(
|
||||
state_context,
|
||||
crate::fighter::state::land::LandingType::Normal,
|
||||
false,
|
||||
)
|
||||
}
|
||||
|
||||
fn is_visually_grounded<'a>(&'a self) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(thiserror::Error, Debug)]
|
||||
pub enum AirAttackStateCreateError {
|
||||
#[error("Attack script: {attack:?} not found")]
|
||||
AttackScriptNotFound{attack: AttackKind},
|
||||
}
|
||||
|
||||
impl AirAttackState {
|
||||
pub fn create(attack_kind: AttackKind, attack_script_assets: &FighterAttackScriptAssets, airborne_state_common: &AirborneStateCommon) -> Result<Self, AirAttackStateCreateError> {
|
||||
if attack_script_assets.scripts.contains_key(&attack_kind) {
|
||||
Ok(AirAttackState {
|
||||
airborne_state_common: airborne_state_common.clone(),
|
||||
attack_kind
|
||||
})
|
||||
} else {
|
||||
Err(AirAttackStateCreateError::AttackScriptNotFound { attack: attack_kind })
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
pub fn check_interrupt(state_context: &InterruptContext, airborne_state_common: &AirborneStateCommon) -> Option<FighterState> {
|
||||
if state_context
|
||||
.input
|
||||
.has_command(crate::input::FighterCommands::Attack)
|
||||
{
|
||||
let attack_kind = state_context
|
||||
.input
|
||||
.get_attack_command_type()
|
||||
.to_attack_kind_airborne(state_context.facing_direction);
|
||||
let state = AirAttackState::create(attack_kind, state_context.attack_script_assets, airborne_state_common);
|
||||
|
||||
match state {
|
||||
Ok(state) => {
|
||||
Some(FighterState::AirAttack(state))
|
||||
},
|
||||
Err(create_error) => {
|
||||
error!("{}", create_error);
|
||||
None
|
||||
},
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
use super::{CollisionContext, EnterContext, FighterStateImpl, InterruptContext, UpdateContext};
|
||||
use crate::fighter::animation::AnimKind;
|
||||
use crate::fighter::state::air::AirborneStateCommon;
|
||||
use crate::fighter::state::{FighterState, air, jump};
|
||||
use crate::fighter::state::{FighterState, air, air_attack, jump};
|
||||
|
||||
#[derive(Debug, Clone, Copy, Hash, Default)]
|
||||
pub struct FallState {
|
||||
@@ -20,7 +20,7 @@ impl FighterStateImpl for FallState {
|
||||
const NAME: &'static str = "Fall";
|
||||
|
||||
fn check_interrupt(&self, state_context: &mut InterruptContext) -> Option<FighterState> {
|
||||
jump::check_input_double_jump(state_context)
|
||||
jump::check_input_double_jump(state_context).or_else(|| air_attack::check_interrupt(state_context, &self.airborne_state_common))
|
||||
}
|
||||
|
||||
fn on_enter(&mut self, state_context: &mut EnterContext) {
|
||||
|
||||
@@ -7,7 +7,7 @@ use crate::{
|
||||
CollisionContext, EnterContext, FighterState, FighterStateImpl, InterruptContext,
|
||||
UpdateContext,
|
||||
air::{self, AirborneStateCommon},
|
||||
air_dodge::{self, AirDodgeState},
|
||||
air_dodge::AirDodgeState,
|
||||
ground,
|
||||
},
|
||||
},
|
||||
@@ -23,8 +23,8 @@ pub enum JumpType {
|
||||
|
||||
#[derive(Debug, Clone, Hash)]
|
||||
pub struct JumpState {
|
||||
jump_type: JumpType,
|
||||
airborne_state_common: AirborneStateCommon,
|
||||
pub jump_type: JumpType,
|
||||
pub airborne_state_common: AirborneStateCommon,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Hash)]
|
||||
@@ -108,14 +108,7 @@ impl FighterStateImpl for JumpSquatState {
|
||||
impl FighterStateImpl for JumpState {
|
||||
const NAME: &'static str = "Jump";
|
||||
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,
|
||||
airborne_state_common: AirborneStateCommon::default(),
|
||||
}))
|
||||
} else {
|
||||
air_dodge::check_input(state_context)
|
||||
}
|
||||
air::air_interrupts_common(state_context, &self.airborne_state_common)
|
||||
}
|
||||
|
||||
fn update(&mut self, state_context: &mut UpdateContext) {
|
||||
|
||||
@@ -47,6 +47,7 @@ pub mod run;
|
||||
pub mod turn;
|
||||
pub mod wait;
|
||||
pub mod walk;
|
||||
pub mod air_attack;
|
||||
|
||||
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
|
||||
pub enum SurfacePolicy {
|
||||
@@ -135,6 +136,7 @@ pub struct InterruptContext<'a> {
|
||||
pub surface: &'a FighterSurfaceState,
|
||||
pub animation: AnimationStatus,
|
||||
pub stage_collision: &'a StageCollision,
|
||||
pub attack_script_assets: &'a FighterAttackScriptAssets,
|
||||
}
|
||||
|
||||
impl InterruptContext<'_> {
|
||||
@@ -246,6 +248,7 @@ fighter_states! {
|
||||
GroundAttack => ground_attack::GroundAttackState,
|
||||
Hitstun => hitstun::HitstunState,
|
||||
Angel => angel::AngelState,
|
||||
AirAttack => air_attack::AirAttackState,
|
||||
}
|
||||
|
||||
#[derive(QueryData)]
|
||||
@@ -292,6 +295,7 @@ impl<'w, 's> FighterFrameQueryItem<'w, 's> {
|
||||
baked_animations: &'a Assets<BakedFighterAnimations>,
|
||||
attributes: &'a FighterAttributes,
|
||||
stage_collision: &'a StageCollision,
|
||||
attack_script_assets: &'a FighterAttackScriptAssets,
|
||||
) -> InterruptContext<'a> {
|
||||
let animation = self.animation_status(animations, baked_animations);
|
||||
InterruptContext {
|
||||
@@ -302,6 +306,7 @@ impl<'w, 's> FighterFrameQueryItem<'w, 's> {
|
||||
animation,
|
||||
surface: &self.surface,
|
||||
stage_collision,
|
||||
attack_script_assets: attack_script_assets
|
||||
}
|
||||
}
|
||||
|
||||
@@ -535,6 +540,7 @@ pub fn state_interrupt_system(
|
||||
&baked_animations,
|
||||
&manifest.attributes,
|
||||
&stage_collision,
|
||||
attack_script_assets
|
||||
))
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user