From 32f88275885afafe8a0a2389b3aa0af7eb5af18c Mon Sep 17 00:00:00 2001 From: mnmaita <47983254+mnmaita@users.noreply.github.com> Date: Fri, 13 Dec 2024 14:34:07 +0100 Subject: [PATCH 01/20] Adds SwapWeapon to PlayerAction --- game/src/game/player/mod.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/game/src/game/player/mod.rs b/game/src/game/player/mod.rs index 19feea6..59cef80 100644 --- a/game/src/game/player/mod.rs +++ b/game/src/game/player/mod.rs @@ -121,6 +121,7 @@ pub enum PlayerAction { Dash, Whirl, Stealth, + SwapWeapon, } #[derive(Component, Debug, Deref, DerefMut)] @@ -326,7 +327,8 @@ fn setup_player( .with(PlayerAction::Attack, KeyCode::KeyJ) .with(PlayerAction::Dash, KeyCode::KeyK) .with(PlayerAction::Whirl, KeyCode::KeyL) - .with(PlayerAction::Stealth, KeyCode::KeyI), + .with(PlayerAction::Stealth, KeyCode::KeyI) + .with(PlayerAction::SwapWeapon, KeyCode::KeyH), }, // bundling things up becuase we reached max tuple ( From 870e74beeb810c4c1ba4fe154bf5eaac455add8a Mon Sep 17 00:00:00 2001 From: mnmaita <47983254+mnmaita@users.noreply.github.com> Date: Fri, 13 Dec 2024 15:02:32 +0100 Subject: [PATCH 02/20] Adds PlayerWeaponPlugin --- game/src/game/player/mod.rs | 3 +++ game/src/game/player/player_weapon.rs | 36 +++++++++++++++++++++++++++ 2 files changed, 39 insertions(+) create mode 100644 game/src/game/player/player_weapon.rs diff --git a/game/src/game/player/mod.rs b/game/src/game/player/mod.rs index 59cef80..d7ec403 100644 --- a/game/src/game/player/mod.rs +++ b/game/src/game/player/mod.rs @@ -1,5 +1,6 @@ mod player_anim; mod player_behaviour; +mod player_weapon; use bevy::utils::hashbrown::HashMap; use leafwing_input_manager::action_state::ActionState; use leafwing_input_manager::axislike::VirtualAxis; @@ -7,6 +8,7 @@ use leafwing_input_manager::input_map::InputMap; use leafwing_input_manager::{Actionlike, InputManagerBundle}; use player_anim::PlayerAnimationPlugin; use player_behaviour::PlayerBehaviorPlugin; +use player_weapon::PlayerWeaponPlugin; use rapier2d::geometry::{Group, InteractionGroups}; use strum::IntoEnumIterator; use strum_macros::EnumIter; @@ -59,6 +61,7 @@ impl Plugin for PlayerPlugin { PlayerBehaviorPlugin, PlayerTransitionPlugin, PlayerAnimationPlugin, + PlayerWeaponPlugin, )); #[cfg(feature = "dev")] diff --git a/game/src/game/player/player_weapon.rs b/game/src/game/player/player_weapon.rs new file mode 100644 index 0000000..2c5effd --- /dev/null +++ b/game/src/game/player/player_weapon.rs @@ -0,0 +1,36 @@ +use leafwing_input_manager::prelude::ActionState; + +use crate::game::player::{Player, PlayerAction}; +use crate::prelude::{ + App, GameTickUpdate, Plugin, Query, ResMut, Resource, With, +}; + +pub(crate) struct PlayerWeaponPlugin; + +impl Plugin for PlayerWeaponPlugin { + fn build(&self, app: &mut App) { + app.insert_resource(PlayerWeapon::default()); + app.add_systems(GameTickUpdate, swap_weapon); + } +} + +#[derive(Resource, Default, PartialEq, Eq)] +pub enum PlayerWeapon { + Bow, + #[default] + Sword, +} + +fn swap_weapon( + mut weapon: ResMut, + query: Query<&ActionState, With>, +) { + for action_state in &query { + if action_state.just_pressed(&PlayerAction::SwapWeapon) { + *weapon = match *weapon { + PlayerWeapon::Bow => PlayerWeapon::Sword, + PlayerWeapon::Sword => PlayerWeapon::Bow, + }; + } + } +} From d5a9d6543269712418191d1bc1713fd8804f0963 Mon Sep 17 00:00:00 2001 From: mnmaita <47983254+mnmaita@users.noreply.github.com> Date: Fri, 13 Dec 2024 15:03:59 +0100 Subject: [PATCH 03/20] Fixes typos in game/player/mod.rs --- game/src/game/player/mod.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/game/src/game/player/mod.rs b/game/src/game/player/mod.rs index d7ec403..5db6a7c 100644 --- a/game/src/game/player/mod.rs +++ b/game/src/game/player/mod.rs @@ -333,7 +333,7 @@ fn setup_player( .with(PlayerAction::Stealth, KeyCode::KeyI) .with(PlayerAction::SwapWeapon, KeyCode::KeyH), }, - // bundling things up becuase we reached max tuple + // bundling things up because we reached max tuple ( Falling, CanDash { @@ -628,7 +628,7 @@ pub struct PlayerConfig { /// How many seconds does our characters innate hover boots work? max_coyote_time: f32, - /// Onlly applies in the downward y direction while the player is falling + /// Only applies in the downward y direction while the player is falling /// and trying to walk into the wall sliding_friction: f32, @@ -784,7 +784,7 @@ pub struct StatusModifier { /// Multiplying Factor on Stat, e.g. 102.0 * 0.5 = 51.0 scalar: Vec, - /// Offseting Value on Stat, e.g. 100.0 - 10.0 = 90.0 + /// Offsetting Value on Stat, e.g. 100.0 - 10.0 = 90.0 delta: Vec, effect_col: Color, From 189f58015951b89316b3c0731003c0cb5ee17c25 Mon Sep 17 00:00:00 2001 From: mnmaita <47983254+mnmaita@users.noreply.github.com> Date: Sun, 15 Dec 2024 12:11:30 +0100 Subject: [PATCH 04/20] Adds bow animations to player --- game/src/game/player/player_anim.rs | 34 ++++++++++++++------------- game/src/game/player/player_weapon.rs | 10 +++++++- 2 files changed, 27 insertions(+), 17 deletions(-) diff --git a/game/src/game/player/player_anim.rs b/game/src/game/player/player_anim.rs index 36fba08..5a061c7 100644 --- a/game/src/game/player/player_anim.rs +++ b/game/src/game/player/player_anim.rs @@ -16,6 +16,8 @@ use crate::prelude::{ Res, With, Without, }; +use super::player_weapon::PlayerWeapon; + /// play animations here, run after transitions pub struct PlayerAnimationPlugin; @@ -152,10 +154,11 @@ fn player_attacking_animation( Option<&HitFreezeTime>, Ref, ), - (Without), + Without, >, mut gfx_query: Query<&mut ScriptPlayer, With>, config: Res, + weapon: Res, ) { for (gent, is_falling, is_jumping, is_running, hitfrozen, attacking) in query.iter() @@ -166,31 +169,29 @@ fn player_attacking_animation( .unwrap_or(false); // let current = player.current_key().unwrap_or("").clone(); player.set_slot("AttackTransition", false); + let basic_air_anim_key_str = &weapon.get_anim_key("BasicAir"); + let basic_run_anim_key_str = &weapon.get_anim_key("BasicRun"); + let basic_idle_anim_key_str = &weapon.get_anim_key("BasicIdle"); + if is_falling || is_jumping { // TODO: These need a way to resume the new animation from the current frame index // or specified offset - if player.current_key().unwrap_or("") - != "anim.player.SwordBasicAir" - { - player.play_key("anim.player.SwordBasicAir"); + if player.current_key() != Some(basic_air_anim_key_str) { + player.play_key(basic_air_anim_key_str); if !attacking.is_added() { player.set_slot("AttackTransition", true); } } } else if is_running && !hitfrozen { - if player.current_key().unwrap_or("") - != "anim.player.SwordBasicRun" - { - player.play_key("anim.player.SwordBasicRun"); + if player.current_key() != Some(basic_run_anim_key_str) { + player.play_key(basic_run_anim_key_str); if !attacking.is_added() { player.set_slot("AttackTransition", true); } } } else { - if player.current_key().unwrap_or("") - != "anim.player.SwordBasicIdle" - { - player.play_key("anim.player.SwordBasicIdle"); + if player.current_key() != Some(basic_idle_anim_key_str) { + player.play_key(basic_idle_anim_key_str); if !attacking.is_added() { player.set_slot("AttackTransition", true); } @@ -228,6 +229,7 @@ fn sprite_flip( mut current_direction: Local, mut old_direction: Local, time: Res, + weapon: Res, ) { for (facing, gent, wall_slide_time) in query.iter() { if let Ok(mut player) = gfx_query.get_mut(gent.e_gfx) { @@ -241,9 +243,9 @@ fn sprite_flip( // (ie: not wall_jump_coyote_time) .map(|s| s.0 <= 1.0 / time.hz as f32) .unwrap_or(false); - if pressed_on_wall - && player.current_key() == Some("anim.player.SwordBasicAir") - { + let is_attacking_while_falling = + player.current_key() == Some(&weapon.get_anim_key("BasicAir")); + if pressed_on_wall && is_attacking_while_falling { facing = match facing { Facing::Right => Facing::Left, Facing::Left => Facing::Right, diff --git a/game/src/game/player/player_weapon.rs b/game/src/game/player/player_weapon.rs index 2c5effd..f239b50 100644 --- a/game/src/game/player/player_weapon.rs +++ b/game/src/game/player/player_weapon.rs @@ -1,4 +1,5 @@ use leafwing_input_manager::prelude::ActionState; +use strum_macros::Display; use crate::game::player::{Player, PlayerAction}; use crate::prelude::{ @@ -14,13 +15,20 @@ impl Plugin for PlayerWeaponPlugin { } } -#[derive(Resource, Default, PartialEq, Eq)] +#[derive(Resource, Default, PartialEq, Eq, Display)] pub enum PlayerWeapon { Bow, #[default] Sword, } +impl PlayerWeapon { + pub fn get_anim_key(&self, action: &str) -> String { + let weapon_str = self.to_string(); + format!("anim.player.{weapon_str}{action}") + } +} + fn swap_weapon( mut weapon: ResMut, query: Query<&ActionState, With>, From d51285dde557e3783b4147a747d1ff6d2c2d961b Mon Sep 17 00:00:00 2001 From: mnmaita <47983254+mnmaita@users.noreply.github.com> Date: Wed, 18 Dec 2024 17:03:43 +0100 Subject: [PATCH 05/20] Adds arrow_velocity to PlayerConfig --- assets/player.cfg.toml | 3 +++ game/src/game/player/mod.rs | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/assets/player.cfg.toml b/assets/player.cfg.toml index ad92637..f2632f3 100644 --- a/assets/player.cfg.toml +++ b/assets/player.cfg.toml @@ -86,3 +86,6 @@ melee_pushback_ticks = 12.0 # Number of kills to trigger passive gain passive_gain_rate = 3.0 + +# Velocity of the projectiles fired by the Bow weapon +arrow_velocity = 1000.0 diff --git a/game/src/game/player/mod.rs b/game/src/game/player/mod.rs index 5db6a7c..430aa4a 100644 --- a/game/src/game/player/mod.rs +++ b/game/src/game/player/mod.rs @@ -679,6 +679,9 @@ pub struct PlayerConfig { /// Ticks for melee knockback velocity; determines how long movement is locked for melee_pushback_ticks: u32, + /// Velocity of the projectiles fired by the Bow weapon + arrow_velocity: f32, + /// How many kills to trigger a passive gain passive_gain_rate: u32, } @@ -752,6 +755,7 @@ fn update_player_config(config: &mut PlayerConfig, cfg: &DynamicConfig) { update_field(&mut errors, &cfg.0, "melee_pushback", |val| config.melee_pushback = val); update_field(&mut errors, &cfg.0, "melee_pushback_ticks", |val| config.melee_pushback_ticks = val as u32); update_field(&mut errors, &cfg.0, "passive_gain_rate", |val| config.passive_gain_rate = val as u32); + update_field(&mut errors, &cfg.0, "arrow_velocity", |val| config.arrow_velocity = val); for error in errors{ warn!("failed to load player cfg value: {}", error); From 23053e8ef17ffdf8c9f52b58f7bb5742cb8349d6 Mon Sep 17 00:00:00 2001 From: mnmaita <47983254+mnmaita@users.noreply.github.com> Date: Wed, 18 Dec 2024 17:05:44 +0100 Subject: [PATCH 06/20] Adds Attack::with_max_targets --- game/src/game/attack/mod.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/game/src/game/attack/mod.rs b/game/src/game/attack/mod.rs index 1f7b003..76dcc99 100644 --- a/game/src/game/attack/mod.rs +++ b/game/src/game/attack/mod.rs @@ -135,6 +135,11 @@ impl Attack { self.status_mod = Some(modif); self } + + pub fn with_max_targets(mut self, max_targets: u32) -> Self { + self.max_targets = max_targets; + self + } } /// Event sent when damage is applied From b9e9cee55333b84166cee3fe88567b1f9a74a63d Mon Sep 17 00:00:00 2001 From: mnmaita <47983254+mnmaita@users.noreply.github.com> Date: Wed, 18 Dec 2024 17:08:02 +0100 Subject: [PATCH 07/20] Adds Bow attacks to player_attack --- game/src/game/player/player_behaviour.rs | 109 ++++++++++++++++------- 1 file changed, 79 insertions(+), 30 deletions(-) diff --git a/game/src/game/player/player_behaviour.rs b/game/src/game/player/player_behaviour.rs index f90d38b..7c59fad 100644 --- a/game/src/game/player/player_behaviour.rs +++ b/game/src/game/player/player_behaviour.rs @@ -1,4 +1,4 @@ -use bevy::sprite::Sprite; +use bevy::sprite::{Sprite, SpriteSheetBundle}; use bevy::transform::TransformSystem::TransformPropagate; use glam::{Vec2, Vec2Swizzles, Vec3Swizzles}; use leafwing_input_manager::action_state::ActionState; @@ -13,6 +13,8 @@ use theseeker_engine::physics::{ }; use theseeker_engine::script::ScriptPlayer; +use super::arc_attack::Projectile; +use super::player_weapon::PlayerWeapon; use super::{ dash_icon_fx, player_dash_fx, player_new_stats_mod, AttackBundle, CanStealth, DashIcon, JumpCount, KillCount, Knockback, Passives, @@ -33,6 +35,7 @@ use crate::prelude::{ IntoSystemConfigs, Plugin, Query, Res, Transform, TransformBundle, With, Without, }; +use crate::StateDespawnMarker; /// Player behavior systems. /// Do stuff here in states and add transitions to other states by pushing @@ -976,6 +979,7 @@ fn player_attack( Entity, &Gent, &Facing, + &Transform, &mut Attacking, &mut TransitionQueue, &ActionState, @@ -985,11 +989,13 @@ fn player_attack( >, mut commands: Commands, config: Res, + weapon: Res, ) { for ( entity, gent, facing, + transform, mut attacking, mut transitions, action_state, @@ -997,35 +1003,78 @@ fn player_attack( ) in query.iter_mut() { if attacking.ticks == 0 { - let attack = commands - .spawn(( - TransformBundle::from_transform(Transform::from_xyz( - 0.0, 0.0, 0.0, - )), - AnimationCollider(gent.e_gfx), - // TODO: ? ColliderMeta - Collider::empty(InteractionGroups::new( - PLAYER_ATTACK, - ENEMY_HURT, - )), - Attack::new(16, entity), - SelfPushback(Knockback::new( - Vec2::new( - config.melee_self_pushback * -facing.direction(), - 0., - ), - config.melee_self_pushback_ticks, - )), - Pushback(Knockback::new( - Vec2::new( - facing.direction() * config.melee_pushback, - 0., - ), - config.melee_pushback_ticks, - )), - )) - .set_parent(entity) - .id(); + let attack = match *weapon { + PlayerWeapon::Bow => { + let mut animation: ScriptPlayer = + ScriptPlayer::default(); + animation.play_key("anim.player.BowBasicArrow"); + animation.set_slot("Start", true); + + let vel = LinearVelocity( + Vec2::X * facing.direction() * config.arrow_velocity, + ); + + commands + .spawn(( + SpriteSheetBundle { + transform: *transform, + ..Default::default() + }, + Projectile { vel }, + Collider::cuboid( + 12.0, + 12.0, + InteractionGroups::new( + PLAYER_ATTACK, + ENEMY_HURT | GROUND, + ), + ), + Attack::new(16, entity).with_max_targets(1), + Pushback(Knockback::new( + Vec2::new( + facing.direction() * config.melee_pushback, + 0., + ), + config.melee_pushback_ticks, + )), + animation, + StateDespawnMarker, + )) + .id() + }, + PlayerWeapon::Sword => { + commands + .spawn(( + TransformBundle::from_transform( + Transform::from_xyz(0.0, 0.0, 0.0), + ), + AnimationCollider(gent.e_gfx), + // TODO: ? ColliderMeta + Collider::empty(InteractionGroups::new( + PLAYER_ATTACK, + ENEMY_HURT, + )), + Attack::new(16, entity), + SelfPushback(Knockback::new( + Vec2::new( + config.melee_self_pushback + * -facing.direction(), + 0., + ), + config.melee_self_pushback_ticks, + )), + Pushback(Knockback::new( + Vec2::new( + facing.direction() * config.melee_pushback, + 0., + ), + config.melee_pushback_ticks, + )), + )) + .set_parent(entity) + .id() + }, + }; if stealthed { commands.entity(attack).insert(Stealthed); From 204ed3df53b12be8e5e82685af26841ac7a63b60 Mon Sep 17 00:00:00 2001 From: mnmaita <47983254+mnmaita@users.noreply.github.com> Date: Wed, 18 Dec 2024 17:13:17 +0100 Subject: [PATCH 08/20] Fixes typos in comments --- assets/player.cfg.toml | 2 +- engine/src/physics.rs | 2 +- game/src/game/attack/mod.rs | 2 +- game/src/game/enemy.rs | 14 ++++++-------- game/src/game/player/player_behaviour.rs | 4 ++-- 5 files changed, 11 insertions(+), 13 deletions(-) diff --git a/assets/player.cfg.toml b/assets/player.cfg.toml index f2632f3..ccd8465 100644 --- a/assets/player.cfg.toml +++ b/assets/player.cfg.toml @@ -33,7 +33,7 @@ fall_accel = 4.5 # How many seconds does our characters innate hover boots work? max_coyote_time = 0.1 -# Onlly applies in the downward y direction while the player is falling +# Only applies in the downward y direction while the player is falling # and trying to walk into the wall sliding_friction = 0.25 diff --git a/engine/src/physics.rs b/engine/src/physics.rs index 0a7c150..3179a95 100644 --- a/engine/src/physics.rs +++ b/engine/src/physics.rs @@ -395,7 +395,7 @@ fn init_physics_world(mut world: ResMut) { /// /// Make sure if you are reading from this in a system, you run after this finishes /// -/// TODO make sure this always runs after the GameTickUpdate; consider creating a seperate +/// TODO make sure this always runs after the GameTickUpdate; consider creating a separate /// [`ScheduleLabel`] for immediately after transform propagation pub fn update_query_pipeline( // Mutable reference because collider data is stored in an Arena that pipeline modifies diff --git a/game/src/game/attack/mod.rs b/game/src/game/attack/mod.rs index 76dcc99..f319863 100644 --- a/game/src/game/attack/mod.rs +++ b/game/src/game/attack/mod.rs @@ -38,7 +38,7 @@ impl Plugin for AttackPlugin { ( determine_attack_targets, apply_attack_modifications, - // DamageInfo event emited here + // DamageInfo event emitted here apply_attack_damage, // OnAttackFirstHitSet track_crits, diff --git a/game/src/game/enemy.rs b/game/src/game/enemy.rs index 2781d2d..fc34d4b 100644 --- a/game/src/game/enemy.rs +++ b/game/src/game/enemy.rs @@ -228,7 +228,7 @@ fn setup_enemy( if !bp.is_added() { continue; } - // TODO: ensure propper z order + // TODO: ensure proper z order xf_gent.translation.z = 14.0 * 0.000001; xf_gent.translation.y += 2.0; // Sprite offset so it looks like it is standing on the ground let e_gfx = commands.spawn(()).id(); @@ -547,7 +547,7 @@ struct Decay; // Check how far the player is, set our range, set our target if applicable, turn to face player if // in range -// TODO: check x and y distance independantly? +// TODO: check x and y distance independently? fn check_player_range( mut query: Query< ( @@ -795,11 +795,9 @@ fn aggro( transitions.push(Aggroed::new_transition(Patrolling)); } else if matches!(range, Range::Melee) { match role { - Role::Melee => { - transitions.push(Waiting::new_transition( - MeleeAttack::default(), - )) - }, + Role::Melee => transitions.push(Waiting::new_transition( + MeleeAttack::default(), + )), Role::Ranged => { velocity.x = 0.; transitions.push(Waiting::new_transition( @@ -865,7 +863,7 @@ fn ranged_attack( )); add_q.add(Idle); } - // if player isnt alive, do nothing, we will transiton back once animation finishes + // if player isnt alive, do nothing, we will transition back once animation finishes let Ok(transform) = player_query.get(attack.target) else { continue; }; diff --git a/game/src/game/player/player_behaviour.rs b/game/src/game/player/player_behaviour.rs index 7c59fad..4cf6ab2 100644 --- a/game/src/game/player/player_behaviour.rs +++ b/game/src/game/player/player_behaviour.rs @@ -581,7 +581,7 @@ pub fn player_collisions( if dashing.is_none() && whirling.is_none() { let sliding_plane = into_vec2(first_hit.normal1); - // configurable theshold for collision normal/sliding plane in case of physics instability + // configurable threshold for collision normal/sliding plane in case of physics instability let threshold = 0.000001; if !(1. - threshold..=1. + threshold) .contains(&sliding_plane.y) @@ -634,7 +634,7 @@ pub fn player_collisions( let friction_force = if projected_velocity.y < -0.0 { // make sure at least 1/2 of player is against the wall - // (because it looks wierd to have the character hanging by their head) + // (because it looks weird to have the character hanging by their head) if spatial_query .ray_cast( pos.translation.xy(), From 9ab5c5346ecf82d7112a5416736b2563f38269aa Mon Sep 17 00:00:00 2001 From: mnmaita <47983254+mnmaita@users.noreply.github.com> Date: Thu, 19 Dec 2024 14:54:21 +0100 Subject: [PATCH 09/20] Adjusts arrow collider size --- game/src/game/player/player_behaviour.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/game/src/game/player/player_behaviour.rs b/game/src/game/player/player_behaviour.rs index 4cf6ab2..b5f0417 100644 --- a/game/src/game/player/player_behaviour.rs +++ b/game/src/game/player/player_behaviour.rs @@ -1023,7 +1023,7 @@ fn player_attack( Projectile { vel }, Collider::cuboid( 12.0, - 12.0, + 3.0, InteractionGroups::new( PLAYER_ATTACK, ENEMY_HURT | GROUND, From 93f18089e96e95c128c88638d8957cd0e6e291a1 Mon Sep 17 00:00:00 2001 From: mnmaita <47983254+mnmaita@users.noreply.github.com> Date: Thu, 19 Dec 2024 15:05:12 +0100 Subject: [PATCH 10/20] Sets arrow attack lifetime to 192 --- game/src/game/player/player_behaviour.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/game/src/game/player/player_behaviour.rs b/game/src/game/player/player_behaviour.rs index b5f0417..ca4e519 100644 --- a/game/src/game/player/player_behaviour.rs +++ b/game/src/game/player/player_behaviour.rs @@ -1029,7 +1029,7 @@ fn player_attack( ENEMY_HURT | GROUND, ), ), - Attack::new(16, entity).with_max_targets(1), + Attack::new(192, entity).with_max_targets(1), Pushback(Knockback::new( Vec2::new( facing.direction() * config.melee_pushback, From aecec13c340d5a04c872b2cd7a5a491f655d7610 Mon Sep 17 00:00:00 2001 From: mnmaita <47983254+mnmaita@users.noreply.github.com> Date: Thu, 19 Dec 2024 15:11:53 +0100 Subject: [PATCH 11/20] Runs swap_weapon on Update schedule --- game/src/game/player/player_weapon.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/game/src/game/player/player_weapon.rs b/game/src/game/player/player_weapon.rs index f239b50..f5cc605 100644 --- a/game/src/game/player/player_weapon.rs +++ b/game/src/game/player/player_weapon.rs @@ -1,17 +1,16 @@ +use bevy::app::Update; use leafwing_input_manager::prelude::ActionState; use strum_macros::Display; use crate::game::player::{Player, PlayerAction}; -use crate::prelude::{ - App, GameTickUpdate, Plugin, Query, ResMut, Resource, With, -}; +use crate::prelude::{App, Plugin, Query, ResMut, Resource, With}; pub(crate) struct PlayerWeaponPlugin; impl Plugin for PlayerWeaponPlugin { fn build(&self, app: &mut App) { app.insert_resource(PlayerWeapon::default()); - app.add_systems(GameTickUpdate, swap_weapon); + app.add_systems(Update, swap_weapon); } } From 1f13e4e96034eb069dbaefdf8988db2b72ee4af0 Mon Sep 17 00:00:00 2001 From: mnmaita <47983254+mnmaita@users.noreply.github.com> Date: Thu, 19 Dec 2024 16:32:05 +0100 Subject: [PATCH 12/20] Adds WallSlideTime::is_pressed_against_wall --- game/src/game/player/mod.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/game/src/game/player/mod.rs b/game/src/game/player/mod.rs index 430aa4a..a22f81a 100644 --- a/game/src/game/player/mod.rs +++ b/game/src/game/player/mod.rs @@ -578,6 +578,13 @@ impl WallSlideTime { fn strict_sliding(&self, cfg: &PlayerConfig) -> bool { self.0 <= cfg.max_coyote_time * 1.0 } + + /// Checks that player is actually against the wall, rather then it being close + /// enough time from the player having left the wall to still jump + /// (ie: not wall_jump_coyote_time) + fn is_pressed_against_wall(&self, time: &Res) -> bool { + self.0 <= 1.0 / time.hz as f32 + } } /// Tracks the cooldown for the available energy for the players whirl From 854c1fc23e1d86cb37e87cf38eda4d7ff5075c12 Mon Sep 17 00:00:00 2001 From: mnmaita <47983254+mnmaita@users.noreply.github.com> Date: Thu, 19 Dec 2024 16:33:08 +0100 Subject: [PATCH 13/20] Implements WallSlideTime::is_pressed_against_wall in sprite_flip --- game/src/game/player/player_anim.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/game/src/game/player/player_anim.rs b/game/src/game/player/player_anim.rs index 5a061c7..1aa827e 100644 --- a/game/src/game/player/player_anim.rs +++ b/game/src/game/player/player_anim.rs @@ -238,11 +238,7 @@ fn sprite_flip( // Have the player face away from the wall if they are attacking while wall sliding let pressed_on_wall = wall_slide_time - // checks that player is actually against the wall, rather then it being close - // enough time from the player having left the wall to still jump - // (ie: not wall_jump_coyote_time) - .map(|s| s.0 <= 1.0 / time.hz as f32) - .unwrap_or(false); + .is_some_and(|s| s.is_pressed_against_wall(&time)); let is_attacking_while_falling = player.current_key() == Some(&weapon.get_anim_key("BasicAir")); if pressed_on_wall && is_attacking_while_falling { From cbd2f1981f28d909f27807ddb65c74c93e3e199c Mon Sep 17 00:00:00 2001 From: mnmaita <47983254+mnmaita@users.noreply.github.com> Date: Thu, 19 Dec 2024 16:33:28 +0100 Subject: [PATCH 14/20] Fixes arrow direction when pressed against walls --- game/src/game/player/player_behaviour.rs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/game/src/game/player/player_behaviour.rs b/game/src/game/player/player_behaviour.rs index ca4e519..276f7cc 100644 --- a/game/src/game/player/player_behaviour.rs +++ b/game/src/game/player/player_behaviour.rs @@ -980,6 +980,7 @@ fn player_attack( &Gent, &Facing, &Transform, + Option<&WallSlideTime>, &mut Attacking, &mut TransitionQueue, &ActionState, @@ -990,12 +991,14 @@ fn player_attack( mut commands: Commands, config: Res, weapon: Res, + time: Res, ) { for ( entity, gent, facing, transform, + wall_slide_time, mut attacking, mut transitions, action_state, @@ -1010,8 +1013,15 @@ fn player_attack( animation.play_key("anim.player.BowBasicArrow"); animation.set_slot("Start", true); + let is_player_pressed_against_wall = wall_slide_time + .is_some_and(|s| s.is_pressed_against_wall(&time)); + let arrow_direction = if is_player_pressed_against_wall { + -facing.direction() + } else { + facing.direction() + }; let vel = LinearVelocity( - Vec2::X * facing.direction() * config.arrow_velocity, + Vec2::X * arrow_direction * config.arrow_velocity, ); commands From 59b714a263d4683b665ff4d2fc95564154f421db Mon Sep 17 00:00:00 2001 From: mnmaita <47983254+mnmaita@users.noreply.github.com> Date: Thu, 19 Dec 2024 22:12:56 +0100 Subject: [PATCH 15/20] Removes gravity from Player arrows --- game/src/game/attack/arc_attack.rs | 13 ++++++++++--- game/src/game/player/player_behaviour.rs | 3 ++- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/game/src/game/attack/arc_attack.rs b/game/src/game/attack/arc_attack.rs index eaf5ee7..6cc1199 100644 --- a/game/src/game/attack/arc_attack.rs +++ b/game/src/game/attack/arc_attack.rs @@ -45,13 +45,18 @@ impl Projectile { } } +/// Marker that identifies arrows shot by the Player. +#[derive(Component)] +pub struct Arrow; + /// Applies gravity to the projectile +/// It will not add gravity to Arrows shot by the Player. pub fn arc_projectile( mut query: Query< ( &mut Transform, - &Collider, &mut Projectile, + Has, ), With, >, @@ -59,8 +64,10 @@ pub fn arc_projectile( time: Res, ) { let fall_accel = config.fall_accel; - for (mut transform, collider, mut projectile) in query.iter_mut() { - projectile.vel.0.y -= fall_accel; + for (mut transform, mut projectile, arrow) in query.iter_mut() { + if !arrow { + projectile.vel.0.y -= fall_accel; + } let z = transform.translation.z; transform.translation = (transform.translation.xy() + *projectile.vel * (1.0 / time.hz as f32)) diff --git a/game/src/game/player/player_behaviour.rs b/game/src/game/player/player_behaviour.rs index 276f7cc..c41dee9 100644 --- a/game/src/game/player/player_behaviour.rs +++ b/game/src/game/player/player_behaviour.rs @@ -13,7 +13,7 @@ use theseeker_engine::physics::{ }; use theseeker_engine::script::ScriptPlayer; -use super::arc_attack::Projectile; +use super::arc_attack::{Arrow, Projectile}; use super::player_weapon::PlayerWeapon; use super::{ dash_icon_fx, player_dash_fx, player_new_stats_mod, AttackBundle, @@ -1026,6 +1026,7 @@ fn player_attack( commands .spawn(( + Arrow, SpriteSheetBundle { transform: *transform, ..Default::default() From ae023fbf06edf58d179c5c5d08afffcb9ee95716 Mon Sep 17 00:00:00 2001 From: mnmaita <47983254+mnmaita@users.noreply.github.com> Date: Sat, 21 Dec 2024 12:24:57 +0100 Subject: [PATCH 16/20] Adds Facing::invert --- game/src/game/gentstate.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/game/src/game/gentstate.rs b/game/src/game/gentstate.rs index d172ead..0de531a 100644 --- a/game/src/game/gentstate.rs +++ b/game/src/game/gentstate.rs @@ -81,6 +81,14 @@ impl Facing { Facing::Left => -1., } } + + /// Returns the opposite of a given [`Facing`] variant. + pub fn invert(&self) -> Self { + match self { + Facing::Right => Facing::Left, + Facing::Left => Facing::Right, + } + } } /// States From bede5e365d939dcbea89b1f5548d9a8614285ed4 Mon Sep 17 00:00:00 2001 From: mnmaita <47983254+mnmaita@users.noreply.github.com> Date: Sat, 21 Dec 2024 12:25:14 +0100 Subject: [PATCH 17/20] Fixes comment typo --- game/src/game/gentstate.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/game/src/game/gentstate.rs b/game/src/game/gentstate.rs index 0de531a..4e78a45 100644 --- a/game/src/game/gentstate.rs +++ b/game/src/game/gentstate.rs @@ -100,7 +100,7 @@ impl Facing { pub trait GentState: Component {} /// A GenericState has a blanket Transitionable impl for any GentState, -/// it will remove itsself on transition +/// it will remove itself on transition pub trait GenericState: Component {} impl Transitionable for N { From 42dbb0f9aa006813a7922c9d405041088d47d8dc Mon Sep 17 00:00:00 2001 From: mnmaita <47983254+mnmaita@users.noreply.github.com> Date: Sat, 21 Dec 2024 12:26:17 +0100 Subject: [PATCH 18/20] Adds is_player_using_bow run condition --- game/src/game/player/player_weapon.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/game/src/game/player/player_weapon.rs b/game/src/game/player/player_weapon.rs index f5cc605..4a9369c 100644 --- a/game/src/game/player/player_weapon.rs +++ b/game/src/game/player/player_weapon.rs @@ -1,4 +1,5 @@ use bevy::app::Update; +use bevy::prelude::Res; use leafwing_input_manager::prelude::ActionState; use strum_macros::Display; @@ -41,3 +42,8 @@ fn swap_weapon( } } } + +/// Run condition that checks if the Player is using the Bow +pub fn is_player_using_bow(weapon: Res) -> bool { + weapon.eq(&PlayerWeapon::Bow) +} From 6ac0cc81d4a380593925a0d0646b5055e0e8d441 Mon Sep 17 00:00:00 2001 From: mnmaita <47983254+mnmaita@users.noreply.github.com> Date: Sat, 21 Dec 2024 12:26:53 +0100 Subject: [PATCH 19/20] Adds auto-aim feature for the Bow --- game/src/game/player/player_behaviour.rs | 47 +++++++++++++++++++++++- 1 file changed, 45 insertions(+), 2 deletions(-) diff --git a/game/src/game/player/player_behaviour.rs b/game/src/game/player/player_behaviour.rs index c41dee9..c32e4e7 100644 --- a/game/src/game/player/player_behaviour.rs +++ b/game/src/game/player/player_behaviour.rs @@ -8,13 +8,13 @@ use theseeker_engine::assets::animation::SpriteAnimation; use theseeker_engine::gent::Gent; use theseeker_engine::physics::{ into_vec2, update_sprite_colliders, AnimationCollider, Collider, - LinearVelocity, PhysicsWorld, ShapeCaster, ENEMY_HURT, ENEMY_INSIDE, + LinearVelocity, PhysicsWorld, ShapeCaster, ENEMY, ENEMY_HURT, ENEMY_INSIDE, GROUND, PLAYER, PLAYER_ATTACK, }; use theseeker_engine::script::ScriptPlayer; use super::arc_attack::{Arrow, Projectile}; -use super::player_weapon::PlayerWeapon; +use super::player_weapon::{is_player_using_bow, PlayerWeapon}; use super::{ dash_icon_fx, player_dash_fx, player_new_stats_mod, AttackBundle, CanStealth, DashIcon, JumpCount, KillCount, Knockback, Passives, @@ -78,6 +78,9 @@ impl Plugin for PlayerBehaviorPlugin { player_sliding .before(player_jump) .run_if(any_with_component::), + bow_auto_aim + .before(player_attack) + .run_if(is_player_using_bow), ) .in_set(PlayerStateSet::Behavior) .before(update_sprite_colliders), @@ -1212,3 +1215,43 @@ pub fn player_whirl( } } } + +pub fn bow_auto_aim( + mut q_gent: Query<(&mut Facing, &Transform), (With, With)>, + q_enemy: Query>, + spatial_query: Res, +) { + for (mut facing, transform) in q_gent.iter_mut() { + let is_facing_enemies = spatial_query + .ray_cast( + transform.translation.xy(), + Vec2::X * facing.direction(), + f32::MAX, + true, + InteractionGroups { + memberships: PLAYER, + filter: ENEMY | GROUND, + }, + None, + ) + .is_some_and(|(entity, _)| q_enemy.contains(entity)); + + let is_facing_away_from_enemy = spatial_query + .ray_cast( + transform.translation.xy(), + Vec2::NEG_X * facing.direction(), + f32::MAX, + true, + InteractionGroups { + memberships: PLAYER, + filter: ENEMY | GROUND, + }, + None, + ) + .is_some_and(|(entity, _)| q_enemy.contains(entity)); + + if !is_facing_enemies && is_facing_away_from_enemy { + *facing = facing.invert(); + } + } +} From 0873df1a861d7289e6930209e09411aa8229c16e Mon Sep 17 00:00:00 2001 From: mnmaita <47983254+mnmaita@users.noreply.github.com> Date: Sat, 21 Dec 2024 12:51:48 +0100 Subject: [PATCH 20/20] Despawns player arrows when they hit walls --- game/src/game/attack/mod.rs | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/game/src/game/attack/mod.rs b/game/src/game/attack/mod.rs index f319863..3e28b1b 100644 --- a/game/src/game/attack/mod.rs +++ b/game/src/game/attack/mod.rs @@ -3,9 +3,11 @@ pub mod particles; use std::mem; +use arc_attack::Arrow; +use rapier2d::prelude::InteractionGroups; use theseeker_engine::gent::Gent; use theseeker_engine::physics::{ - update_sprite_colliders, Collider, PhysicsWorld, GROUND, + update_sprite_colliders, Collider, PhysicsWorld, GROUND, PLAYER_ATTACK, }; use super::enemy::{Defense, EnemyGfx, EnemyStateSet, JustGotHitMarker}; @@ -60,6 +62,7 @@ impl Plugin for AttackPlugin { // cleanup attack_tick, despawn_projectile, + despawn_player_arrows, attack_cleanup, ) .chain() @@ -417,6 +420,32 @@ pub fn despawn_projectile( } } +pub fn despawn_player_arrows( + query: Query<(Entity, &Transform, &Collider), With>, + spatial_query: Res, + mut commands: Commands, +) { + for (entity, transform, collider) in query.iter() { + let is_arrow_intersecting_with_ground = !spatial_query + .intersect( + transform.translation.xy(), + collider.0.shape(), + InteractionGroups { + memberships: PLAYER_ATTACK, + filter: GROUND, + }, + None, + ) + .is_empty(); + + if is_arrow_intersecting_with_ground { + // Note: purposefully does not despawn child entities, nor remove the + // reference, so that child particle systems have the option of lingering + commands.entity(entity).despawn(); + } + } +} + pub fn kill_on_damage( query: Query<(Entity, &Health), With>, mut damage_events: EventReader,