diff --git a/assets/fighters/bandit/bandit.fighter.yaml b/assets/fighters/bandit/bandit.fighter.yaml index 090a9b58..43b30272 100644 --- a/assets/fighters/bandit/bandit.fighter.yaml +++ b/assets/fighters/bandit/bandit.fighter.yaml @@ -42,17 +42,17 @@ spritesheet: attacking: frames: [14, 17] -attack: - name: "punch" - damage: 4 - frames: - startup: 1 - active: 2 - recovery: 3 - hitbox: - size: [36, 24] - offset: [24, 0] - hitstun_duration: 0.2 +attacks: + - name: "punch" + damage: 4 + frames: + startup: 1 + active: 2 + recovery: 3 + hitbox: + size: [36, 24] + offset: [24, 0] + hitstun_duration: 0.2 audio: effects: diff --git a/assets/fighters/big_bass/big_bass.fighter.yaml b/assets/fighters/big_bass/big_bass.fighter.yaml index 86f0e309..9515cc50 100644 --- a/assets/fighters/big_bass/big_bass.fighter.yaml +++ b/assets/fighters/big_bass/big_bass.fighter.yaml @@ -41,17 +41,17 @@ spritesheet: attacking: frames: [30, 44] -attack: - name: "ground_slam" - damage: 35 - frames: - startup: 5 - active: 9 - recovery: 14 - hitbox: - size: [96, 32] - offset: [0, -69] - hitstun_duration: 0.2 +attacks: + - name: "ground_slam" + damage: 35 + frames: + startup: 5 + active: 9 + recovery: 14 + hitbox: + size: [96, 32] + offset: [0, -69] + hitstun_duration: 0.2 audio: effects: diff --git a/assets/fighters/brute/brute.fighter.yaml b/assets/fighters/brute/brute.fighter.yaml index abbd110a..6a12ff01 100644 --- a/assets/fighters/brute/brute.fighter.yaml +++ b/assets/fighters/brute/brute.fighter.yaml @@ -42,17 +42,17 @@ spritesheet: attacking: frames: [16, 23] -attack: - name: "punch" - damage: 10 - frames: - startup: 2 - active: 3 - recovery: 7 - hitbox: - size: [36, 24] - offset: [24, 0] - hitstun_duration: 0.2 +attacks: + - name: "punch" + damage: 10 + frames: + startup: 2 + active: 3 + recovery: 7 + hitbox: + size: [36, 24] + offset: [24, 0] + hitstun_duration: 0.2 audio: effects: {} diff --git a/assets/fighters/dev/dev.fighter.yaml b/assets/fighters/dev/dev.fighter.yaml index 14437362..eacefddf 100644 --- a/assets/fighters/dev/dev.fighter.yaml +++ b/assets/fighters/dev/dev.fighter.yaml @@ -16,8 +16,8 @@ hud: spritesheet: image: [dev_base_96_80.png] tile_size: [96, 80] - columns: 15 - rows: 14 + columns: 14 + rows: 15 animation_fps: 0.12 animations: @@ -39,17 +39,17 @@ spritesheet: attacking: frames: [85, 90] -attack: - name: "punch" - damage: 35 - frames: - startup: 1 - active: 2 - recovery: 4 - hitbox: - size: [32, 32] - offset: [32, 0] - hitstun_duration: 0.2 +attacks: + - name: "punch" + damage: 35 + frames: + startup: 1 + active: 2 + recovery: 4 + hitbox: + size: [32, 32] + offset: [32, 0] + hitstun_duration: 0.2 audio: effects: diff --git a/assets/fighters/fishy/fishy.fighter.yaml b/assets/fighters/fishy/fishy.fighter.yaml index 49b274e4..c2b61621 100644 --- a/assets/fighters/fishy/fishy.fighter.yaml +++ b/assets/fighters/fishy/fishy.fighter.yaml @@ -39,18 +39,17 @@ spritesheet: attacking: frames: [85, 90] -attack: - name: "flop" - damage: 35 - frames: - startup: 1 - active: 2 - recovery: 4 - hitbox: - size: [32, 32] - offset: [32, 0] - hitstun_duration: 0.2 - # velocity: [20.0, 0.0] +attacks: + - name: "flop" + damage: 35 + frames: + startup: 1 + active: 2 + recovery: 4 + hitbox: + size: [32, 32] + offset: [32, 0] + hitstun_duration: 0.2 audio: effects: diff --git a/assets/fighters/sharky/sharky.fighter.yaml b/assets/fighters/sharky/sharky.fighter.yaml index 5756e855..355badfa 100644 --- a/assets/fighters/sharky/sharky.fighter.yaml +++ b/assets/fighters/sharky/sharky.fighter.yaml @@ -39,17 +39,17 @@ spritesheet: attacking: frames: [85, 90] -attack: - name: "flop" - damage: 35 - frames: - startup: 1 - active: 2 - recovery: 4 - hitbox: - size: [32, 32] - offset: [32, 0] - hitstun_duration: 0.2 +attacks: + - name: "flop" + damage: 35 + frames: + startup: 1 + active: 2 + recovery: 4 + hitbox: + size: [32, 32] + offset: [32, 0] + hitstun_duration: 0.2 audio: effects: diff --git a/assets/fighters/slinger/slinger.fighter.yaml b/assets/fighters/slinger/slinger.fighter.yaml index 42fcd62a..c80734d6 100644 --- a/assets/fighters/slinger/slinger.fighter.yaml +++ b/assets/fighters/slinger/slinger.fighter.yaml @@ -46,17 +46,17 @@ spritesheet: attacking: frames: [14, 18] # this should be changed to a ranged attack -attack: - name: "punch" - damage: 7 - frames: - startup: 1 - active: 2 - recovery: 3 - hitbox: - size: [36, 24] - offset: [24, 0] - hitstun_duration: 0.2 +attacks: + - name: "punch" + damage: 7 + frames: + startup: 1 + active: 2 + recovery: 3 + hitbox: + size: [36, 24] + offset: [24, 0] + hitstun_duration: 0.2 audio: effects: {} diff --git a/assets/levels/1_beach/beach.level.yaml b/assets/levels/1_beach/beach.level.yaml index f8c92bae..93378be0 100644 --- a/assets/levels/1_beach/beach.level.yaml +++ b/assets/levels/1_beach/beach.level.yaml @@ -44,7 +44,8 @@ parallax_background: transition_factor: 0.9 players: - - fighter: /fighters/fishy/fishy.fighter.yaml + # - fighter: /fighters/fishy/fishy.fighter.yaml + - fighter: /fighters/dev/dev.fighter.yaml location: [0, 0, 0] - fighter: /fighters/sharky/sharky.fighter.yaml location: [-70, 30, 0] diff --git a/src/attack.rs b/src/attack.rs index 355a5cb9..acb9ac6e 100644 --- a/src/attack.rs +++ b/src/attack.rs @@ -7,9 +7,8 @@ use serde::Deserialize; use crate::{ animation::Animation, damage::{DamageEvent, Damageable, Health}, - fighter_state::MeleeWeapon, + fighter::AvailableAttacks, item::Drop, - metadata::FighterMeta, GameState, }; @@ -89,30 +88,18 @@ pub struct AttackFrames { fn activate_hitbox( attack_query: Query<(Entity, &AttackFrames, &Parent), Without>, - fighter_query: Query<( - &Animation, - Option<&Handle>, - Option<&MeleeWeapon>, - )>, + fighter_query: Query<(&Animation, &AvailableAttacks)>, mut commands: Commands, - fighter_assets: Res>, ) { for (entity, attack_frames, parent) in attack_query.iter() { - if let Ok((animation, fighter_meta, melee_weapon)) = fighter_query.get(**parent) { + if let Ok((animation, available_attacks)) = fighter_query.get(**parent) { if animation.current_frame >= attack_frames.startup && animation.current_frame <= attack_frames.active { - if let Some(fighter_meta) = fighter_meta { - if let Some(fighter_data) = fighter_assets.get(fighter_meta) { - commands.entity(entity).insert(Collider::cuboid( - fighter_data.attack.hitbox.size.x / 2., - fighter_data.attack.hitbox.size.y / 2., - )); - } - } else if let Some(melee_weapon) = melee_weapon { + if let Some(attack) = available_attacks.0.last() { commands.entity(entity).insert(Collider::cuboid( - melee_weapon.attack.hitbox.size.x / 2., - melee_weapon.attack.hitbox.size.y / 2., + attack.hitbox.size.x / 2., + attack.hitbox.size.y / 2., )); } } diff --git a/src/enemy_ai.rs b/src/enemy_ai.rs index 5695bdce..182c934c 100644 --- a/src/enemy_ai.rs +++ b/src/enemy_ai.rs @@ -14,12 +14,15 @@ use crate::{ Stats, }; +//maybe implement as plugin + /// A place that an enemy fighter is going to move to, in an attempt to attack a player. /// /// The attack distance is for randomization purposes, and it's the distance that triggers the /// attack. More precisely, it's the max distance - if the enemy finds itself at a smaller distance, /// it will attack. -#[derive(Component)] +#[derive(Component, Reflect, Default)] +#[reflect(Component)] #[component(storage = "SparseSet")] pub struct EnemyTarget { pub position: Vec2, @@ -136,6 +139,7 @@ pub fn emit_enemy_intents( Facing::Left }; + // make them attack with their first available attack?? // And attack! if maybe_boss.is_some() { intents.push_back(StateTransition::new( diff --git a/src/fighter.rs b/src/fighter.rs index 0f81fd7a..9635a30f 100644 --- a/src/fighter.rs +++ b/src/fighter.rs @@ -12,7 +12,7 @@ use crate::{ damage::{Damageable, Health}, enemy::Enemy, fighter_state::{Idling, StateTransitionIntents}, - metadata::FighterMeta, + metadata::{AttackMeta, FighterMeta}, movement::LinearVelocity, player::Player, }; @@ -42,8 +42,12 @@ pub struct ActiveFighterBundle { /// Fighters start off idling, but this component may be removed when the fighter state changes. pub idling: Idling, pub velocity: LinearVelocity, + pub available_attacks: AvailableAttacks, } +#[derive(Component)] +pub struct AvailableAttacks(pub Vec); + #[derive(Component, Deserialize, Clone, Debug, Reflect)] #[reflect(Component)] #[serde(deny_unknown_fields)] @@ -121,6 +125,7 @@ impl ActiveFighterBundle { // ysort: YSort(fighter.spritesheet.tile_size.y as f32 / 2.), ysort: YSort(consts::FIGHTERS_Z), velocity: default(), + available_attacks: AvailableAttacks(fighter.attacks.clone()), }; let hurtbox = commands .spawn_bundle(PhysicsBundle::new(&fighter.hurtbox, body_layers)) diff --git a/src/fighter_state.rs b/src/fighter_state.rs index f72c3cb1..44aede17 100644 --- a/src/fighter_state.rs +++ b/src/fighter_state.rs @@ -15,13 +15,13 @@ use crate::{ damage::{DamageEvent, Health}, enemy::{Boss, Enemy}, enemy_ai, - fighter::{Attached, Inventory}, + fighter::{Attached, AvailableAttacks, Inventory}, input::PlayerAction, item::{Drop, Item, ItemBundle, Projectile, ScriptItemGrabEvent, ScriptItemThrowEvent}, lifetime::Lifetime, metadata::{AttackMeta, AudioMeta, FighterMeta, ItemKind, ItemMeta, ItemSpawnMeta}, movement::LinearVelocity, - player::{AvailableAttacks, Player}, + player::Player, Collider, GameState, Stats, }; @@ -662,6 +662,7 @@ fn flopping( &mut LinearVelocity, &Facing, &Handle, + &AvailableAttacks, &mut Flopping, Option<&Player>, Option<&Enemy>, @@ -675,6 +676,7 @@ fn flopping( mut velocity, facing, meta_handle, + available_attacks, mut flopping, player, enemy, @@ -687,6 +689,7 @@ fn flopping( continue; } + let attack = available_attacks.0.last().expect("Attack not loaded"); if let Some(fighter) = fighter_assets.get(meta_handle) { // Start the attack if !flopping.has_started { @@ -696,12 +699,12 @@ fn flopping( // Start the attack from the beginning animation.play(Flopping::ANIMATION, false); - let mut offset = fighter.attack.hitbox.offset; + let mut offset = attack.hitbox.offset; if facing.is_left() { offset.x *= -1.0 } offset.y += fighter.collision_offset; - let attack_frames = fighter.attack.frames; + let attack_frames = attack.frames; // Spawn the attack entity let attack_entity = commands @@ -724,13 +727,13 @@ fn flopping( }, )) .insert(Attack { - damage: fighter.attack.damage, + damage: attack.damage, velocity: if facing.is_left() { Vec2::NEG_X } else { Vec2::X - } * fighter.attack.velocity.unwrap_or(Vec2::ZERO), - hitstun_duration: fighter.attack.hitstun_duration, + } * attack.velocity.unwrap_or(Vec2::ZERO), + hitstun_duration: attack.hitstun_duration, }) .insert(attack_frames) .id(); @@ -751,7 +754,7 @@ fn flopping( // Do a forward jump thing //TODO: Fix hacky way to get a forward jump - if animation.current_frame < fighter.attack.frames.recovery { + if animation.current_frame < attack.frames.recovery { if facing.is_left() { velocity.x -= 200.0; } else { @@ -759,12 +762,11 @@ fn flopping( } } - if animation.current_frame < fighter.attack.frames.startup { - let v_per_frame = 200.0 / fighter.attack.frames.startup as f32; + if animation.current_frame < attack.frames.startup { + let v_per_frame = 200.0 / attack.frames.startup as f32; velocity.y += v_per_frame; - } else if animation.current_frame < fighter.attack.frames.active { - let v_per_frame = - 200.0 / (fighter.attack.frames.active - fighter.attack.frames.startup) as f32; + } else if animation.current_frame < attack.frames.active { + let v_per_frame = 200.0 / (attack.frames.active - attack.frames.startup) as f32; velocity.y -= v_per_frame; } @@ -790,14 +792,24 @@ fn punching( &mut LinearVelocity, &Facing, &Handle, + &AvailableAttacks, &mut Punching, Option<&Player>, Option<&Enemy>, )>, fighter_assets: Res>, ) { - for (entity, mut animation, mut velocity, facing, meta_handle, mut punching, player, enemy) in - &mut fighters + for ( + entity, + mut animation, + mut velocity, + facing, + meta_handle, + available_attacks, + mut punching, + player, + enemy, + ) in &mut fighters { let is_player = player.is_some(); let is_enemy = enemy.is_some(); @@ -806,6 +818,7 @@ fn punching( continue; } + let attack = available_attacks.0.last().expect("Attack not loaded"); if let Some(fighter) = fighter_assets.get(meta_handle) { if !punching.has_started { punching.has_started = true; @@ -813,12 +826,12 @@ fn punching( // Start the attack from the beginning animation.play(Punching::ANIMATION, false); - let mut offset = fighter.attack.hitbox.offset; + let mut offset = attack.hitbox.offset; if facing.is_left() { offset.x *= -1.0 } offset.y += fighter.collision_offset; - let attack_frames = fighter.attack.frames; + let attack_frames = attack.frames; // Spawn the attack entity let attack_entity = commands .spawn_bundle(TransformBundle::from_transform( @@ -840,13 +853,13 @@ fn punching( }, )) .insert(Attack { - damage: fighter.attack.damage, + damage: attack.damage, velocity: if facing.is_left() { Vec2::NEG_X } else { Vec2::X - } * fighter.attack.velocity.unwrap_or(Vec2::ZERO), - hitstun_duration: fighter.attack.hitstun_duration, + } * attack.velocity.unwrap_or(Vec2::ZERO), + hitstun_duration: attack.hitstun_duration, }) .insert(attack_frames) .id(); @@ -882,6 +895,7 @@ fn ground_slam( &mut LinearVelocity, &Facing, &Handle, + &AvailableAttacks, &mut GroundSlam, ), With, @@ -895,17 +909,19 @@ fn ground_slam( mut velocity, facing, meta_handle, + available_attacks, mut ground_slam, ) in &mut fighters { // Start the attack + let attack = available_attacks.0.last().expect("Attack not loaded"); if let Some(fighter) = fighter_assets.get(meta_handle) { - let mut offset = fighter.attack.hitbox.offset; + let mut offset = attack.hitbox.offset; if facing.is_left() { offset.x *= -1.0 } offset.y += fighter.collision_offset; - let attack_frames = fighter.attack.frames; + let attack_frames = attack.frames; if !ground_slam.has_started { ground_slam.has_started = true; ground_slam.start_y = transform.translation.y; @@ -926,13 +942,13 @@ fn ground_slam( BodyLayers::PLAYER, )) .insert(Attack { - damage: fighter.attack.damage, + damage: attack.damage, velocity: if facing.is_left() { Vec2::NEG_X } else { Vec2::X - } * fighter.attack.velocity.unwrap_or(Vec2::ZERO), - hitstun_duration: fighter.attack.hitstun_duration, + } * attack.velocity.unwrap_or(Vec2::ZERO), + hitstun_duration: attack.hitstun_duration, }) .insert(attack_frames) .id(); diff --git a/src/loading.rs b/src/loading.rs index 5b857e1d..cfb4dce2 100644 --- a/src/loading.rs +++ b/src/loading.rs @@ -326,7 +326,6 @@ fn load_level( mut items_assets: ResMut>, mut parallax: ResMut, mut texture_atlases: ResMut>, - fighter_assets: Res>, asset_server: Res, game: Res, windows: Res, @@ -365,7 +364,6 @@ fn load_level( i, &game, storage.get(Settings::STORAGE_KEY).as_ref(), - &fighter_assets, )); } diff --git a/src/main.rs b/src/main.rs index 32d7d959..01c7ae13 100644 --- a/src/main.rs +++ b/src/main.rs @@ -49,6 +49,7 @@ use animation::*; use attack::AttackPlugin; use audio::*; use camera::*; +use enemy_ai::EnemyTarget; use metadata::GameMeta; use ui::UIPlugin; use utils::ResetController; @@ -137,6 +138,8 @@ fn main() { .with_system(game_over_on_players_death) .into(), ) + //this should be moved to AudioPlugin, it also causes a panic in egui_inspector when + //using the color picker widget currently .add_system_to_stage( CoreStage::PostUpdate, main_menu_sounds @@ -145,7 +148,7 @@ fn main() { ); // Register reflect types that don't come from plugins - app.register_type::(); + app.register_type::().register_type::(); // Add debug plugins if enabled if engine_config.debug_tools { diff --git a/src/metadata.rs b/src/metadata.rs index d5d3f027..6b202bcf 100644 --- a/src/metadata.rs +++ b/src/metadata.rs @@ -107,8 +107,7 @@ pub struct FighterMeta { pub spritesheet: FighterSpritesheetMeta, pub audio: AudioMeta, pub hurtbox: ColliderMeta, - //Will likely need a hashmap(?) of AttackMetas, fighters will have multiple attacks - pub attack: AttackMeta, + pub attacks: Vec, pub attachment: Option, } diff --git a/src/player.rs b/src/player.rs index 098b8691..1ff0f906 100644 --- a/src/player.rs +++ b/src/player.rs @@ -6,7 +6,7 @@ use crate::{ consts, fighter::Inventory, input::PlayerAction, - metadata::{AttackMeta, FighterMeta, FighterSpawnMeta, GameMeta, Settings}, + metadata::{FighterMeta, FighterSpawnMeta, GameMeta, Settings}, }; #[derive(Component)] @@ -26,7 +26,6 @@ pub struct PlayerBundle { fighter_handle: Handle, #[bundle] input_manager_bundle: InputManagerBundle, - available_attacks: AvailableAttacks, } impl PlayerBundle { @@ -35,7 +34,6 @@ impl PlayerBundle { player_i: usize, game_meta: &GameMeta, settings: Option<&Settings>, - fighter_assets: &Res>, ) -> Self { let ground_offset = Vec3::new(0.0, consts::GROUND_Y, 0.0); let player_pos = player_meta.location + ground_offset; @@ -53,12 +51,6 @@ impl PlayerBundle { ..default() }; - let available_attacks = AvailableAttacks(vec![fighter_assets - .get(&player_meta.fighter_handle) - .expect("Fighter not loaded") - .attack - .clone()]); - PlayerBundle { player: Player, index: PlayerIndex(player_i), @@ -67,10 +59,6 @@ impl PlayerBundle { fighter_handle, input_manager_bundle, inventory: Inventory(None), - available_attacks, } } } - -#[derive(Component)] -pub struct AvailableAttacks(pub Vec);