feat: Proof-of-concept attack combo system

This commit is contained in:
Alexey 2026-04-16 17:06:52 +03:00
commit 95276c070b
15 changed files with 391 additions and 60 deletions

View file

@ -1,25 +1,99 @@
//! Player systems
use crate::timer::TickEvent;
use super::*;
/// Do something based on [PlayerInput]
pub fn handle_input(
time: Res<Time>,
mut commands: Commands,
time: Res<Time>,
player_query: Query<(
Entity,
&Player,
&ActionState<PlayerInput>,
&InputState,
&mut KinematicCharacterController,
&mut Sprite,
Option<&mut AttackGraph>,
Option<&states::Free>,
Option<&states::Choosing>,
Option<&states::Attacking>,
Option<&states::Awaiting>,
)>,
) {
for (player, action_state, mut controller, mut sprite) in player_query {
let direction = action_state.clamped_value(&PlayerInput::Move);
controller.translation = Some(vec2(direction * player.speed * time.delta_secs(), 0.));
if direction != 0. {
sprite.flip_x = direction < 0.;
for (
player_id,
player,
action_state,
mut controller,
mut sprite,
maybe_attack_graph,
maybe_free,
maybe_choosing,
maybe_attacking,
maybe_awaiting,
) in player_query {
if maybe_free.is_some() {
let direction = action_state.clamped_value(&PlayerInput::Move);
controller.translation = Some(vec2(direction * player.speed * time.delta_secs(), 0.));
if direction != 0. {
sprite.flip_x = direction < 0.;
}
} else if let Some(states::Choosing { log }) = maybe_choosing &&
let Some(mut attack_graph) = maybe_attack_graph {
if let Some(next_state) = attack_graph.next(*log) {
let next_attack = match *log {
PlayerInput::LightAttack => {
states::Attacking {
phys: next_state,
beats_remaining: 1,
}
},
PlayerInput::HeavyAttack => {
states::Attacking {
phys: next_state,
beats_remaining: 2,
}
},
_ => unreachable!(),
};
commands.entity(player_id).insert(states::NextAttack(next_attack));
} else {
commands.entity(player_id).insert(Done::Failure);
}
} else if let Some(states::Attacking { phys, beats_remaining }) = maybe_attacking {
println!("{phys:#?}");
if *beats_remaining == 0 {
commands.entity(player_id).insert(Done::Success);
}
} else if let Some(states::Awaiting { beats_remaining, .. }) = maybe_awaiting {
if *beats_remaining == 0 {
commands.entity(player_id).insert(Done::Success);
}
}
}
}
// TODO: change beats_remaining to more accurate counting
/// Observer that updates temporal states on timer tick
pub fn on_timer_tick(
_: On<TickEvent>,
player_query: Query<(
Option<&mut states::Attacking>,
Option<&mut states::Awaiting>,
), With<Player>>
) {
for (maybe_attacking, maybe_awaiting) in player_query {
if let Some(mut attacking) = maybe_attacking {
info!("attack tick");
attacking.beats_remaining -= 1;
} else if let Some(mut awaiting) = maybe_awaiting {
info!("await tick");
awaiting.beats_remaining -= 1;
}
}
}