Attack system revamp (#82)
CI / build-and-test (push) Successful in 1m35s
CI / production-build (push) Successful in 11m29s

- Add crouch cancelling
- Add IASA for aerial attacks
- Add scaffolding for autocancel
- Add hitbox group system
- Add new ergonomic features for attack scripting
- Add more information to the hitbox viewer
- Improve the looks of debug capsules

Reviewed-on: #82
Co-authored-by: Álex Román Núñez <eirexe@eirteam.moe>
This commit was merged in pull request #82.
This commit is contained in:
2026-10-04 18:57:29 +00:00
committed by EIREXE
parent 04aceb05a9
commit d2d649b059
15 changed files with 1046 additions and 449 deletions
+22 -8
View File
@@ -1,6 +1,5 @@
use bevy::prelude::*;
use serde::{Deserialize, Serialize};
use std::collections::HashSet;
use crate::{fighter::attack::AttackHitbox, math::int::FGi32};
@@ -15,22 +14,37 @@ pub enum MoveAngleKind {
#[derive(Asset, Reflect, Serialize, Deserialize)]
pub struct FighterAttackScript {
pub hitboxes: Vec<AttackHitbox>,
pub iasa_frame: u32,
pub wont_autocancel_window: (u32, u32),
pub iasa_frame: Option<u32>,
pub wont_autocancel_window: Option<(u32, u32)>,
pub landing_duration: Option<u32>,
}
impl FighterAttackScript {
pub fn validate(&self) -> Result<(), String> {
let mut ids = HashSet::with_capacity(self.hitboxes.len());
for hitbox in &self.hitboxes {
hitbox.validate()?;
if !ids.insert(hitbox.id) {
return Err(format!("duplicate hitbox id {}", hitbox.id));
}
for (index, left) in self.hitboxes.iter().enumerate() {
for right in self.hitboxes.iter().skip(index + 1) {
if left.id == right.id
&& left.start_frame < right.end_frame
&& right.start_frame < left.end_frame
{
return Err(format!(
"hitbox id {} has overlapping intervals {}..{} and {}..{}",
left.id, left.start_frame, left.end_frame, right.start_frame,
right.end_frame
));
}
}
}
if self.wont_autocancel_window.0 > self.wont_autocancel_window.1 {
return Err("autocancel window end precedes its start".into());
if let Some(wont_autocancel_window) = self.wont_autocancel_window {
if wont_autocancel_window.0 > wont_autocancel_window.1 {
return Err("autocancel window end precedes its start".into());
}
}
Ok(())
}
}