diff --git a/assets/tilesheet/bandit_hideout.ase b/assets/tilesheet/bandit_hideout.ase index 281c32d..f3ef0b8 100644 Binary files a/assets/tilesheet/bandit_hideout.ase and b/assets/tilesheet/bandit_hideout.ase differ diff --git a/assets/tilesheet/bandit_hideout.png b/assets/tilesheet/bandit_hideout.png index fe8cbb5..7fafc2b 100644 Binary files a/assets/tilesheet/bandit_hideout.png and b/assets/tilesheet/bandit_hideout.png differ diff --git a/assets/tilesheet/heart.ase b/assets/tilesheet/heart.ase new file mode 100644 index 0000000..f6a93ed Binary files /dev/null and b/assets/tilesheet/heart.ase differ diff --git a/assets/tilesheet/heart.png b/assets/tilesheet/heart.png new file mode 100644 index 0000000..1a5ad94 Binary files /dev/null and b/assets/tilesheet/heart.png differ diff --git a/src/app.rs b/src/app.rs index 32963fd..18661eb 100644 --- a/src/app.rs +++ b/src/app.rs @@ -18,7 +18,8 @@ use super::{ }; use crate::{ ability::AbilityPlugin, ai::AIPlugin, attack::AttackPlugin, enviro::EnviroPlugin, - item::ItemPlugin, map::MapPlugin, room::RoomPlugin, weapon::WeaponPlugin, + item::ItemPlugin, map::MapPlugin, room::RoomPlugin, screens::ScreensPlugin, + weapon::WeaponPlugin, }; pub fn app() { @@ -34,6 +35,7 @@ pub fn app() { app.insert_resource(ClearColor(Color::rgb(0.0, 0.0, 0.0))) .insert_resource(ImageSettings::default_nearest()) + .insert_resource(Msaa { samples: 1 }) .insert_resource(window_descriptor); // .insert_resource(LogSettings { // level: bevy::log::Level::DEBUG, @@ -59,7 +61,8 @@ pub fn app() { .add_plugin(HealthBarPlugin) .add_plugin(EnviroPlugin) .add_plugin(WeaponPlugin) - .add_plugin(GridPlugin); + .add_plugin(GridPlugin) + .add_plugin(ScreensPlugin); app.run(); } diff --git a/src/assets.rs b/src/assets.rs index 23de52f..c9fd980 100644 --- a/src/assets.rs +++ b/src/assets.rs @@ -10,7 +10,7 @@ use crate::{ }; #[derive(Deref)] -pub struct SpriteSheet(Handle); +pub struct SpriteSheet(pub Handle); #[derive(Debug, Deref)] pub struct PrefabData(pub HashMap); diff --git a/src/attack.rs b/src/attack.rs index ad95f8c..f1b6d47 100644 --- a/src/attack.rs +++ b/src/attack.rs @@ -4,6 +4,7 @@ use serde::Deserialize; use crate::{ enemy::DamageEnemyEvent, grid::{CellType, Grid}, + player::DamagePlayerEvent, utils::{ok_or_continue, variant_eq, Dir}, }; @@ -69,7 +70,8 @@ impl Plugin for AttackPlugin { fn process_attack( mut events: EventReader, - mut writer: EventWriter, + mut enemy_writer: EventWriter, + mut player_writer: EventWriter, grid: Res, ) { for AttackEvent { @@ -86,10 +88,11 @@ fn process_attack( match cell_entity { CellType::Enemy(entity) => { - writer.send(DamageEnemyEvent { entity: *entity }); + enemy_writer.send(DamageEnemyEvent { entity: *entity }); }, CellType::Player(entity) => { info!("player hit!"); + player_writer.send(DamagePlayerEvent { entity: *entity }); }, _ => {}, } diff --git a/src/main.rs b/src/main.rs index 31b4389..a763018 100644 --- a/src/main.rs +++ b/src/main.rs @@ -20,6 +20,7 @@ mod movement; mod player; mod prefab; mod room; +mod screens; mod spritesheet_constants; mod ui; mod utils; diff --git a/src/player/inventory.rs b/src/player/inventory.rs index 994b1d1..7e422a0 100644 --- a/src/player/inventory.rs +++ b/src/player/inventory.rs @@ -3,11 +3,12 @@ use bevy_bobs::prefab::PrefabId; #[derive(Component)] pub struct Inventory { - pub weapon: PrefabId, + pub weapon_primary: PrefabId, + pub weapon_secondary: PrefabId, pub armor: PrefabId, pub ability: PrefabId, - pub slots: Vec, - capactiy: u32, + // pub slots: Vec, + // capactiy: u32, } impl Inventory {} diff --git a/src/player/mod.rs b/src/player/mod.rs index e9c855b..6a9346b 100644 --- a/src/player/mod.rs +++ b/src/player/mod.rs @@ -61,6 +61,10 @@ pub struct SpawnPlayerEvent { pub prefab_id: PrefabId, } +pub struct DamagePlayerEvent { + pub entity: Entity, +} + pub struct PlayerPlugin; impl Plugin for PlayerPlugin { @@ -70,6 +74,7 @@ impl Plugin for PlayerPlugin { .add_loopless_state(PlayerState::Move) .add_event::() .add_event::() + .add_event::() .add_system(controller.run_in_state(GameState::PlayerInput)) .add_system( move_controller @@ -87,6 +92,7 @@ impl Plugin for PlayerPlugin { .add_enter_system(GameState::PlayerInput, on_turn_start) .add_exit_system(GameState::PlayerInput, reset_on_turn_end) .add_system(spawn) + .add_system(take_damage) .add_system(update_move_indicator.run_in_state(GameState::PlayerInput)) .add_system(spawn_from_ldtk); } @@ -128,10 +134,6 @@ fn spawn( ..default() }, texture_atlas: asset_sheet.clone(), - transform: Transform { - translation: to_world_coords(spawn_pos).extend(BEING_LAYER), - ..default() - }, ..default() }) .insert(Player) @@ -349,3 +351,16 @@ fn spawn_from_ldtk( } } } + +fn take_damage( + mut cmd: Commands, + mut events: EventReader, + mut query: Query<(&mut Health, &GridEntity)>, +) { + for DamagePlayerEvent { entity } in events.iter() { + let (mut health, grid_entity) = query.get_mut(*entity).unwrap(); + + health.take(1); + if health.is_zero() {} + } +} diff --git a/src/screens/components/health.rs b/src/screens/components/health.rs new file mode 100644 index 0000000..206a1df --- /dev/null +++ b/src/screens/components/health.rs @@ -0,0 +1,58 @@ +use std::thread::current; + +use autodefault::*; +use bevy::prelude::*; +use bevy_bobs::component::health::Health; + +use crate::{ + assets::SpriteSheet, player::Player, screens::utils::FONT_PATH, + spritesheet_constants::SpriteIndex, utils::ok_or_return, +}; + +#[derive(Component)] +struct HealthNode; + +pub struct HealthPlugin; + +impl Plugin for HealthPlugin { + fn build(&self, app: &mut App) { + app.add_system(update); + } +} + +#[autodefault] +#[allow(non_snake_case)] +pub fn HealthBar(cmd: &mut ChildBuilder) -> Entity { + cmd.spawn() + .insert(HealthNode) + .insert_bundle(NodeBundle { + style: Style { + display: Display::Flex, + }, + }) + .id() +} + +#[autodefault] +fn update( + mut cmd: Commands, + mut player_query: Query<&Health, With>, + mut ui_query: Query<(Entity, &mut HealthNode), Without>, + asset_server: Res, +) { + let health = ok_or_return!(player_query.get_single()); + + // TODO kinda inefficnet to despawn all health nodes and respawn every frame + for (entity, mut health_node) in ui_query.iter_mut() { + cmd.entity(entity).despawn_descendants(); + + for i in 0..health.current() { + cmd.entity(entity).with_children(|parent| { + parent.spawn().insert_bundle(ImageBundle { + image: UiImage(asset_server.load("tilesheet/heart.png")), + style: Style {}, + }); + }); + } + } +} diff --git a/src/screens/components/inventory.rs b/src/screens/components/inventory.rs new file mode 100644 index 0000000..b6b33ba --- /dev/null +++ b/src/screens/components/inventory.rs @@ -0,0 +1,7 @@ +use bevy::prelude::*; + +pub struct InventoryPlugin; + +impl Plugin for InventoryPlugin { + fn build(&self, app: &mut App) {} +} diff --git a/src/screens/components/mod.rs b/src/screens/components/mod.rs new file mode 100644 index 0000000..337ae11 --- /dev/null +++ b/src/screens/components/mod.rs @@ -0,0 +1,14 @@ +pub mod health; +pub mod inventory; + +use bevy::prelude::*; + +use self::{health::HealthPlugin, inventory::InventoryPlugin}; + +pub struct ComponentPlugin; + +impl Plugin for ComponentPlugin { + fn build(&self, app: &mut App) { + app.add_plugin(InventoryPlugin).add_plugin(HealthPlugin); + } +} diff --git a/src/screens/ingame.rs b/src/screens/ingame.rs new file mode 100644 index 0000000..163142c --- /dev/null +++ b/src/screens/ingame.rs @@ -0,0 +1,35 @@ +use autodefault::*; +use bevy::prelude::*; +use iyes_loopless::prelude::*; + +use super::{ + components::health::HealthBar, + state::ScreenState, + utils::{destroy_ui, UIRoot}, +}; +use crate::{assets::SpriteSheet, spritesheet_constants::SpriteIndex}; + +pub struct IngamePlugin; + +impl Plugin for IngamePlugin { + fn build(&self, app: &mut App) { + app.add_enter_system(ScreenState::Ingame, render_ui) + .add_exit_system(ScreenState::Ingame, destroy_ui); + } +} + +#[autodefault] +fn render_ui(mut cmd: Commands) { + cmd.spawn() + .insert(UIRoot) + .insert_bundle(NodeBundle { + color: UiColor(Color::NONE), + style: Style { + align_self: AlignSelf::FlexEnd, + // justify_content: JustifyContent::Center, + }, + }) + .with_children(|mut parent| { + HealthBar(&mut parent); + }); +} diff --git a/src/screens/mod.rs b/src/screens/mod.rs new file mode 100644 index 0000000..e58f208 --- /dev/null +++ b/src/screens/mod.rs @@ -0,0 +1,28 @@ +mod components; +mod ingame; +mod state; +mod utils; + +use bevy::prelude::*; +use iyes_loopless::state::NextState; + +use self::{ + components::ComponentPlugin, + ingame::IngamePlugin, + state::{ScreenState, StatePlugin}, +}; + +pub struct ScreensPlugin; + +impl Plugin for ScreensPlugin { + fn build(&self, app: &mut App) { + app.add_plugin(StatePlugin) + .add_plugin(IngamePlugin) + .add_plugin(ComponentPlugin) + .add_startup_system(debug); + } +} + +fn debug(mut cmd: Commands) { + cmd.insert_resource(NextState(ScreenState::Ingame)); +} diff --git a/src/screens/state.rs b/src/screens/state.rs new file mode 100644 index 0000000..ea59cb4 --- /dev/null +++ b/src/screens/state.rs @@ -0,0 +1,18 @@ +use bevy::prelude::*; +use iyes_loopless::prelude::*; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum ScreenState { + MainMenu, + Settings, + LevelSelect, + Ingame, +} + +pub struct StatePlugin; + +impl Plugin for StatePlugin { + fn build(&self, app: &mut App) { + app.add_loopless_state(ScreenState::MainMenu); + } +} diff --git a/src/screens/utils.rs b/src/screens/utils.rs new file mode 100644 index 0000000..da64a08 --- /dev/null +++ b/src/screens/utils.rs @@ -0,0 +1,13 @@ +use bevy::prelude::*; + +pub const FONT_PATH: &str = "fonts/arcadeclassic.ttf"; + +/// Marker component for the root node of each screen +#[derive(Component)] +pub struct UIRoot; + +/// Clean up UI when switching screens +pub fn destroy_ui(mut cmd: Commands, query: Query>) { + let e = query.single(); + cmd.entity(e).despawn_recursive(); +} diff --git a/src/spritesheet_constants.rs b/src/spritesheet_constants.rs index 354dc35..59e6b9a 100644 --- a/src/spritesheet_constants.rs +++ b/src/spritesheet_constants.rs @@ -20,6 +20,13 @@ pub enum SpriteIndex { // MoveIndicatorN = sprite!(5, 10), // MoveIndicatorS = sprite!(6, 10), // MoveIndicatorE = sprite!(7, 10), + ItemSlotBg = sprite!(0, 11), + WeaponSlot = sprite!(1, 11), + ArmorSlot = sprite!(2, 11), + AbilitySlot = sprite!(3, 11), + + HeartFull = sprite!(0, 12), + HeartEmpty = sprite!(0, 13), } // ui