Port to fixed point math

This commit is contained in:
2026-08-24 21:54:23 +02:00
parent 91c5c4e05f
commit 73855ea354
27 changed files with 703 additions and 229 deletions
+1 -1
View File
@@ -13,7 +13,7 @@ pub struct FighterAnimationPlayerLink(Entity);
pub fn apply_fighter_translation_to_visuals(query: Query<(&FighterTranslation, &FighterECB, &mut Transform)>) {
for (translation, ecb, mut transform) in query {
let translation = translation.0 + ecb.get_bottom_point();
transform.translation = Vec3::new(translation.x, translation.y, 0.0);
transform.translation = Vec3::new(translation.x.to_num(), translation.y.to_num(), 0.0);
}
}
+15 -14
View File
@@ -1,31 +1,32 @@
use bevy::prelude::*;
use crate::input::FighterInputFrame;
use crate::{input::FighterInputFrame, math::int::FGi32};
/// Per-fighter tuning values. These are character data, not global rules —
/// anything that applies to every fighter belongs in
/// [`crate::game_settings::FighterSettingsCommon`] instead.
#[derive(Component, Clone, Copy)]
pub struct FighterAttributes {
pub base_walk_accel: f32,
pub stick_walk_accel: f32,
pub max_walk_vel: f32,
pub base_walk_accel: FGi32,
pub stick_walk_accel: FGi32,
pub max_walk_vel: FGi32,
pub dash_duration: u32,
pub dash_initial_velocity: f32,
pub base_dash_accel: f32,
pub stick_dash_accel: f32,
pub max_dash_vel: f32,
pub dash_initial_velocity: FGi32,
pub base_dash_accel: FGi32,
pub stick_dash_accel: FGi32,
pub max_dash_vel: FGi32,
pub jump_vertical_velocity: f32,
pub jumpsquat_duration: u32,
pub jump_vertical_velocity: FGi32,
pub ground_friction: f32,
pub terminal_velocity: f32,
pub gravity: f32,
pub ground_friction: FGi32,
pub terminal_velocity: FGi32,
pub gravity: FGi32,
}
impl FighterAttributes {
pub fn get_accel_and_target_dashrun(&self, input: &FighterInputFrame) -> (f32, f32) {
pub fn get_accel_and_target_dashrun(&self, input: &FighterInputFrame) -> (FGi32, FGi32) {
let accel = input.movement.x * self.stick_dash_accel;
let accel = accel + input.movement.x.signum() * self.base_dash_accel;
let target_vel = input.movement.x * self.max_dash_vel;
@@ -33,7 +34,7 @@ impl FighterAttributes {
(accel, target_vel)
}
pub fn get_accel_and_target_walk(&self, input: &FighterInputFrame) -> (f32, f32) {
pub fn get_accel_and_target_walk(&self, input: &FighterInputFrame) -> (FGi32, FGi32) {
let accel = input.movement.x * self.stick_walk_accel;
let accel = accel + input.movement.x.signum() * self.base_walk_accel;
let target_vel = input.movement.x * self.max_walk_vel;
+5 -3
View File
@@ -5,6 +5,8 @@ use bevy::{color::palettes::css::HOT_PINK, prelude::*};
use crate::fighter::ecb::FighterPreviousECB;
use crate::fighter::state::FighterStateContext;
use crate::fighter::{FighterECB, FighterPreviousTranslation, FighterTranslation, FighterVelocity};
use crate::math::segment::FGSegment2d;
use crate::math::vec::FGVec2;
use crate::stage::StagePoly;
use crate::stage::line::{StageCollision, StageLineID};
/*
@@ -36,14 +38,14 @@ pub fn collide_fighter_with_scene(
pub struct AirCollisionWithStageResult {
pub line_id: StageLineID,
pub hit_position: Vec2,
pub hit_normal: Vec2,
pub hit_position: FGVec2,
pub hit_normal: FGVec2,
}
pub fn air_collide_with_stage(
state_context: &FighterStateContext,
) -> Option<AirCollisionWithStageResult> {
let ray_segment = Segment2d::new(
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(),
);
+8 -4
View File
@@ -1,16 +1,20 @@
//! Fighter debug views: gizmos and the egui inspector window.
use bevy::color::palettes::css::ORANGE;
use bevy::{color::palettes::css::YELLOW, prelude::*};
use bevy_egui::{EguiContexts, egui};
use crate::fighter::ecb::FighterPreviousECB;
use crate::fighter::state::StateNameDebug;
use crate::fighter::{FighterECB, FighterTranslation, FighterVelocity};
use crate::fighter::{FighterECB, FighterPreviousTranslation, FighterTranslation, FighterVelocity};
use crate::input::FighterInput;
pub fn debug_draw_ecb(ecbs: Query<(&FighterECB, &FighterTranslation)>, mut gizmos: Gizmos) {
for (ecb, trf) in ecbs {
let transformed = ecb.to_3d_lineloop(Transform::from_xyz(trf.x, trf.y, 0.0));
pub fn debug_draw_ecb(ecbs: Query<(&FighterECB, &FighterTranslation, &FighterPreviousECB, &FighterPreviousTranslation)>, mut gizmos: Gizmos) {
for (ecb, trf, ecb_prev, trf_prev) in ecbs {
let transformed = ecb.to_3d_lineloop(Transform::from_xyz(trf.x.to_num(), trf.y.to_num(), 0.0));
gizmos.lineloop(transformed, YELLOW);
let prev_transformed = ecb_prev.to_3d_lineloop(Transform::from_xyz(trf_prev.x.to_num(), trf_prev.y.to_num(), -0.1));
gizmos.lineloop(prev_transformed, ORANGE);
}
}
+53 -16
View File
@@ -1,4 +1,7 @@
use bevy::prelude::*;
use fixed::traits::Fixed;
use crate::math::{int::FGi32, vec::FGVec2};
/// Environment collision box: the diamond used to resolve a fighter against
/// the stage. Purely geometry — the collision response lives in
@@ -6,40 +9,74 @@ use bevy::prelude::*;
#[derive(Component, Debug, Clone, Copy)]
#[require(FighterPreviousECB)]
pub struct FighterECB {
pub vertical_half: f32,
pub horizontal_half: f32,
pub vertical_half: FGi32,
pub horizontal_half: FGi32,
}
#[derive(Component, Debug, Clone, Copy, Default)]
pub struct FighterPreviousECB {
pub vertical_half: f32,
pub horizontal_half: f32,
pub vertical_half: FGi32,
pub horizontal_half: FGi32,
}
impl From<FighterECB> for FighterPreviousECB {
fn from(ecb: FighterECB) -> Self {
Self {
vertical_half: ecb.vertical_half,
horizontal_half: ecb.horizontal_half,
}
}
}
pub fn snapshot_fighter_ecb(
fighters: Query<(&FighterECB, &mut FighterPreviousECB)>,
) {
for (ecb, mut previous_ecb) in fighters {
*previous_ecb = (*ecb).into();
}
}
impl FighterECB {
pub fn to_3d_lineloop(&self, trf: Transform) -> [Vec3; 4] {
let rel_up = trf.transform_point(Vec3::new(0.0, self.vertical_half, 0.0));
let rel_down = trf.transform_point(Vec3::new(0.0, -self.vertical_half, 0.0));
let rel_left = trf.transform_point(Vec3::new(-self.horizontal_half, 0.0, 0.0));
let rel_right = trf.transform_point(Vec3::new(self.horizontal_half, 0.0, 0.0));
let rel_up = trf.transform_point(Vec3::new(0.0, self.vertical_half.to_num(), 0.0));
let rel_down = trf.transform_point(Vec3::new(0.0, (-self.vertical_half).to_num(), 0.0));
let rel_left = trf.transform_point(Vec3::new((-self.horizontal_half).to_num(), 0.0, 0.0));
let rel_right = trf.transform_point(Vec3::new(self.horizontal_half.to_num(), 0.0, 0.0));
[rel_up, rel_right, rel_down, rel_left]
}
pub fn get_bottom_point(&self) -> Vec2 {
Vec2::new(0.0, -self.vertical_half)
pub fn get_bottom_point(&self) -> FGVec2 {
FGVec2::new(FGi32::ZERO, -self.vertical_half)
}
}
impl FighterPreviousECB {
pub fn to_3d_lineloop(&self, trf: Transform) -> [Vec3; 4] {
let rel_up = trf.transform_point(Vec3::new(0.0, self.vertical_half, 0.0));
let rel_down = trf.transform_point(Vec3::new(0.0, -self.vertical_half, 0.0));
let rel_left = trf.transform_point(Vec3::new(-self.horizontal_half, 0.0, 0.0));
let rel_right = trf.transform_point(Vec3::new(self.horizontal_half, 0.0, 0.0));
let rel_up = trf.transform_point(Vec3::new(0.0, self.vertical_half.to_num(), 0.0));
let rel_down = trf.transform_point(Vec3::new(0.0, (-self.vertical_half).to_num(), 0.0));
let rel_left = trf.transform_point(Vec3::new((-self.horizontal_half).to_num(), 0.0, 0.0));
let rel_right = trf.transform_point(Vec3::new(self.horizontal_half.to_num(), 0.0, 0.0));
[rel_up, rel_right, rel_down, rel_left]
}
pub fn get_bottom_point(&self) -> Vec2 {
Vec2::new(0.0, -self.vertical_half)
pub fn get_bottom_point(&self) -> FGVec2 {
FGVec2::new(FGi32::ZERO, -self.vertical_half)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn previous_ecb_copies_current_dimensions() {
let current = FighterECB {
vertical_half: FGi32::lit("0.5"),
horizontal_half: FGi32::lit("0.25"),
};
let previous = FighterPreviousECB::from(current);
assert_eq!(previous.vertical_half, current.vertical_half);
assert_eq!(previous.horizontal_half, current.horizontal_half);
}
}
+7 -1
View File
@@ -45,7 +45,12 @@ impl Plugin for FighterPlugin {
// Every state gets a chance to interrupt itself, in priority order.
.add_systems(
GgrsSchedule,
(animation::setup_fighter_animation_player, state::state_interrupt_system,).in_set(GameplaySet::Interrupt),
(
ecb::snapshot_fighter_ecb.before(state_interrupt_system),
animation::setup_fighter_animation_player,
state::state_interrupt_system,
)
.in_set(GameplaySet::Interrupt),
)
.add_systems(
GgrsSchedule,
@@ -74,6 +79,7 @@ impl Plugin for FighterPlugin {
// components; a component simulated here but missing from this list
// is a desync waiting to happen.
.rollback_component_with_copy::<FighterECB>()
.rollback_component_with_copy::<ecb::FighterPreviousECB>()
.rollback_component_with_copy::<FighterVelocity>()
.rollback_component_with_copy::<FighterTranslation>()
.rollback_component_with_copy::<FighterPreviousTranslation>()
+5 -5
View File
@@ -3,20 +3,20 @@
use bevy::prelude::*;
use crate::fighter::FighterAttributes;
use crate::{fighter::FighterAttributes, math::vec::FGVec2};
#[derive(Component, Clone, Copy)]
pub struct Grounded;
#[derive(Component, Deref, DerefMut, Default, Debug, Clone, Copy)]
pub struct FighterVelocity(pub Vec2);
pub struct FighterVelocity(pub FGVec2);
#[derive(Component, Deref, DerefMut, Default, Clone, Copy)]
pub struct FighterPreviousTranslation(pub Vec2);
pub struct FighterPreviousTranslation(pub FGVec2);
#[derive(Component, Deref, DerefMut, Default, Clone, Copy)]
#[require(FighterPreviousTranslation)]
pub struct FighterTranslation(pub Vec2);
pub struct FighterTranslation(pub FGVec2);
pub fn apply_air_motion(
fighters: Query<(
@@ -37,7 +37,7 @@ pub fn copy_fighter_transform_to_visuals(
fighters: Query<(&FighterTranslation, &mut Transform)>,
) {
for (translation, mut transform) in fighters {
transform.translation = Vec3::new(translation.x, translation.y, 0.0);
transform.translation = Vec3::new(translation.x.to_num(), translation.y.to_num(), 0.0);
}
}
+7 -6
View File
@@ -2,7 +2,7 @@ use std::hash::{Hash, Hasher};
use bevy::prelude::*;
use super::{FighterStateImpl, FighterStateContext, FighterStateTransition, ground, run, wait, walk};
use super::{FighterStateImpl, FighterStateContext, ground, run, wait, walk};
use crate::fighter::state::ground::GroundedStateCommon;
use crate::fighter::state::wait::WaitState;
use crate::fighter::state::{FighterState};
@@ -12,11 +12,12 @@ use crate::input::{
FighterCommands::{SmashMoveLeft, SmashMoveRight},
FighterInput,
};
use crate::math::int::FGi32;
#[derive(Debug, Clone)]
pub struct DashState {
frames_in_dash: u32,
direction: f32,
direction: FGi32,
ground_common: GroundedStateCommon
}
@@ -28,7 +29,7 @@ impl std::hash::Hash for DashState {
}
impl DashState {
pub fn new(direction: f32, ground_common: GroundedStateCommon) -> Self {
pub fn new(direction: FGi32, ground_common: GroundedStateCommon) -> Self {
Self {
frames_in_dash: 0,
direction,
@@ -98,11 +99,11 @@ impl FighterStateImpl for DashState {
}
}
fn check_smash_input_with_dir(state_context: &FighterStateContext) -> Option<f32> {
fn check_smash_input_with_dir(state_context: &FighterStateContext) -> Option<FGi32> {
if state_context.input.has_command(SmashMoveLeft) {
return Some(-1.0);
return Some(FGi32::NEG_ONE);
} else if state_context.input.has_command(SmashMoveRight) {
return Some(1.0);
return Some(FGi32::ONE);
} else {
None
}
+1 -1
View File
@@ -1,6 +1,6 @@
use bevy::prelude::*;
use super::{FighterStateImpl, FighterStateContext, FighterStateTransition, ground, walk};
use super::{FighterStateImpl, FighterStateContext, ground, walk};
use crate::fighter::state::{FighterState, air};
use crate::fighter::state::ground::GroundedStateCommon;
use crate::fighter::state::wait::WaitState;
+21 -23
View File
@@ -7,17 +7,20 @@ use crate::fighter::{
FighterAttributes, FighterECB, FighterPreviousTranslation, FighterTranslation, FighterVelocity,
};
use crate::game_settings::GameSettings;
use crate::math::int::FGi32;
use crate::math::vec::FGVec2;
use crate::stage::StagePoly;
use crate::stage::line::{StageCollision, StageLineID, StagePolyLineSegment, StagePolyLineSegmentType};
use bevy::prelude::*;
use fixed::traits::Fixed;
#[derive(Reflect, Hash, Clone, Debug)]
pub struct GroundedStateCommon {
pub current_line_id: StageLineID,
}
pub fn apply_grounded_friction(friction: f32, ground_vel: f32) -> f32 {
pub fn apply_grounded_friction(friction: FGi32, ground_vel: FGi32) -> FGi32 {
if friction.abs() > ground_vel.abs() {
-ground_vel
} else {
@@ -28,21 +31,21 @@ pub fn apply_grounded_friction(friction: f32, ground_vel: f32) -> f32 {
pub fn move_accelerate() {}
pub fn compute_ground_accel(
accel: f32,
target_vel: f32,
gr_vel: f32,
accel: FGi32,
target_vel: FGi32,
gr_vel: FGi32,
attribs: &FighterAttributes,
game_settings: &GameSettings,
) -> f32 {
) -> FGi32 {
if target_vel == 0.0 {
apply_grounded_friction(attribs.ground_friction, gr_vel)
} else {
let mut accel = accel;
let ground_max_horizontal_velocity =
game_settings.figher_common.ground_max_horizontal_velocity;
if !(gr_vel * accel < 0.0) {
if !(gr_vel * accel < FGi32::ZERO) {
// accelerating, not reversing
if accel > 0.0 {
if accel > FGi32::ZERO {
if gr_vel + accel > target_vel {
accel = -attribs.ground_friction;
if gr_vel + accel < target_vel {
@@ -78,7 +81,7 @@ pub fn apply_grounded_motion(
) {
// Vertical velocity should be 0 on the ground
prev_translation.0 = translation.0;
translation.0 += Vec2::new(velocity.0.x ,0.0);
translation.0 += FGVec2::new(velocity.0.x ,FGi32::ZERO);
}
pub fn collide_with_stage_grounded(
@@ -96,34 +99,29 @@ pub fn collide_with_stage_grounded(
if let Some(stage_poly) = stage_poly {
let ecb_bottom_pos = translation.0 + ecb.get_bottom_point();
let left_segment_idx = ground_common
.current_line_id
.segment
.checked_sub(1)
.unwrap_or(0);
let right_segment_idx =
(ground_common.current_line_id.segment + 1) % stage_poly.segments.len();
let current_segment_idx = ground_common.current_line_id.segment;
// First, we check the current segment, if that fails, we check the surrounding ones
let grounded_ecb_bottom_pos = [
ground_common.current_line_id.segment.clone(),
left_segment_idx,
right_segment_idx,
Some(current_segment_idx),
stage_poly.get_prev_segment_index(current_segment_idx),
stage_poly.get_next_segment_index(current_segment_idx),
]
.iter()
.into_iter()
.flatten()
.find_map(|segment_idx| {
let segment = stage_poly.get_segment(*segment_idx)?;
let segment = stage_poly.get_segment(segment_idx)?;
if segment.segment_type != StagePolyLineSegmentType::Floor {
return None;
}
let line_dir = segment.segment.direction();
let projected_point = segment.segment.point1() + (ecb_bottom_pos - segment.segment.point1()).project_onto(line_dir.as_vec2());
let projected_point = segment.segment.point1() + (ecb_bottom_pos - segment.segment.point1()).project_onto(line_dir);
let closest_point = segment.segment.closest_point(ecb_bottom_pos);
let distance = closest_point.distance(projected_point);
if distance < 0.01 {
return Some((projected_point, *segment_idx, segment.normal));
return Some((projected_point, segment_idx, segment.normal));
}
None
+85 -20
View File
@@ -1,41 +1,106 @@
use bevy::prelude::*;
use crate::fighter::state::{FighterState, FighterStateImpl};
use crate::{
fighter::state::{
FighterState, FighterStateContext, FighterStateImpl,
fall::FallState,
ground::{self, GroundedMotionResult, GroundedStateCommon},
},
input::FighterCommands,
};
pub struct JumpState {
pub counter: u32
pub enum JumpType {
ShortHop,
LongJump,
DoubleJump,
}
#[derive(Debug, Clone, Hash)]
pub struct JumpState {}
#[derive(Debug, Clone, Hash)]
pub struct JumpSquatState {
pub counter: u32
pub grounded_common: GroundedStateCommon,
pub duration_counter: u32,
}
impl JumpSquatState {
pub fn create(grounded_common: GroundedStateCommon) -> Self {
Self {
grounded_common,
duration_counter: 0,
}
}
}
impl FighterStateImpl for JumpSquatState {
const NAME: &'static str = "JumpSquat";
fn check_interrupt(
&self,
state_context: &super::FighterStateContext,
) -> Option<FighterState> {
None
fn check_interrupt(&self, state_context: &FighterStateContext) -> Option<FighterState> {
if self.duration_counter >= state_context.fighter_attribs.jumpsquat_duration {
Some(FighterState::Jump(JumpState {}))
} else {
None
}
}
fn update(&mut self, _state_context: &mut super::FighterStateContext) {
todo!()
fn update(&mut self, state_context: &mut FighterStateContext) {
self.duration_counter += 1;
let friction =
if state_context.velocity.x.abs() > state_context.fighter_attribs.max_walk_vel {
state_context.fighter_attribs.ground_friction
* state_context
.game_settings
.figher_common
.ground_friction_over_walk_speed_multiplier
} else {
state_context.fighter_attribs.ground_friction
};
let ground_velocity = state_context.velocity.x;
state_context.velocity.x += ground::apply_grounded_friction(friction, ground_velocity);
ground::apply_grounded_motion(
state_context.velocity,
state_context.translation,
state_context.prev_translation,
);
}
fn check_collision_interrupt(
&mut self,
state_context: &mut FighterStateContext,
) -> Option<FighterState> {
if let GroundedMotionResult::InAir =
ground::collide_with_stage_grounded(state_context, &mut self.grounded_common, false)
{
Some(FighterState::Fall(FallState))
} else {
None
}
}
}
impl FighterStateImpl for JumpState {
const NAME: &'static str = "Jump";
fn check_interrupt(
&self,
state_context: &super::FighterStateContext,
) -> Option<FighterState> {
fn check_interrupt(&self, state_context: &FighterStateContext) -> Option<FighterState> {
None
}
fn update(&mut self, _state_context: &mut super::FighterStateContext) {
todo!()
}
}
fn update(&mut self, _state_context: &mut FighterStateContext) {}
}
pub fn check_input(
state_context: &FighterStateContext,
ground_common: &GroundedStateCommon,
) -> Option<FighterState> {
state_context
.input
.has_command(FighterCommands::Jump)
.then_some(FighterState::JumpSquat(JumpSquatState::create(
ground_common.clone(),
)));
None
}
+13 -13
View File
@@ -11,6 +11,7 @@ use crate::fighter::ecb::FighterPreviousECB;
use crate::fighter::{FighterAttributes, FighterECB, FighterPreviousTranslation, FighterTranslation, FighterVelocity};
use crate::game_settings::GameSettings;
use crate::input::FighterInput;
use crate::math::int::FGi32;
use crate::schedule::GameplaySet;
use crate::stage::StagePoly;
use crate::stage::line::StageCollision;
@@ -24,14 +25,6 @@ pub mod fall;
pub mod air;
pub mod jump;
pub enum FighterStateTransition {
Wait,
Walk,
Dash(f32),
Run,
Fall,
}
macro_rules! fighter_states {
($($variant:ident => $ty:ty),* $(,)?) => {
#[derive(Component, Clone, Debug, Hash)]
@@ -80,7 +73,7 @@ pub trait FighterStateImpl: Sized {
}
}
pub struct FighterStateContext<'a> {
pub struct FighterStateContext<'a, 'w, 's> {
pub translation: &'a mut FighterTranslation,
pub prev_translation: &'a mut FighterPreviousTranslation,
pub input: &'a mut FighterInput,
@@ -91,6 +84,7 @@ pub struct FighterStateContext<'a> {
pub game_settings: &'a GameSettings,
pub entity: Entity,
pub stage_collision: &'a StageCollision,
pub gizmos: Option<&'a mut Gizmos<'w, 's>>,
}
fighter_states! {
@@ -98,7 +92,9 @@ fighter_states! {
Walk => walk::WalkState,
Dash => dash::DashState,
Run => run::RunState,
Fall => fall::FallState
Fall => fall::FallState,
JumpSquat => jump::JumpSquatState,
Jump => jump::JumpState
}
#[derive(Component)]
@@ -128,6 +124,7 @@ pub fn state_update_system(
game_settings: &game_settings,
entity: ent,
stage_collision: &stage_collision,
gizmos: Some(&mut gizmos),
};
state.update(&mut update_ctx);
}
@@ -150,7 +147,8 @@ pub fn state_interrupt_system (
fighter_attribs: &attribs,
game_settings: &game_settings,
entity: ent,
stage_collision: &stage_collision
stage_collision: &stage_collision,
gizmos: None,
};
if let Some(new_state) = state.check_interrupt(&state_context) {
let mut new_state = new_state;
@@ -171,6 +169,7 @@ pub fn state_collision_interrupt_system(
stage_collision: Res<StageCollision>,
game_settings: Res<GameSettings>,
mut commands: Commands,
mut gizmos: Gizmos,
) {
for (ent, mut state, mut translation, mut prev_translation, mut input, mut velocity, mut ecb, mut prev_ecb, attribs) in query {
let mut state_context = FighterStateContext {
@@ -183,7 +182,8 @@ pub fn state_collision_interrupt_system(
fighter_attribs: &attribs,
game_settings: &game_settings,
entity: ent,
stage_collision: &stage_collision
stage_collision: &stage_collision,
gizmos: Some(&mut gizmos),
};
if let Some(new_state) = state.check_collision_interrupt(&mut state_context) {
let mut new_state = new_state;
@@ -197,4 +197,4 @@ pub fn state_collision_interrupt_system(
info!("State {} -> {}", old_state_name, new_state_name);
}
}
}
}
+1 -1
View File
@@ -1,6 +1,6 @@
use bevy::prelude::*;
use super::{FighterStateImpl, FighterStateContext, FighterStateTransition, ground, wait, walk};
use super::{FighterStateImpl, FighterStateContext, ground, wait, walk};
use crate::fighter::state::FighterState;
use crate::fighter::state::fall::FallState;
use crate::fighter::state::ground::{GroundedMotionResult, GroundedStateCommon};
+5 -2
View File
@@ -1,6 +1,6 @@
use bevy::prelude::*;
use super::{FighterStateImpl, FighterStateContext, FighterStateTransition, ground, walk};
use super::{FighterStateImpl, FighterStateContext, ground, walk};
use crate::fighter::state::FighterState;
use crate::fighter::state::fall::FallState;
use crate::fighter::state::ground::{GroundedMotionResult, GroundedStateCommon};
@@ -33,7 +33,10 @@ impl FighterStateImpl for WaitState {
} else {
state_context.fighter_attribs.ground_friction
};
state_context.velocity.x += ground::apply_grounded_friction(friction, state_context.velocity.x);
let ground_velocity = state_context.velocity.x;
state_context.velocity.x += ground::apply_grounded_friction(friction, ground_velocity);
ground::apply_grounded_motion(
state_context.velocity,
+1 -1
View File
@@ -1,6 +1,6 @@
use bevy::prelude::*;
use super::{FighterStateImpl, FighterStateContext, FighterStateTransition, dash, ground, wait};
use super::{FighterStateImpl, FighterStateContext, dash, ground, wait};
use crate::fighter::state::fall::FallState;
use crate::fighter::state::ground::{GroundedMotionResult, GroundedStateCommon};
use crate::fighter::state::{self, FighterState};