Port to fixed point math
This commit is contained in:
@@ -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
@@ -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,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(),
|
||||
);
|
||||
|
||||
@@ -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
@@ -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
@@ -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>()
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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,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
@@ -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
@@ -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
@@ -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,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};
|
||||
|
||||
@@ -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,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};
|
||||
|
||||
Reference in New Issue
Block a user