Integrate basic attack script debug.
This commit is contained in:
@@ -149,4 +149,8 @@ pub enum AnimKind {
|
|||||||
AirDodge,
|
AirDodge,
|
||||||
Fall,
|
Fall,
|
||||||
Turn,
|
Turn,
|
||||||
|
|
||||||
|
// Attacks
|
||||||
|
|
||||||
|
AttackJab1,
|
||||||
}
|
}
|
||||||
|
|||||||
+27
-4
@@ -1,7 +1,9 @@
|
|||||||
use bevy::reflect::Reflect;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use bevy::{asset::Handle, ecs::component::Component, reflect::Reflect};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::math::{int::FGi32, vec3::FGVec3};
|
use crate::{fighter::animation::AnimKind, math::{int::FGi32, vec3::FGVec3}, scripting::FighterAttackScript};
|
||||||
#[derive(Debug, Default, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Default, Clone, Serialize, Deserialize)]
|
||||||
pub struct FighterDamage(FGi32);
|
pub struct FighterDamage(FGi32);
|
||||||
|
|
||||||
@@ -59,9 +61,19 @@ impl AttackAngle {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Reflect, PartialEq, Eq, Hash, Clone)]
|
#[derive(Serialize, Deserialize, Reflect, PartialEq, Eq, Hash, Clone, Debug)]
|
||||||
pub enum AttackKind {
|
pub enum AttackKind {
|
||||||
NAir
|
NAir,
|
||||||
|
Jab
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AttackKind {
|
||||||
|
pub fn get_animation(&self) -> AnimKind {
|
||||||
|
match self {
|
||||||
|
AttackKind::NAir => AnimKind::AttackJab1,
|
||||||
|
AttackKind::Jab => AnimKind::AttackJab1,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Reflect, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Reflect, Serialize, Deserialize)]
|
||||||
@@ -79,3 +91,14 @@ pub struct AttackHitbox {
|
|||||||
pub start_frame: u32,
|
pub start_frame: u32,
|
||||||
pub end_frame: u32
|
pub end_frame: u32
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn update_active_hitbox_list(script: &FighterAttackScript, list: &mut Vec<usize>, frame: u32) {
|
||||||
|
*list = script.hitboxes.iter().enumerate().filter(|(i, hb)| {
|
||||||
|
hb.start_frame <= frame && hb.end_frame > frame
|
||||||
|
}).map(|(i, _)| i).collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Component)]
|
||||||
|
pub struct FighterAttackScriptAssets {
|
||||||
|
pub scripts: HashMap<AttackKind, Handle<FighterAttackScript>>
|
||||||
|
}
|
||||||
@@ -20,7 +20,10 @@ use serde::{Deserialize, Serialize};
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
fighter::{animation::AnimKind, manifest::FighterManifest},
|
fighter::{animation::AnimKind, manifest::FighterManifest},
|
||||||
math::int::{FGWide, FGi32},
|
math::{
|
||||||
|
int::{FGWide, FGi32},
|
||||||
|
vec3::FGVec3,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const BAKED_ANIMATION_FPS: u32 = 60;
|
pub const BAKED_ANIMATION_FPS: u32 = 60;
|
||||||
@@ -33,6 +36,14 @@ pub struct FixedMat4 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl FixedMat4 {
|
impl FixedMat4 {
|
||||||
|
pub const IDENTITY: Self = Self {
|
||||||
|
cols: [
|
||||||
|
[FGi32::ONE, FGi32::ZERO, FGi32::ZERO, FGi32::ZERO],
|
||||||
|
[FGi32::ZERO, FGi32::ONE, FGi32::ZERO, FGi32::ZERO],
|
||||||
|
[FGi32::ZERO, FGi32::ZERO, FGi32::ONE, FGi32::ZERO],
|
||||||
|
[FGi32::ZERO, FGi32::ZERO, FGi32::ZERO, FGi32::ONE],
|
||||||
|
]
|
||||||
|
};
|
||||||
fn from_mat4(matrix: Mat4) -> io::Result<Self> {
|
fn from_mat4(matrix: Mat4) -> io::Result<Self> {
|
||||||
let values = matrix.to_cols_array();
|
let values = matrix.to_cols_array();
|
||||||
let mut cols = [[FGi32::ZERO; 4]; 4];
|
let mut cols = [[FGi32::ZERO; 4]; 4];
|
||||||
@@ -47,7 +58,7 @@ impl FixedMat4 {
|
|||||||
Ok(Self { cols })
|
Ok(Self { cols })
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mul(self, rhs: Self) -> Self {
|
pub fn mul(self, rhs: Self) -> Self {
|
||||||
let mut cols = [[FGi32::ZERO; 4]; 4];
|
let mut cols = [[FGi32::ZERO; 4]; 4];
|
||||||
for column in 0..4 {
|
for column in 0..4 {
|
||||||
for row in 0..4 {
|
for row in 0..4 {
|
||||||
@@ -61,6 +72,67 @@ impl FixedMat4 {
|
|||||||
}
|
}
|
||||||
Self { cols }
|
Self { cols }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn transform_point(self, point: FGVec3) -> FGVec3 {
|
||||||
|
let input = [point.x, point.y, point.z, FGi32::ONE];
|
||||||
|
let mut output = [FGi32::ZERO; 3];
|
||||||
|
for row in 0..3 {
|
||||||
|
let mut value = FGWide::ZERO;
|
||||||
|
for (column, input) in input.into_iter().enumerate() {
|
||||||
|
value += FGWide::from_num(self.cols[column][row]) * FGWide::from_num(input);
|
||||||
|
}
|
||||||
|
output[row] = FGi32::from_num(value);
|
||||||
|
}
|
||||||
|
FGVec3 {
|
||||||
|
x: output[0],
|
||||||
|
y: output[1],
|
||||||
|
z: output[2],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn translate(&mut self, translation: FGVec3) {
|
||||||
|
self.cols[3][0] = translation.x;
|
||||||
|
self.cols[3][1] = translation.y;
|
||||||
|
self.cols[3][2] = translation.z;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn rotate_y(self, quarter_turns: u8) -> Self {
|
||||||
|
let rotation = match quarter_turns % 4 {
|
||||||
|
0 => Self {
|
||||||
|
cols: [
|
||||||
|
[FGi32::ONE, FGi32::ZERO, FGi32::ZERO, FGi32::ZERO],
|
||||||
|
[FGi32::ZERO, FGi32::ONE, FGi32::ZERO, FGi32::ZERO],
|
||||||
|
[FGi32::ZERO, FGi32::ZERO, FGi32::ONE, FGi32::ZERO],
|
||||||
|
[FGi32::ZERO, FGi32::ZERO, FGi32::ZERO, FGi32::ONE],
|
||||||
|
],
|
||||||
|
},
|
||||||
|
1 => Self {
|
||||||
|
cols: [
|
||||||
|
[FGi32::ZERO, FGi32::ZERO, FGi32::NEG_ONE, FGi32::ZERO],
|
||||||
|
[FGi32::ZERO, FGi32::ONE, FGi32::ZERO, FGi32::ZERO],
|
||||||
|
[FGi32::ONE, FGi32::ZERO, FGi32::ZERO, FGi32::ZERO],
|
||||||
|
[FGi32::ZERO, FGi32::ZERO, FGi32::ZERO, FGi32::ONE],
|
||||||
|
],
|
||||||
|
},
|
||||||
|
2 => Self {
|
||||||
|
cols: [
|
||||||
|
[FGi32::NEG_ONE, FGi32::ZERO, FGi32::ZERO, FGi32::ZERO],
|
||||||
|
[FGi32::ZERO, FGi32::ONE, FGi32::ZERO, FGi32::ZERO],
|
||||||
|
[FGi32::ZERO, FGi32::ZERO, FGi32::NEG_ONE, FGi32::ZERO],
|
||||||
|
[FGi32::ZERO, FGi32::ZERO, FGi32::ZERO, FGi32::ONE],
|
||||||
|
],
|
||||||
|
},
|
||||||
|
_ => Self {
|
||||||
|
cols: [
|
||||||
|
[FGi32::ZERO, FGi32::ZERO, FGi32::ONE, FGi32::ZERO],
|
||||||
|
[FGi32::ZERO, FGi32::ONE, FGi32::ZERO, FGi32::ZERO],
|
||||||
|
[FGi32::NEG_ONE, FGi32::ZERO, FGi32::ZERO, FGi32::ZERO],
|
||||||
|
[FGi32::ZERO, FGi32::ZERO, FGi32::ZERO, FGi32::ONE],
|
||||||
|
],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
self.mul(rotation)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
@@ -525,4 +597,50 @@ mod tests {
|
|||||||
baked.bone_names.len()
|
baked.bone_names.len()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn fixed_matrix_transforms_points() {
|
||||||
|
let transform = FixedMat4 {
|
||||||
|
cols: [
|
||||||
|
[FGi32::lit("2"), FGi32::ZERO, FGi32::ZERO, FGi32::ZERO],
|
||||||
|
[FGi32::ZERO, FGi32::lit("3"), FGi32::ZERO, FGi32::ZERO],
|
||||||
|
[FGi32::ZERO, FGi32::ZERO, FGi32::lit("4"), FGi32::ZERO],
|
||||||
|
[
|
||||||
|
FGi32::lit("10"),
|
||||||
|
FGi32::lit("-5"),
|
||||||
|
FGi32::lit("1.5"),
|
||||||
|
FGi32::ONE,
|
||||||
|
],
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
transform.transform_point(FGVec3::lit("1.25", "-2", "0.5")),
|
||||||
|
FGVec3::lit("12.5", "-11", "3.5")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn fixed_matrix_rotates_points_around_y() {
|
||||||
|
let transform = FixedMat4 {
|
||||||
|
cols: [
|
||||||
|
[FGi32::ONE, FGi32::ZERO, FGi32::ZERO, FGi32::ZERO],
|
||||||
|
[FGi32::ZERO, FGi32::ONE, FGi32::ZERO, FGi32::ZERO],
|
||||||
|
[FGi32::ZERO, FGi32::ZERO, FGi32::ONE, FGi32::ZERO],
|
||||||
|
[
|
||||||
|
FGi32::lit("10"),
|
||||||
|
FGi32::lit("2"),
|
||||||
|
FGi32::lit("-3"),
|
||||||
|
FGi32::ONE,
|
||||||
|
],
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
transform
|
||||||
|
.rotate_y(5)
|
||||||
|
.transform_point(FGVec3::lit("1", "0", "0")),
|
||||||
|
FGVec3::lit("10", "2", "-4")
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+41
-3
@@ -10,10 +10,11 @@ use crate::fighter::ecb::FighterPreviousECB;
|
|||||||
use crate::fighter::state::StateNameDebug;
|
use crate::fighter::state::StateNameDebug;
|
||||||
use crate::fighter::visual::FighterAnimations;
|
use crate::fighter::visual::FighterAnimations;
|
||||||
use crate::fighter::{
|
use crate::fighter::{
|
||||||
FighterECB, FighterPreviousTranslation, FighterTranslation,
|
FighterECB, FighterFacingDirection, FighterHitboxes, FighterPreviousTranslation, FighterTranslation, FighterVelocity,
|
||||||
FighterVelocity,
|
|
||||||
};
|
};
|
||||||
use crate::input::FighterInput;
|
use crate::input::FighterInput;
|
||||||
|
use crate::math::vec3::FGVec3;
|
||||||
|
use crate::scripting::FighterAttackScript;
|
||||||
|
|
||||||
pub fn debug_draw_ecb(
|
pub fn debug_draw_ecb(
|
||||||
ecbs: Query<(
|
ecbs: Query<(
|
||||||
@@ -60,14 +61,51 @@ pub fn animation_debug(
|
|||||||
.get(&anims.baked)
|
.get(&anims.baked)
|
||||||
.expect("Baked anims should be in");
|
.expect("Baked anims should be in");
|
||||||
for bone in &baked.bone_names {
|
for bone in &baked.bone_names {
|
||||||
let out = anims.sample_bone(&baked_anims, *frame, bone);
|
if bone != "Bone_30" {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let out = anims.sample_bone(&baked_anims, frame, bone);
|
||||||
if let Some(out) = out {
|
if let Some(out) = out {
|
||||||
let pos = global_transform.transform_point(Vec3::new(
|
let pos = global_transform.transform_point(Vec3::new(
|
||||||
out.cols[3][0].to_num(),
|
out.cols[3][0].to_num(),
|
||||||
out.cols[3][1].to_num(),
|
out.cols[3][1].to_num(),
|
||||||
out.cols[3][2].to_num(),
|
out.cols[3][2].to_num(),
|
||||||
));
|
));
|
||||||
|
//gizmos.text(pos, bone, 1.0, Vec2::new(0.0, 0.0), bevy::color::palettes::css::BLACK);
|
||||||
gizmos.cross(pos, 0.5, bevy::color::palettes::css::RED);
|
gizmos.cross(pos, 0.5, bevy::color::palettes::css::RED);
|
||||||
|
gizmos.axes(*global_transform, 1.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn attack_debug(
|
||||||
|
query: Query<(&FighterHitboxes, &FighterAnimationFrame, &FighterAnimations, &FighterTranslation, &FighterFacingDirection)>,
|
||||||
|
baked_anims: Res<Assets<BakedFighterAnimations>>,
|
||||||
|
attack_scripts: Res<Assets<FighterAttackScript>>,
|
||||||
|
mut gizmos: Gizmos,
|
||||||
|
) {
|
||||||
|
for (hitboxes, frame, animations, translation, facing_direction) in query {
|
||||||
|
if let Some(script) = &hitboxes.attack_script {
|
||||||
|
let script = attack_scripts.get(script).expect("Script ref should be valid");
|
||||||
|
let player_trf = translation.get_3d_transform(facing_direction);
|
||||||
|
|
||||||
|
for i in hitboxes.active_hitboxes.iter() {
|
||||||
|
let offset = script.hitboxes[*i].offset;
|
||||||
|
let radius = script.hitboxes[*i].radius;
|
||||||
|
let bone = &script.hitboxes[*i].bone;
|
||||||
|
|
||||||
|
let trf = animations.sample_bone(&baked_anims, frame, bone);
|
||||||
|
if let Some(trf) = trf {
|
||||||
|
let trf = player_trf.mul(trf);
|
||||||
|
let start = player_trf.transform_point(FGVec3::lit("0.0", "1.0", "0.0"));
|
||||||
|
let end = player_trf.transform_point(FGVec3::lit("0.0", "1.0", "1.0"));
|
||||||
|
let pos = trf.transform_point(offset);
|
||||||
|
let pos_draw = Vec3::new(pos.x.to_num(), pos.y.to_num(), pos.z.to_num());
|
||||||
|
gizmos.sphere(pos_draw, radius.to_num(), bevy::color::palettes::css::RED);
|
||||||
|
|
||||||
|
gizmos.arrow(start.to_vec3(), end.to_vec3(),bevy::color::palettes::css::RED);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+17
-11
@@ -29,16 +29,8 @@ pub use motion::{FighterPreviousTranslation, FighterTranslation, FighterVelocity
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
fighter::{
|
fighter::{
|
||||||
animation::animation_init,
|
animation::animation_init, attack::FighterAttackScriptAssets, manifest::FighterManifest, state::{FighterState, fall::FallState}, visual::FighterAnimations,
|
||||||
manifest::FighterManifest,
|
}, input::FighterInput, math::{int::FGi32, vec::FGVec2}, player::Player, schedule::GameplaySet, scripting::FighterAttackScript, stage::line::StageCollision,
|
||||||
state::{FighterState, fall::FallState},
|
|
||||||
visual::FighterAnimations,
|
|
||||||
},
|
|
||||||
input::FighterInput,
|
|
||||||
math::{int::FGi32, vec::FGVec2},
|
|
||||||
player::Player,
|
|
||||||
schedule::GameplaySet,
|
|
||||||
stage::line::StageCollision,
|
|
||||||
};
|
};
|
||||||
use state::state_interrupt_system;
|
use state::state_interrupt_system;
|
||||||
|
|
||||||
@@ -158,20 +150,29 @@ impl Plugin for FighterPlugin {
|
|||||||
.add_systems(FixedPostUpdate, debug::debug_draw_ecb)
|
.add_systems(FixedPostUpdate, debug::debug_draw_ecb)
|
||||||
.add_systems(EguiPrimaryContextPass, debug::fighter_debug)
|
.add_systems(EguiPrimaryContextPass, debug::fighter_debug)
|
||||||
.add_systems(FixedPostUpdate, debug::animation_debug)
|
.add_systems(FixedPostUpdate, debug::animation_debug)
|
||||||
|
.add_systems(FixedPostUpdate, debug::attack_debug)
|
||||||
.add_systems(EguiPrimaryContextPass, debug::update_config)
|
.add_systems(EguiPrimaryContextPass, debug::update_config)
|
||||||
.rollback_component_with_clone::<FighterState>()
|
.rollback_component_with_clone::<FighterState>()
|
||||||
|
.rollback_component_with_clone::<FighterHitboxes>()
|
||||||
.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)]
|
||||||
|
pub struct FighterHitboxes {
|
||||||
|
pub attack_script: Option<Handle<FighterAttackScript>>,
|
||||||
|
pub active_hitboxes: Vec<usize>
|
||||||
|
}
|
||||||
|
|
||||||
pub fn spawn_fighter(
|
pub fn spawn_fighter(
|
||||||
commands: &mut Commands,
|
commands: &mut Commands,
|
||||||
player_handle: usize,
|
player_handle: usize,
|
||||||
spawn_position: FGVec2,
|
spawn_position: FGVec2,
|
||||||
manifest: Handle<FighterManifest>,
|
manifest: Handle<FighterManifest>,
|
||||||
animations: FighterAnimations,
|
animations: FighterAnimations,
|
||||||
|
attack_scripts: FighterAttackScriptAssets,
|
||||||
visual_root: WorldAssetRoot,
|
visual_root: WorldAssetRoot,
|
||||||
) {
|
) {
|
||||||
commands.spawn((
|
commands.spawn((
|
||||||
@@ -183,14 +184,19 @@ pub fn spawn_fighter(
|
|||||||
manifest: manifest,
|
manifest: manifest,
|
||||||
},
|
},
|
||||||
FighterFacingDirection::Right,
|
FighterFacingDirection::Right,
|
||||||
FighterECB {
|
(FighterECB {
|
||||||
vertical_half: FGi32::lit("5.0"),
|
vertical_half: FGi32::lit("5.0"),
|
||||||
horizontal_half: FGi32::lit("2.5"),
|
horizontal_half: FGi32::lit("2.5"),
|
||||||
},
|
},
|
||||||
|
FighterHitboxes {
|
||||||
|
attack_script: None,
|
||||||
|
active_hitboxes: vec![]
|
||||||
|
}),
|
||||||
FighterVelocity::default(),
|
FighterVelocity::default(),
|
||||||
FighterTranslation(spawn_position),
|
FighterTranslation(spawn_position),
|
||||||
visual_root,
|
visual_root,
|
||||||
animations,
|
animations,
|
||||||
|
attack_scripts,
|
||||||
FighterState::Fall(FallState),
|
FighterState::Fall(FallState),
|
||||||
animation::FighterAnimationFrame::new(animation::AnimKind::Wait, true),
|
animation::FighterAnimationFrame::new(animation::AnimKind::Wait, true),
|
||||||
FighterVisual,
|
FighterVisual,
|
||||||
|
|||||||
+13
-1
@@ -2,8 +2,9 @@
|
|||||||
//! this module is what turns that into a position.
|
//! this module is what turns that into a position.
|
||||||
|
|
||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
|
use fixed::types::I16F16;
|
||||||
|
|
||||||
use crate::math::vec::FGVec2;
|
use crate::{fighter::{FighterFacingDirection, baked_animation::FixedMat4}, math::{int::FGi32, vec::FGVec2, vec3::FGVec3}};
|
||||||
|
|
||||||
#[derive(Component, Clone, Copy)]
|
#[derive(Component, Clone, Copy)]
|
||||||
pub struct Grounded;
|
pub struct Grounded;
|
||||||
@@ -18,6 +19,17 @@ pub struct FighterPreviousTranslation(pub FGVec2);
|
|||||||
#[require(FighterPreviousTranslation)]
|
#[require(FighterPreviousTranslation)]
|
||||||
pub struct FighterTranslation(pub FGVec2);
|
pub struct FighterTranslation(pub FGVec2);
|
||||||
|
|
||||||
|
impl FighterTranslation {
|
||||||
|
pub fn get_3d_transform(&self, facing_dir: &FighterFacingDirection) -> FixedMat4 {
|
||||||
|
let mut o = match facing_dir {
|
||||||
|
FighterFacingDirection::Left => FixedMat4::IDENTITY.rotate_y(3),
|
||||||
|
FighterFacingDirection::Right => FixedMat4::IDENTITY.rotate_y(1),
|
||||||
|
};
|
||||||
|
o.translate(FGVec3::new(self.0.x, self.0.y, FGi32::ZERO));
|
||||||
|
o
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn apply_air_motion(
|
pub fn apply_air_motion(
|
||||||
fighters: Query<(
|
fighters: Query<(
|
||||||
&FighterVelocity,
|
&FighterVelocity,
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
//! ECS types so it stays cheap to reason about and to unit-test — it has to be
|
//! ECS types so it stays cheap to reason about and to unit-test — it has to be
|
||||||
//! bit-for-bit deterministic for rollback.
|
//! bit-for-bit deterministic for rollback.
|
||||||
|
|
||||||
use crate::fighter::state::{FighterState, FighterStateContext, dash, turn, wait, walk};
|
use crate::fighter::state::{FighterState, FighterStateContext, dash, ground_attack, turn, wait, walk};
|
||||||
use crate::fighter::{
|
use crate::fighter::{
|
||||||
FighterAttributes, FighterPreviousTranslation, FighterTranslation, FighterVelocity,
|
FighterAttributes, FighterPreviousTranslation, FighterTranslation, FighterVelocity,
|
||||||
};
|
};
|
||||||
@@ -151,7 +151,9 @@ pub fn grounded_movement_standstill_common_interrupts(
|
|||||||
state_context: &FighterStateContext,
|
state_context: &FighterStateContext,
|
||||||
ground_common: &GroundedStateCommon,
|
ground_common: &GroundedStateCommon,
|
||||||
) -> Option<FighterState> {
|
) -> Option<FighterState> {
|
||||||
if let Some(state) = dash::check_input(state_context, &ground_common) {
|
if let Some(state) = ground_attack::check_interrupt(state_context, &ground_common) {
|
||||||
|
Some(state)
|
||||||
|
} else if let Some(state) = dash::check_input(state_context, &ground_common) {
|
||||||
Some(state)
|
Some(state)
|
||||||
} else if let Some(state) = turn::check_input(state_context, &ground_common) {
|
} else if let Some(state) = turn::check_input(state_context, &ground_common) {
|
||||||
Some(state)
|
Some(state)
|
||||||
|
|||||||
@@ -0,0 +1,48 @@
|
|||||||
|
use crate::fighter::{attack::{AttackKind, update_active_hitbox_list}, state::{FighterState, FighterStateImpl, ground::GroundedStateCommon, wait::WaitState}};
|
||||||
|
|
||||||
|
use bevy::prelude::*;
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Hash)]
|
||||||
|
pub struct GroundAttackState {
|
||||||
|
pub attack_kind: AttackKind,
|
||||||
|
pub grounded_common: GroundedStateCommon,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FighterStateImpl for GroundAttackState {
|
||||||
|
const NAME: &'static str = "GroundAttack";
|
||||||
|
|
||||||
|
fn check_interrupt(&self, state_context: &mut super::FighterStateContext) -> Option<FighterState> {
|
||||||
|
if state_context.is_current_animation_finished() {
|
||||||
|
Some(FighterState::Wait(WaitState {
|
||||||
|
grounded_common: self.grounded_common.clone()
|
||||||
|
}))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update(&mut self, state_context: &mut super::FighterStateContext) {
|
||||||
|
let script = state_context.attack_scripts.get(&state_context.attack_script_assets.scripts[&self.attack_kind]);
|
||||||
|
if let Some(script) = script {
|
||||||
|
let animation_frame = state_context.get_current_animation_frame();
|
||||||
|
update_active_hitbox_list(script, &mut state_context.hitboxes.active_hitboxes, animation_frame);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn on_enter(&mut self, state_context: &mut super::FighterStateContext) {
|
||||||
|
state_context.play_animation(self.attack_kind.get_animation(), false);
|
||||||
|
state_context.hitboxes.attack_script = Some(state_context.attack_script_assets.scripts[&self.attack_kind].clone());
|
||||||
|
state_context.hitboxes.active_hitboxes.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn check_interrupt(state_context: &super::FighterStateContext, grounded_common: &GroundedStateCommon) -> Option<FighterState> {
|
||||||
|
if state_context.input.has_command(crate::input::FighterCommands::Attack) {
|
||||||
|
Some(FighterState::GroundAttack(GroundAttackState {
|
||||||
|
attack_kind: AttackKind::Jab,
|
||||||
|
grounded_common: grounded_common.clone()
|
||||||
|
}))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,16 +6,18 @@ use bevy::ecs::query::QueryData;
|
|||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
|
|
||||||
use crate::fighter::animation::{AnimKind, FighterAnimationFrame, FighterAnimationPlayerLink};
|
use crate::fighter::animation::{AnimKind, FighterAnimationFrame, FighterAnimationPlayerLink};
|
||||||
|
use crate::fighter::attack::FighterAttackScriptAssets;
|
||||||
use crate::fighter::baked_animation::{BakedFighterAnimations, FixedMat4};
|
use crate::fighter::baked_animation::{BakedFighterAnimations, FixedMat4};
|
||||||
use crate::fighter::ecb::FighterPreviousECB;
|
use crate::fighter::ecb::FighterPreviousECB;
|
||||||
use crate::fighter::manifest::FighterManifest;
|
use crate::fighter::manifest::FighterManifest;
|
||||||
|
use crate::fighter::state::ground_attack::GroundAttackState;
|
||||||
use crate::fighter::visual::FighterAnimations;
|
use crate::fighter::visual::FighterAnimations;
|
||||||
use crate::fighter::{
|
use crate::fighter::{
|
||||||
Fighter, FighterECB, FighterFacingDirection, FighterPreviousTranslation,
|
Fighter, FighterECB, FighterFacingDirection, FighterHitboxes, FighterPreviousTranslation, FighterTranslation, FighterVelocity,
|
||||||
FighterTranslation, FighterVelocity,
|
|
||||||
};
|
};
|
||||||
use crate::game_settings::GameSettings;
|
use crate::game_settings::GameSettings;
|
||||||
use crate::input::FighterInput;
|
use crate::input::FighterInput;
|
||||||
|
use crate::scripting::FighterAttackScript;
|
||||||
use crate::stage::line::StageCollision;
|
use crate::stage::line::StageCollision;
|
||||||
|
|
||||||
pub mod air;
|
pub mod air;
|
||||||
@@ -29,6 +31,7 @@ pub mod run;
|
|||||||
pub mod turn;
|
pub mod turn;
|
||||||
pub mod wait;
|
pub mod wait;
|
||||||
pub mod walk;
|
pub mod walk;
|
||||||
|
pub mod ground_attack;
|
||||||
|
|
||||||
macro_rules! fighter_states {
|
macro_rules! fighter_states {
|
||||||
($($variant:ident => $ty:ty),* $(,)?) => {
|
($($variant:ident => $ty:ty),* $(,)?) => {
|
||||||
@@ -80,6 +83,7 @@ pub struct FighterStateContext<'a> {
|
|||||||
pub translation: &'a mut FighterTranslation,
|
pub translation: &'a mut FighterTranslation,
|
||||||
pub prev_translation: &'a mut FighterPreviousTranslation,
|
pub prev_translation: &'a mut FighterPreviousTranslation,
|
||||||
pub input: &'a mut FighterInput,
|
pub input: &'a mut FighterInput,
|
||||||
|
pub hitboxes: &'a mut FighterHitboxes,
|
||||||
pub velocity: &'a mut FighterVelocity,
|
pub velocity: &'a mut FighterVelocity,
|
||||||
pub ecb: &'a mut FighterECB,
|
pub ecb: &'a mut FighterECB,
|
||||||
pub prev_ecb: &'a mut FighterPreviousECB,
|
pub prev_ecb: &'a mut FighterPreviousECB,
|
||||||
@@ -91,7 +95,9 @@ pub struct FighterStateContext<'a> {
|
|||||||
pub animation_transitions: &'a mut AnimationTransitions,
|
pub animation_transitions: &'a mut AnimationTransitions,
|
||||||
pub animation_frame: &'a mut FighterAnimationFrame,
|
pub animation_frame: &'a mut FighterAnimationFrame,
|
||||||
pub baked_animations: &'a Assets<BakedFighterAnimations>,
|
pub baked_animations: &'a Assets<BakedFighterAnimations>,
|
||||||
|
pub attack_scripts: &'a Assets<FighterAttackScript>,
|
||||||
pub fighter_manifest: &'a FighterManifest,
|
pub fighter_manifest: &'a FighterManifest,
|
||||||
|
pub attack_script_assets: &'a FighterAttackScriptAssets,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FighterStateContext<'_> {
|
impl FighterStateContext<'_> {
|
||||||
@@ -124,7 +130,7 @@ impl FighterStateContext<'_> {
|
|||||||
|
|
||||||
pub fn sample_bone(&self, bone: &str) -> Option<FixedMat4> {
|
pub fn sample_bone(&self, bone: &str) -> Option<FixedMat4> {
|
||||||
self.animations
|
self.animations
|
||||||
.sample_bone(self.baked_animations, *self.animation_frame, bone)
|
.sample_bone(self.baked_animations, self.animation_frame, bone)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -138,7 +144,8 @@ fighter_states! {
|
|||||||
Jump => jump::JumpState,
|
Jump => jump::JumpState,
|
||||||
Land => land::LandingState,
|
Land => land::LandingState,
|
||||||
AirDodge => air_dodge::AirDodgeState,
|
AirDodge => air_dodge::AirDodgeState,
|
||||||
Turn => turn::TurnState
|
Turn => turn::TurnState,
|
||||||
|
GroundAttack => ground_attack::GroundAttackState,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(QueryData)]
|
#[derive(QueryData)]
|
||||||
@@ -147,6 +154,7 @@ pub struct FighterFrameQuery {
|
|||||||
pub translation: &'static mut FighterTranslation,
|
pub translation: &'static mut FighterTranslation,
|
||||||
pub prev_translation: &'static mut FighterPreviousTranslation,
|
pub prev_translation: &'static mut FighterPreviousTranslation,
|
||||||
pub input: &'static mut FighterInput,
|
pub input: &'static mut FighterInput,
|
||||||
|
pub hitboxes: &'static mut FighterHitboxes,
|
||||||
pub velocity: &'static mut FighterVelocity,
|
pub velocity: &'static mut FighterVelocity,
|
||||||
pub ecb: &'static mut FighterECB,
|
pub ecb: &'static mut FighterECB,
|
||||||
pub prev_ecb: &'static mut FighterPreviousECB,
|
pub prev_ecb: &'static mut FighterPreviousECB,
|
||||||
@@ -164,12 +172,15 @@ impl<'w, 's> FighterFrameQueryItem<'w, 's> {
|
|||||||
animation_player: &'a mut AnimationPlayer,
|
animation_player: &'a mut AnimationPlayer,
|
||||||
animation_transitions: &'a mut AnimationTransitions,
|
animation_transitions: &'a mut AnimationTransitions,
|
||||||
baked_animations: &'a Assets<BakedFighterAnimations>,
|
baked_animations: &'a Assets<BakedFighterAnimations>,
|
||||||
|
attack_scripts: &'a Assets<FighterAttackScript>,
|
||||||
|
attack_script_assets: &'a FighterAttackScriptAssets,
|
||||||
manifest: &'a FighterManifest,
|
manifest: &'a FighterManifest,
|
||||||
) -> FighterStateContext<'a> {
|
) -> FighterStateContext<'a> {
|
||||||
FighterStateContext {
|
FighterStateContext {
|
||||||
translation: &mut self.translation,
|
translation: &mut self.translation,
|
||||||
prev_translation: &mut self.prev_translation,
|
prev_translation: &mut self.prev_translation,
|
||||||
input: &mut self.input,
|
input: &mut self.input,
|
||||||
|
hitboxes: &mut self.hitboxes,
|
||||||
velocity: &mut self.velocity,
|
velocity: &mut self.velocity,
|
||||||
ecb: &mut self.ecb,
|
ecb: &mut self.ecb,
|
||||||
prev_ecb: &mut self.prev_ecb,
|
prev_ecb: &mut self.prev_ecb,
|
||||||
@@ -181,6 +192,8 @@ impl<'w, 's> FighterFrameQueryItem<'w, 's> {
|
|||||||
animation_transitions,
|
animation_transitions,
|
||||||
animation_frame: &mut self.animation_frame,
|
animation_frame: &mut self.animation_frame,
|
||||||
baked_animations,
|
baked_animations,
|
||||||
|
attack_scripts,
|
||||||
|
attack_script_assets,
|
||||||
fighter_manifest: manifest,
|
fighter_manifest: manifest,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -195,6 +208,7 @@ pub struct StatefulFighterQuery {
|
|||||||
pub animations: &'static FighterAnimations,
|
pub animations: &'static FighterAnimations,
|
||||||
pub animation_player_link: &'static FighterAnimationPlayerLink,
|
pub animation_player_link: &'static FighterAnimationPlayerLink,
|
||||||
pub fighter: &'static Fighter,
|
pub fighter: &'static Fighter,
|
||||||
|
pub attack_script_assets: &'static FighterAttackScriptAssets,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Component)]
|
#[derive(Component)]
|
||||||
@@ -212,6 +226,7 @@ pub fn state_update_system(
|
|||||||
stage_collision: Res<StageCollision>,
|
stage_collision: Res<StageCollision>,
|
||||||
game_settings: Res<GameSettings>,
|
game_settings: Res<GameSettings>,
|
||||||
baked_animations: Res<Assets<BakedFighterAnimations>>,
|
baked_animations: Res<Assets<BakedFighterAnimations>>,
|
||||||
|
attack_scripts: Res<Assets<FighterAttackScript>>,
|
||||||
manifests: Res<Assets<FighterManifest>>,
|
manifests: Res<Assets<FighterManifest>>,
|
||||||
) {
|
) {
|
||||||
for fighter in &mut query {
|
for fighter in &mut query {
|
||||||
@@ -235,6 +250,8 @@ pub fn state_update_system(
|
|||||||
&mut animation_player,
|
&mut animation_player,
|
||||||
&mut animation_transitions,
|
&mut animation_transitions,
|
||||||
&baked_animations,
|
&baked_animations,
|
||||||
|
&attack_scripts,
|
||||||
|
&fighter.attack_script_assets,
|
||||||
&manifests
|
&manifests
|
||||||
.get(&(fighter.fighter.manifest))
|
.get(&(fighter.fighter.manifest))
|
||||||
.expect("Fighter manifest should be valid"),
|
.expect("Fighter manifest should be valid"),
|
||||||
@@ -250,6 +267,7 @@ pub fn state_interrupt_system(
|
|||||||
game_settings: Res<GameSettings>,
|
game_settings: Res<GameSettings>,
|
||||||
baked_animations: Res<Assets<BakedFighterAnimations>>,
|
baked_animations: Res<Assets<BakedFighterAnimations>>,
|
||||||
fighter_manifests: Res<Assets<FighterManifest>>,
|
fighter_manifests: Res<Assets<FighterManifest>>,
|
||||||
|
attack_scripts: Res<Assets<FighterAttackScript>>,
|
||||||
mut commands: Commands,
|
mut commands: Commands,
|
||||||
) {
|
) {
|
||||||
for fighter in &mut query {
|
for fighter in &mut query {
|
||||||
@@ -260,6 +278,7 @@ pub fn state_interrupt_system(
|
|||||||
animations,
|
animations,
|
||||||
animation_player_link,
|
animation_player_link,
|
||||||
fighter,
|
fighter,
|
||||||
|
attack_script_assets
|
||||||
} = fighter;
|
} = fighter;
|
||||||
let Ok((mut animation_player, mut animation_transitions)) =
|
let Ok((mut animation_player, mut animation_transitions)) =
|
||||||
animation_players.get_mut(animation_player_link.player())
|
animation_players.get_mut(animation_player_link.player())
|
||||||
@@ -273,6 +292,8 @@ pub fn state_interrupt_system(
|
|||||||
&mut animation_player,
|
&mut animation_player,
|
||||||
&mut animation_transitions,
|
&mut animation_transitions,
|
||||||
&baked_animations,
|
&baked_animations,
|
||||||
|
&attack_scripts,
|
||||||
|
attack_script_assets,
|
||||||
fighter_manifests
|
fighter_manifests
|
||||||
.get(&fighter.manifest)
|
.get(&fighter.manifest)
|
||||||
.expect("Fighter manifest should be valid"),
|
.expect("Fighter manifest should be valid"),
|
||||||
@@ -297,6 +318,7 @@ pub fn state_collision_interrupt_system(
|
|||||||
game_settings: Res<GameSettings>,
|
game_settings: Res<GameSettings>,
|
||||||
baked_animations: Res<Assets<BakedFighterAnimations>>,
|
baked_animations: Res<Assets<BakedFighterAnimations>>,
|
||||||
fighter_manifests: Res<Assets<FighterManifest>>,
|
fighter_manifests: Res<Assets<FighterManifest>>,
|
||||||
|
attack_scripts: Res<Assets<FighterAttackScript>>,
|
||||||
mut commands: Commands,
|
mut commands: Commands,
|
||||||
) {
|
) {
|
||||||
for fighter in &mut query {
|
for fighter in &mut query {
|
||||||
@@ -307,6 +329,7 @@ pub fn state_collision_interrupt_system(
|
|||||||
animations,
|
animations,
|
||||||
animation_player_link,
|
animation_player_link,
|
||||||
fighter,
|
fighter,
|
||||||
|
attack_script_assets,
|
||||||
} = fighter;
|
} = fighter;
|
||||||
let Ok((mut animation_player, mut animation_transitions)) =
|
let Ok((mut animation_player, mut animation_transitions)) =
|
||||||
animation_players.get_mut(animation_player_link.player())
|
animation_players.get_mut(animation_player_link.player())
|
||||||
@@ -320,6 +343,8 @@ pub fn state_collision_interrupt_system(
|
|||||||
&mut animation_player,
|
&mut animation_player,
|
||||||
&mut animation_transitions,
|
&mut animation_transitions,
|
||||||
&baked_animations,
|
&baked_animations,
|
||||||
|
&attack_scripts,
|
||||||
|
&attack_script_assets,
|
||||||
fighter_manifests
|
fighter_manifests
|
||||||
.get(&fighter.manifest)
|
.get(&fighter.manifest)
|
||||||
.expect("Fighter manifest should be valid"),
|
.expect("Fighter manifest should be valid"),
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ impl FighterAnimations {
|
|||||||
pub fn sample_bone(
|
pub fn sample_bone(
|
||||||
&self,
|
&self,
|
||||||
baked_assets: &Assets<BakedFighterAnimations>,
|
baked_assets: &Assets<BakedFighterAnimations>,
|
||||||
frame: FighterAnimationFrame,
|
frame: &FighterAnimationFrame,
|
||||||
bone: &str,
|
bone: &str,
|
||||||
) -> Option<crate::fighter::baked_animation::FixedMat4> {
|
) -> Option<crate::fighter::baked_animation::FixedMat4> {
|
||||||
let baked = baked_assets.get(&self.baked)?;
|
let baked = baked_assets.get(&self.baked)?;
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ pub enum FighterCommands {
|
|||||||
SmashMoveRight,
|
SmashMoveRight,
|
||||||
Jump,
|
Jump,
|
||||||
Shield,
|
Shield,
|
||||||
|
Attack,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Frames of life remaining for each buffered command. Indexed by
|
/// Frames of life remaining for each buffered command. Indexed by
|
||||||
@@ -30,6 +31,7 @@ pub struct FighterCommandLifetimes {
|
|||||||
smash_move_right: u8,
|
smash_move_right: u8,
|
||||||
jump: u8,
|
jump: u8,
|
||||||
shield: u8,
|
shield: u8,
|
||||||
|
attack: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Index<FighterCommands> for FighterCommandLifetimes {
|
impl Index<FighterCommands> for FighterCommandLifetimes {
|
||||||
@@ -41,6 +43,7 @@ impl Index<FighterCommands> for FighterCommandLifetimes {
|
|||||||
FighterCommands::SmashMoveRight => &self.smash_move_right,
|
FighterCommands::SmashMoveRight => &self.smash_move_right,
|
||||||
FighterCommands::Jump => &self.jump,
|
FighterCommands::Jump => &self.jump,
|
||||||
FighterCommands::Shield => &self.shield,
|
FighterCommands::Shield => &self.shield,
|
||||||
|
FighterCommands::Attack => &self.attack,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -52,6 +55,7 @@ impl IndexMut<FighterCommands> for FighterCommandLifetimes {
|
|||||||
FighterCommands::SmashMoveRight => &mut self.smash_move_right,
|
FighterCommands::SmashMoveRight => &mut self.smash_move_right,
|
||||||
FighterCommands::Jump => &mut self.jump,
|
FighterCommands::Jump => &mut self.jump,
|
||||||
FighterCommands::Shield => &mut self.shield,
|
FighterCommands::Shield => &mut self.shield,
|
||||||
|
FighterCommands::Attack => &mut self.attack,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -148,6 +152,13 @@ pub fn postprocess_input(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !input.prev_frame.attack && input.current_frame.attack {
|
||||||
|
input.set_lifetime(
|
||||||
|
FighterCommands::Attack,
|
||||||
|
game_settings.input_common.input_buffer_size,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
if x_abs >= axis_threshold && input.frames_in_smash_move_deadzone <= frame_threshold {
|
if x_abs >= axis_threshold && input.frames_in_smash_move_deadzone <= frame_threshold {
|
||||||
input.clear_command(FighterCommands::SmashMoveLeft);
|
input.clear_command(FighterCommands::SmashMoveLeft);
|
||||||
input.clear_command(FighterCommands::SmashMoveRight);
|
input.clear_command(FighterCommands::SmashMoveRight);
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
use bevy_egui::prelude::*;
|
use bevy_egui::prelude::*;
|
||||||
|
|
||||||
use crate::input::FighterInput;
|
use crate::{fighter::{FighterHitboxes, animation::FighterAnimationFrame, visual::FighterAnimations}, input::FighterInput};
|
||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
|
|
||||||
pub fn input_debug(mut contexts: EguiContexts, query: Query<&FighterInput>) -> Result {
|
pub fn input_debug(mut contexts: EguiContexts, query: Query<&FighterInput>) -> Result {
|
||||||
|
|||||||
@@ -10,4 +10,5 @@ pub struct FighterInputFrame {
|
|||||||
pub directional_attack: FGVec2,
|
pub directional_attack: FGVec2,
|
||||||
pub jump: bool,
|
pub jump: bool,
|
||||||
pub shield: bool,
|
pub shield: bool,
|
||||||
|
pub attack: bool,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ pub fn sample_gamepad(pad: &Gamepad, input_map: &BaseInputMap) -> FighterInputFr
|
|||||||
match gamepad_element.action {
|
match gamepad_element.action {
|
||||||
InputMapAction::Jump => input_frame.jump |= pressed,
|
InputMapAction::Jump => input_frame.jump |= pressed,
|
||||||
InputMapAction::Shield => input_frame.shield |= pressed,
|
InputMapAction::Shield => input_frame.shield |= pressed,
|
||||||
|
InputMapAction::Attack => input_frame.attack |= pressed,
|
||||||
// Digital buttons driving movement isn't used by the
|
// Digital buttons driving movement isn't used by the
|
||||||
// default bindings (the stick covers that), but stay
|
// default bindings (the stick covers that), but stay
|
||||||
// consistent with the keyboard backend if one is added.
|
// consistent with the keyboard backend if one is added.
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ pub fn sample_keyboard(key: &ButtonInput<KeyCode>, input_map: &BaseInputMap) ->
|
|||||||
}
|
}
|
||||||
InputMapAction::Jump => input_frame.jump = action_strength != FGi32::ZERO,
|
InputMapAction::Jump => input_frame.jump = action_strength != FGi32::ZERO,
|
||||||
InputMapAction::Shield => input_frame.shield = action_strength != FGi32::ZERO,
|
InputMapAction::Shield => input_frame.shield = action_strength != FGi32::ZERO,
|
||||||
|
InputMapAction::Attack => input_frame.attack = action_strength != FGi32::ZERO,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ pub enum InputMapAction {
|
|||||||
MovementYDir(i32),
|
MovementYDir(i32),
|
||||||
Jump,
|
Jump,
|
||||||
Shield,
|
Shield,
|
||||||
|
Attack,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
|||||||
@@ -67,6 +67,11 @@ impl Plugin for FighterInputPlugin {
|
|||||||
key: KeyCode::ShiftLeft,
|
key: KeyCode::ShiftLeft,
|
||||||
action: InputMapAction::Shield,
|
action: InputMapAction::Shield,
|
||||||
},
|
},
|
||||||
|
// attack
|
||||||
|
KeyboardInputMapElement {
|
||||||
|
key: KeyCode::KeyJ,
|
||||||
|
action: InputMapAction::Attack,
|
||||||
|
},
|
||||||
],
|
],
|
||||||
gamepad: vec![
|
gamepad: vec![
|
||||||
// left stick
|
// left stick
|
||||||
@@ -92,6 +97,11 @@ impl Plugin for FighterInputPlugin {
|
|||||||
binding: GamepadBinding::Button(GamepadButton::RightTrigger),
|
binding: GamepadBinding::Button(GamepadButton::RightTrigger),
|
||||||
action: InputMapAction::Shield,
|
action: InputMapAction::Shield,
|
||||||
},
|
},
|
||||||
|
// attack
|
||||||
|
GamepadInputMapElement {
|
||||||
|
binding: GamepadBinding::Button(GamepadButton::East),
|
||||||
|
action: InputMapAction::Attack,
|
||||||
|
},
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
.add_plugins(gamecube::GamecubeAdapterPlugin)
|
.add_plugins(gamecube::GamecubeAdapterPlugin)
|
||||||
|
|||||||
+9
-13
@@ -8,7 +8,7 @@ use bevy_ggrs::prelude::Session;
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
AppState, args::Args, fighter::{
|
AppState, args::Args, fighter::{
|
||||||
FighterId, animation::AnimKind, attack::AttackKind, baked_animation::BakedFighterAnimations, manifest::{FighterManifest, FighterManifestRegistry}, spawn_fighter, visual::FighterAnimations,
|
FighterId, animation::AnimKind, attack::{AttackKind, FighterAttackScriptAssets}, baked_animation::BakedFighterAnimations, manifest::{FighterManifest, FighterManifestRegistry}, spawn_fighter, visual::FighterAnimations,
|
||||||
}, math::{int::FGi32, vec::FGVec2}, netcode::{GGRSCfg, session::create_session}, scripting::FighterAttackScript, stage::{
|
}, math::{int::FGi32, vec::FGVec2}, netcode::{GGRSCfg, session::create_session}, scripting::FighterAttackScript, stage::{
|
||||||
self,
|
self,
|
||||||
manifest::{StageId, StageManifest, StageManifestRegistry},
|
manifest::{StageId, StageManifest, StageManifestRegistry},
|
||||||
@@ -163,7 +163,6 @@ pub fn prepare_match(
|
|||||||
}
|
}
|
||||||
|
|
||||||
let mut prepared = Vec::with_capacity(assets.fighters.len());
|
let mut prepared = Vec::with_capacity(assets.fighters.len());
|
||||||
let mut shared_animations = HashMap::<FighterId, FighterAnimations>::new();
|
|
||||||
|
|
||||||
for character in &assets.fighters {
|
for character in &assets.fighters {
|
||||||
let manifest_handle = registry
|
let manifest_handle = registry
|
||||||
@@ -189,15 +188,6 @@ pub fn prepare_match(
|
|||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(animations) = shared_animations.get(&character.fighter) {
|
|
||||||
prepared.push((
|
|
||||||
scene,
|
|
||||||
animations.clone(),
|
|
||||||
manifest_handle,
|
|
||||||
));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut graph = AnimationGraph::new();
|
let mut graph = AnimationGraph::new();
|
||||||
let mut clips = HashMap::<AnimKind, AnimationNodeIndex>::new();
|
let mut clips = HashMap::<AnimKind, AnimationNodeIndex>::new();
|
||||||
|
|
||||||
@@ -235,10 +225,15 @@ pub fn prepare_match(
|
|||||||
clips,
|
clips,
|
||||||
baked: character.baked_animations.clone(),
|
baked: character.baked_animations.clone(),
|
||||||
};
|
};
|
||||||
shared_animations.insert(character.fighter, animations.clone());
|
|
||||||
|
let attack_scripts = FighterAttackScriptAssets {
|
||||||
|
scripts: character.attack_scripts.clone()
|
||||||
|
};
|
||||||
|
|
||||||
prepared.push((
|
prepared.push((
|
||||||
scene,
|
scene,
|
||||||
animations,
|
animations,
|
||||||
|
attack_scripts,
|
||||||
manifest_handle,
|
manifest_handle,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
@@ -272,7 +267,7 @@ pub fn prepare_match(
|
|||||||
|
|
||||||
for (
|
for (
|
||||||
index,
|
index,
|
||||||
(player, (scene, animations, manifest_handle)),
|
(player, (scene, animations, attack_scripts, manifest_handle)),
|
||||||
) in request.players.iter().zip(prepared).enumerate()
|
) in request.players.iter().zip(prepared).enumerate()
|
||||||
{
|
{
|
||||||
let spawn_x = (index as i32 * 2 + 1 - request.players.len() as i32) * 5;
|
let spawn_x = (index as i32 * 2 + 1 - request.players.len() as i32) * 5;
|
||||||
@@ -282,6 +277,7 @@ pub fn prepare_match(
|
|||||||
FGVec2::new(FGi32::from_num(spawn_x), FGi32::lit("12.5")),
|
FGVec2::new(FGi32::from_num(spawn_x), FGi32::lit("12.5")),
|
||||||
manifest_handle.clone(),
|
manifest_handle.clone(),
|
||||||
animations,
|
animations,
|
||||||
|
attack_scripts,
|
||||||
WorldAssetRoot(scene),
|
WorldAssetRoot(scene),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,15 @@ pub struct FGVec3 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl FGVec3 {
|
impl FGVec3 {
|
||||||
|
|
||||||
|
pub fn new(x: FGi32, y: FGi32, z: FGi32) -> Self {
|
||||||
|
Self {
|
||||||
|
x,
|
||||||
|
y,
|
||||||
|
z
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn lit(x: &str, y: &str, z: &str) -> Self {
|
pub fn lit(x: &str, y: &str, z: &str) -> Self {
|
||||||
Self {
|
Self {
|
||||||
x: FGi32::lit(x),
|
x: FGi32::lit(x),
|
||||||
@@ -19,4 +28,8 @@ impl FGVec3 {
|
|||||||
z: FGi32::lit(z),
|
z: FGi32::lit(z),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn to_vec3(&self) -> Vec3 {
|
||||||
|
Vec3::new(self.x.to_num(), self.y.to_num(), self.z.to_num())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user