Fix various minor issues

This commit is contained in:
2026-09-03 18:50:38 +02:00
parent 472d21fd39
commit 7c7f9a2762
15 changed files with 54 additions and 32 deletions
+2 -1
View File
@@ -1,4 +1,5 @@
use bevy::prelude::*; use bevy::prelude::*;
use strum_macros::EnumIter;
use crate::fighter::{FighterFacingDirection, FighterVisual}; use crate::fighter::{FighterFacingDirection, FighterVisual};
@@ -63,7 +64,7 @@ pub fn apply_animation(
} }
#[derive( #[derive(
Debug, Clone, Copy, PartialEq, Eq, Hash, serde::Deserialize, serde::Serialize, Reflect, Debug, Clone, Copy, PartialEq, Eq, Hash, serde::Deserialize, serde::Serialize, Reflect, EnumIter
)] )]
pub enum AnimKind { pub enum AnimKind {
Wait, Wait,
+2 -2
View File
@@ -175,7 +175,7 @@ pub fn update_active_hitbox_list(script: &FighterAttackScript, list: &mut Vec<us
.collect() .collect()
} }
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq, Hash)]
pub struct FighterSolvedHurtbox { pub struct FighterSolvedHurtbox {
pub hurtbox_idx: usize, pub hurtbox_idx: usize,
pub capsule: FixedAffineCapsule, pub capsule: FixedAffineCapsule,
@@ -185,7 +185,7 @@ pub struct FighterSolvedHurtbox {
pub struct FighterAttackScriptAssets { pub struct FighterAttackScriptAssets {
pub scripts: HashMap<AttackKind, Handle<FighterAttackScript>>, pub scripts: HashMap<AttackKind, Handle<FighterAttackScript>>,
} }
#[derive(Component, Clone, Debug, Default)] #[derive(Component, Clone, Debug, Default, Hash)]
pub struct FighterSolvedHurtboxes(pub Vec<FighterSolvedHurtbox>); pub struct FighterSolvedHurtboxes(pub Vec<FighterSolvedHurtbox>);
pub fn solve_hurtboxes( pub fn solve_hurtboxes(
+1 -1
View File
@@ -38,7 +38,7 @@ pub const BAKED_ANIMATION_FPS: u32 = 60;
/// Parent transforms are composed after /// Parent transforms are composed after
/// quantization, which makes every runtime sample platform-independent. /// quantization, which makes every runtime sample platform-independent.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)] #[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize, Hash)]
pub struct FixedMat4 { pub struct FixedMat4 {
pub cols: [[FGi32; 4]; 4], pub cols: [[FGi32; 4]; 4],
} }
+12 -5
View File
@@ -30,7 +30,7 @@ pub fn collide_fighter_with_scene(
} }
} }
*/ */
#[derive(Clone)]
pub struct AirCollisionWithStageResult { pub struct AirCollisionWithStageResult {
pub line_id: StageLineID, pub line_id: StageLineID,
pub hit_position: FGVec2, pub hit_position: FGVec2,
@@ -45,9 +45,11 @@ pub fn air_collide_with_stage(
state_context.translation.0 + state_context.ecb.get_bottom_point(), state_context.translation.0 + state_context.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 state_context.stage_collision.stage_polys.iter().enumerate() {
if let Some(intersect_result) = poly.intersect_ray(ray_segment) { if let Some(intersect_result) = poly.intersect_ray(ray_segment) {
return Some(AirCollisionWithStageResult { intersect_results.push((AirCollisionWithStageResult {
line_id: { line_id: {
StageLineID { StageLineID {
polygon: poly_idx, polygon: poly_idx,
@@ -56,9 +58,14 @@ pub fn air_collide_with_stage(
}, },
hit_position: intersect_result.position, hit_position: intersect_result.position,
hit_normal: intersect_result.normal, hit_normal: intersect_result.normal,
}, intersect_result.position.distance_squared(ray_segment.point2())));
}
}
intersect_results.sort_by(| (_, a), (_, b) | {
a.cmp(b)
}); });
}
}
None intersect_results.iter().last().map(|(val, _)| {
val.to_owned().clone()
})
} }
+2 -2
View File
@@ -5,14 +5,14 @@ use crate::math::{int::FGi32, vec::FGVec2};
/// Environment collision box: the diamond used to resolve a fighter against /// Environment collision box: the diamond used to resolve a fighter against
/// the stage. Purely geometry — the collision response lives in /// the stage. Purely geometry — the collision response lives in
/// [`super::collision`]. /// [`super::collision`].
#[derive(Component, Debug, Clone, Copy)] #[derive(Component, Debug, Clone, Copy, Hash)]
#[require(FighterPreviousECB)] #[require(FighterPreviousECB)]
pub struct FighterECB { pub struct FighterECB {
pub vertical_half: FGi32, pub vertical_half: FGi32,
pub horizontal_half: FGi32, pub horizontal_half: FGi32,
} }
#[derive(Component, Debug, Clone, Copy, Default)] #[derive(Component, Debug, Clone, Copy, Default, Hash)]
pub struct FighterPreviousECB { pub struct FighterPreviousECB {
pub vertical_half: FGi32, pub vertical_half: FGi32,
pub horizontal_half: FGi32, pub horizontal_half: FGi32,
+1 -1
View File
@@ -10,7 +10,7 @@ use crate::{
/// A capsule after an arbitrary affine transform. Non-uniform scale turns the /// A capsule after an arbitrary affine transform. Non-uniform scale turns the
/// spherical caps and circular cylinder into ellipsoidal geometry. /// spherical caps and circular cylinder into ellipsoidal geometry.
#[derive(Clone, Copy, Debug, PartialEq)] #[derive(Clone, Copy, Debug, PartialEq, Hash)]
pub struct FixedAffineCapsule { pub struct FixedAffineCapsule {
pub transform: FixedMat4, pub transform: FixedMat4,
pub half_length: FGi32, pub half_length: FGi32,
+6 -2
View File
@@ -109,13 +109,17 @@ pub fn prepare_fighter_manifests(
); );
return; return;
} }
if !manifest.animations.contains_key(&AnimKind::Wait) {
for anim_kind in AnimKind::iter() {
if !manifest.animations.contains_key(&anim_kind) {
fail( fail(
&mut next_state, &mut next_state,
&format!("{:?} has no Wait animation", manifest.id), &format!("{:?} has no {:?} animation", manifest.id, anim_kind),
); );
return; return;
} }
}
if !manifest.camera.is_valid() { if !manifest.camera.is_valid() {
fail( fail(
&mut next_state, &mut next_state,
+9 -1
View File
@@ -144,13 +144,19 @@ impl Plugin for FighterPlugin {
// components; a component simulated here but missing from this list // components; a component simulated here but missing from this list
// is a desync waiting to happen. // is a desync waiting to happen.
.rollback_component_with_copy::<FighterECB>() .rollback_component_with_copy::<FighterECB>()
.checksum_component_with_hash::<FighterECB>()
.rollback_component_with_copy::<ecb::FighterPreviousECB>() .rollback_component_with_copy::<ecb::FighterPreviousECB>()
.checksum_component_with_hash::<ecb::FighterPreviousECB>()
.rollback_component_with_copy::<FighterVelocity>() .rollback_component_with_copy::<FighterVelocity>()
.checksum_component_with_hash::<FighterVelocity>()
.rollback_component_with_copy::<FighterTranslation>() .rollback_component_with_copy::<FighterTranslation>()
.checksum_component_with_hash::<FighterTranslation>()
.rollback_component_with_copy::<FighterPreviousTranslation>() .rollback_component_with_copy::<FighterPreviousTranslation>()
.checksum_component_with_hash::<FighterPreviousTranslation>()
.rollback_component_with_copy::<animation::FighterAnimationFrame>() .rollback_component_with_copy::<animation::FighterAnimationFrame>()
.checksum_component_with_hash::<animation::FighterAnimationFrame>() .checksum_component_with_hash::<animation::FighterAnimationFrame>()
.rollback_component_with_copy::<Grounded>() .rollback_component_with_copy::<Grounded>()
.checksum_component_with_hash::<Grounded>()
.rollback_component_with_copy::<FighterFacingDirection>() .rollback_component_with_copy::<FighterFacingDirection>()
.rollback_resource_with_reflect::<StageCollision>() .rollback_resource_with_reflect::<StageCollision>()
// Debug views. // Debug views.
@@ -176,14 +182,16 @@ impl Plugin for FighterPlugin {
) )
.rollback_component_with_clone::<FighterState>() .rollback_component_with_clone::<FighterState>()
.rollback_component_with_clone::<FighterHitboxes>() .rollback_component_with_clone::<FighterHitboxes>()
.checksum_component_with_hash::<FighterHitboxes>()
.rollback_component_with_clone::<FighterSolvedHurtboxes>() .rollback_component_with_clone::<FighterSolvedHurtboxes>()
.checksum_component_with_hash::<FighterSolvedHurtboxes>()
.checksum_component_with_hash::<FighterState>() .checksum_component_with_hash::<FighterState>()
.checksum_component_with_hash::<FighterFacingDirection>() .checksum_component_with_hash::<FighterFacingDirection>()
.register_type::<FighterFacingDirection>(); .register_type::<FighterFacingDirection>();
} }
} }
#[derive(Component, Clone)] #[derive(Component, Clone, Hash)]
pub struct FighterHitboxes { pub struct FighterHitboxes {
pub attack_script: Option<Handle<FighterAttackScript>>, pub attack_script: Option<Handle<FighterAttackScript>>,
pub active_hitboxes: Vec<usize>, pub active_hitboxes: Vec<usize>,
+4 -4
View File
@@ -10,16 +10,16 @@ use crate::{
math::{int::FGi32, vec::FGVec2, vec3::FGVec3}, math::{int::FGi32, vec::FGVec2, vec3::FGVec3},
}; };
#[derive(Component, Clone, Copy)] #[derive(Component, Clone, Copy, Hash)]
pub struct Grounded; pub struct Grounded;
#[derive(Component, Deref, DerefMut, Default, Debug, Clone, Copy)] #[derive(Component, Deref, DerefMut, Default, Debug, Clone, Copy, Hash)]
pub struct FighterVelocity(pub FGVec2); pub struct FighterVelocity(pub FGVec2);
#[derive(Component, Deref, DerefMut, Default, Clone, Copy)] #[derive(Component, Deref, DerefMut, Default, Clone, Copy, Hash)]
pub struct FighterPreviousTranslation(pub FGVec2); pub struct FighterPreviousTranslation(pub FGVec2);
#[derive(Component, Deref, DerefMut, Default, Clone, Copy)] #[derive(Component, Deref, DerefMut, Default, Clone, Copy, Hash)]
#[require(FighterPreviousTranslation)] #[require(FighterPreviousTranslation)]
pub struct FighterTranslation(pub FGVec2); pub struct FighterTranslation(pub FGVec2);
-5
View File
@@ -221,11 +221,6 @@ impl FighterStateImpl for JumpState {
}; };
state_context.velocity.y = vertical_vel; state_context.velocity.y = vertical_vel;
state_context.velocity.x += state_context
.fighter_manifest
.attributes
.jump_horizontal_velocity
* movement_stick_x;
} }
fn check_collision_interrupt( fn check_collision_interrupt(
+1 -1
View File
@@ -120,7 +120,7 @@ impl FighterStateContext<'_> {
anims_data anims_data
.frame_count(self.animation_frame.kind) .frame_count(self.animation_frame.kind)
.expect("Current animation should have baked frames") .expect("Current animation should have baked frames")
< self.animation_frame.frame <= self.animation_frame.frame
} }
} }
+2 -2
View File
@@ -25,7 +25,7 @@ pub enum FighterCommands {
/// Frames of life remaining for each buffered command. Indexed by /// Frames of life remaining for each buffered command. Indexed by
/// [`FighterCommands`] so adding a command is a two-line change here. /// [`FighterCommands`] so adding a command is a two-line change here.
#[derive(Default, Clone, Copy)] #[derive(Default, Clone, Copy, Hash)]
pub struct FighterCommandLifetimes { pub struct FighterCommandLifetimes {
smash_move_left: u8, smash_move_left: u8,
smash_move_right: u8, smash_move_right: u8,
@@ -60,7 +60,7 @@ impl IndexMut<FighterCommands> for FighterCommandLifetimes {
} }
} }
#[derive(Component, Default, Clone, Copy)] #[derive(Component, Default, Clone, Copy, Hash)]
#[require(Rollback)] #[require(Rollback)]
pub struct FighterInput { pub struct FighterInput {
command_lifetimes: FighterCommandLifetimes, command_lifetimes: FighterCommandLifetimes,
+1 -1
View File
@@ -4,7 +4,7 @@ use crate::math::vec::FGVec2;
/// One frame of a player's raw input. This is the type GGRS serializes and /// One frame of a player's raw input. This is the type GGRS serializes and
/// sends over the wire, so keep it small and keep it `PartialEq`. /// sends over the wire, so keep it small and keep it `PartialEq`.
#[derive(Copy, Clone, Debug, PartialEq, Default, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Default, Serialize, Deserialize, Hash)]
pub struct FighterInputFrame { pub struct FighterInputFrame {
pub movement: FGVec2, pub movement: FGVec2,
pub directional_attack: FGVec2, pub directional_attack: FGVec2,
+2 -1
View File
@@ -108,7 +108,8 @@ impl Plugin for FighterInputPlugin {
GgrsSchedule, GgrsSchedule,
buffer::postprocess_input.in_set(GameplaySet::Input), buffer::postprocess_input.in_set(GameplaySet::Input),
) )
.rollback_component_with_clone::<FighterInput>(); .rollback_component_with_clone::<FighterInput>()
.checksum_component_with_hash::<FighterInput>();
} }
} }
+6
View File
@@ -118,6 +118,12 @@ impl FGVec2 {
(to - self).length() (to - self).length()
} }
#[inline]
#[must_use]
pub fn distance_squared(self, to: Self) -> FGWide {
(to - self).length_squared()
}
#[inline] #[inline]
pub fn normalize(&self) -> Option<Self> { pub fn normalize(&self) -> Option<Self> {
let x = I32F32::from_num(self.x); let x = I32F32::from_num(self.x);