Integrated trait objects and made modular spawn points

This commit is contained in:
Franklin 2023-11-12 14:36:37 -04:00
parent 8afa56d306
commit 61f33357a4
24 changed files with 168 additions and 87 deletions

26
Cargo.lock generated
View File

@ -390,6 +390,31 @@ dependencies = [
"syn 2.0.32", "syn 2.0.32",
] ]
[[package]]
name = "bevy-trait-query"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "03c0e3cf09569de8478a06f958a0df02cb12ecbda4d77059d8e4dc3e5a072126"
dependencies = [
"bevy-trait-query-impl",
"bevy_app",
"bevy_core",
"bevy_ecs",
"tracing",
]
[[package]]
name = "bevy-trait-query-impl"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4a9d5d3e9b4854feb8b622ceaa36e84cb4a14e30ef8b12231db681a04f545748"
dependencies = [
"proc-macro-crate",
"proc-macro2",
"quote",
"syn 2.0.32",
]
[[package]] [[package]]
name = "bevy_a11y" name = "bevy_a11y"
version = "0.12.0" version = "0.12.0"
@ -1885,6 +1910,7 @@ version = "0.1.0"
dependencies = [ dependencies = [
"bevy", "bevy",
"bevy-inspector-egui", "bevy-inspector-egui",
"bevy-trait-query",
"bevy_editor_pls", "bevy_editor_pls",
"bevy_hanabi", "bevy_hanabi",
"bevy_rapier3d", "bevy_rapier3d",

View File

@ -19,4 +19,5 @@ bevy = { version = "0.12", features = ["dynamic_linking"]}
bevy-inspector-egui = "0.21.0" bevy-inspector-egui = "0.21.0"
bevy_editor_pls = "0.6" bevy_editor_pls = "0.6"
bevy_rapier3d = { path = "../bevy_rapier/bevy_rapier3d", features = ["debug-render-3d"] } bevy_rapier3d = { path = "../bevy_rapier/bevy_rapier3d", features = ["debug-render-3d"] }
bevy_hanabi = { version = "0.8", default-features = false, features = [ "3d" ] } bevy_hanabi = { version = "0.8", default-features = false, features = [ "3d" ] }
bevy-trait-query = "0.4.0"

View File

@ -1,2 +1,2 @@
pub mod loot_container; //pub mod loot_container;
pub mod pickup_item; pub mod pickup_item;

View File

@ -1,4 +1,8 @@
use std::sync::Arc;
use bevy::prelude::*; use bevy::prelude::*;
use crate::comps::core::items::item::Item;
#[derive(Event)] #[derive(Event)]
pub struct PickupItemEvent(); pub struct PickupItemEvent(pub Arc<dyn Item>);

View File

@ -1,5 +1,3 @@
use bevy::ecs::component::SparseStorage;
use crate::comps::core::{grid::UGrid, items::item::Item}; use crate::comps::core::{grid::UGrid, items::item::Item};
use super::inventory_item::InventoryItem; use super::inventory_item::InventoryItem;
@ -19,7 +17,7 @@ impl AnyInventory {
items: Vec::new(), items: Vec::new(),
} }
} }
pub fn add_item_at(&mut self, position: UGrid, item: impl Item<Storage = SparseStorage>) { pub fn add_item_at(&mut self, position: UGrid, item: impl Item) {
// Is Item bigger than inventory? // Is Item bigger than inventory?
// Does position + item size exceed bounds? // Does position + item size exceed bounds?
if !self.valid_item_and_size_for_inventory(position, &item) { if !self.valid_item_and_size_for_inventory(position, &item) {
@ -33,7 +31,7 @@ impl AnyInventory {
self.items.push(InventoryItem::new(item, spots_to_occupy)); self.items.push(InventoryItem::new(item, spots_to_occupy));
} }
// Is there any items in inventory that are in any of the spots that this new item will be in // Is there any items in inventory that are in any of the spots that this new item will be in
pub fn item_fits_at(&self, position: UGrid, item: &impl Item<Storage = SparseStorage>) -> bool { pub fn item_fits_at(&self, position: UGrid, item: &impl Item) -> bool {
let spots_to_occupy = Self::get_spots_from_item_at_pos(position, item); let spots_to_occupy = Self::get_spots_from_item_at_pos(position, item);
for inventory_item in self.items.iter() { for inventory_item in self.items.iter() {
if inventory_item.is_in_range(&spots_to_occupy) { if inventory_item.is_in_range(&spots_to_occupy) {
@ -44,7 +42,7 @@ impl AnyInventory {
} }
pub fn get_spots_from_item_at_pos( pub fn get_spots_from_item_at_pos(
position: UGrid, position: UGrid,
item: &impl Item<Storage = SparseStorage>, item: &impl Item,
) -> Vec<UGrid> { ) -> Vec<UGrid> {
let end_position = position + item.inventory_size(); let end_position = position + item.inventory_size();
let mut spots = Vec::new(); let mut spots = Vec::new();
@ -61,7 +59,7 @@ impl AnyInventory {
pub fn valid_item_and_size_for_inventory( pub fn valid_item_and_size_for_inventory(
&self, &self,
position: UGrid, position: UGrid,
item: &impl Item<Storage = SparseStorage>, item: &impl Item,
) -> bool { ) -> bool {
let item_bounds = position + item.inventory_size(); let item_bounds = position + item.inventory_size();
!(item_bounds.width > self.size.width || item_bounds.height > self.size.height) !(item_bounds.width > self.size.width || item_bounds.height > self.size.height)

View File

@ -6,7 +6,7 @@ use crate::comps::core::{grid::UGrid, items::item::Item};
#[derive(Clone)] #[derive(Clone)]
pub struct InventoryItem { pub struct InventoryItem {
item: Arc<dyn Item<Storage = SparseStorage>>, item: Arc<dyn Item>,
/// Coordinates that this InventoryItem occupies inside an AnyInventory /// Coordinates that this InventoryItem occupies inside an AnyInventory
occupied_spots: Vec<UGrid>, occupied_spots: Vec<UGrid>,
rotated: Option<bool>, rotated: Option<bool>,
@ -14,13 +14,13 @@ pub struct InventoryItem {
#[allow(unused)] #[allow(unused)]
impl InventoryItem { impl InventoryItem {
pub fn item(&self) -> &dyn Item<Storage = SparseStorage> { pub fn item(&self) -> &dyn Item {
self.item.as_ref() self.item.as_ref()
} }
pub fn rotated(&self) -> Option<bool> { pub fn rotated(&self) -> Option<bool> {
self.rotated self.rotated
} }
pub fn new(item: impl Item<Storage = SparseStorage>, occupied_spots: Vec<UGrid>) -> Self { pub fn new(item: impl Item, occupied_spots: Vec<UGrid>) -> Self {
let size = item.inventory_size(); let size = item.inventory_size();
let rotated = item.inventory_rotatable().then(|| false); let rotated = item.inventory_rotatable().then(|| false);
Self { Self {

View File

@ -1,12 +1,10 @@
use std::sync::Arc; use bevy::prelude::*;
use bevy::{ecs::component::SparseStorage, prelude::*};
use crate::comps::core::items::item::Item; use crate::comps::core::items::item::Item;
/// # ItemInventory /// # ItemInventory
/// Specifically made to hold single items such as Guns, Pieces of armor. /// Specifically made to hold single items such as Guns, Pieces of armor.
#[derive(Component, Clone, Default)] #[derive(Component, Clone, Default)]
pub struct ItemInventory { pub struct ItemInventory<'a> {
pub item: Option<Arc<dyn Item<Storage = SparseStorage>>>, pub item: Option<&'a dyn Item>,
} }

View File

@ -1,4 +1,4 @@
pub mod any_inventory; //pub mod any_inventory;
pub mod inventory_item; //pub mod inventory_item;
pub mod item_inventory; pub mod item_inventory;
pub mod player_inventory; pub mod player_inventory;

View File

@ -1,22 +1,20 @@
use bevy::prelude::*; use bevy::prelude::*;
use crate::comps::core::grid::UGrid; use super::item_inventory::ItemInventory;
use super::{any_inventory::AnyInventory, item_inventory::ItemInventory};
#[derive(Component)] #[derive(Component)]
pub struct PlayerInventory { pub struct PlayerInventory<'a> {
pub primary: ItemInventory, pub primary: ItemInventory<'a>,
pub secondary: ItemInventory, pub secondary: ItemInventory<'a>,
pub backpack: AnyInventory, //pub backpack: AnyInventory,
} }
impl Default for PlayerInventory { impl<'a> Default for PlayerInventory<'a> {
fn default() -> Self { fn default() -> Self {
Self { Self {
primary: Default::default(), primary: Default::default(),
secondary: Default::default(), secondary: Default::default(),
backpack: AnyInventory::new(UGrid::new_square(10)), //backpack: AnyInventory::new(UGrid::new_square(10)),
} }
} }
} }

View File

@ -16,7 +16,8 @@ pub enum ItemType {
Consumable, Consumable,
} }
pub trait Item: Component { #[bevy_trait_query::queryable]
pub trait Item {
fn get_type(&self) -> ItemType; fn get_type(&self) -> ItemType;
fn asset_path(&self) -> &str; fn asset_path(&self) -> &str;
/// Optional Stackable. If value is Some(x) x is the max quantity per stack /// Optional Stackable. If value is Some(x) x is the max quantity per stack

View File

@ -2,13 +2,13 @@ use std::fmt::Display;
use bevy::prelude::Component; use bevy::prelude::Component;
use crate::comps::core::inventory::any_inventory::AnyInventory; //use crate::comps::core::inventory::any_inventory::AnyInventory;
#[allow(unused)] #[allow(unused)]
#[derive(Component)] #[derive(Component)]
pub enum Interactable { pub enum Interactable {
Holdable, Holdable,
Lootable(AnyInventory), //Lootable(AnyInventory),
Item, Item,
} }
@ -16,7 +16,7 @@ impl Display for Interactable {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self { match self {
Interactable::Holdable => write!(f, "Holdable"), Interactable::Holdable => write!(f, "Holdable"),
Interactable::Lootable(_) => write!(f, "Lootable"), //Interactable::Lootable(_) => write!(f, "Lootable"),
Interactable::Item => write!(f, "Item"), Interactable::Item => write!(f, "Item"),
} }
} }

View File

@ -3,7 +3,7 @@ use bevy_rapier3d::prelude::*;
use crate::{ use crate::{
comps::core::{ comps::core::{
events::loot_container::LootContainerEvent, //events::loot_container::LootContainerEvent,
markers::{ markers::{
camera::MainCamera, camera::MainCamera,
firearm::{FirearmData, MagazineData}, firearm::{FirearmData, MagazineData},
@ -225,7 +225,7 @@ pub fn interact_action(
keyboard_input: Res<Input<KeyCode>>, keyboard_input: Res<Input<KeyCode>>,
rapier_context: Res<RapierContext>, rapier_context: Res<RapierContext>,
mut hud_state: ResMut<HudState>, mut hud_state: ResMut<HudState>,
mut loot_container_event_writer: EventWriter<LootContainerEvent>, //mut loot_container_event_writer: EventWriter<LootContainerEvent>,
) { ) {
for (player_entity, transform) in player_query.iter() { for (player_entity, transform) in player_query.iter() {
for global_transform in camera_query.iter() { for global_transform in camera_query.iter() {
@ -250,17 +250,18 @@ pub fn interact_action(
if interactable_entity == entity { if interactable_entity == entity {
hud_state.interaction_clue_shown = true; hud_state.interaction_clue_shown = true;
hud_state.interaction_clue_text = interactable.to_string(); hud_state.interaction_clue_text = interactable.to_string();
println!("{interactable}");
if keyboard_input.just_pressed(KeyCode::F) { if keyboard_input.just_pressed(KeyCode::F) {
// TODO: Move this key to Controls state global // TODO: Move this key to Controls state global
println!("Interacted with interactable");
match interactable { match interactable {
Interactable::Holdable => todo!(), Interactable::Holdable => todo!(),
Interactable::Lootable(any_inventory) => { /*Interactable::Lootable(any_inventory) => {
loot_container_event_writer loot_container_event_writer
.send(LootContainerEvent(any_inventory.clone())) .send(LootContainerEvent(any_inventory.clone()))
} }*/
Interactable::Item => todo!(), Interactable::Item => {
//loot_container_event_writer
// .send()
},
} }
} }
return; return;

View File

@ -1,7 +1,10 @@
#![feature(step_trait)] #![feature(step_trait)]
#![feature(trivial_bounds)]
#![feature(return_position_impl_trait_in_trait)]
use bevy::prelude::*; use bevy::prelude::*;
use bevy_rapier3d::prelude::*; use bevy_rapier3d::prelude::*;
use scenes::scene1; use scenes::scene1;
use setup::spawners::{spawn_point::SpawnPointPlugin, item::ItemSpawnPointPlugin};
use ui::{editor::plugin::MainEditorUiPlugin, game::plugin::MainGameUIPlugin}; use ui::{editor::plugin::MainEditorUiPlugin, game::plugin::MainGameUIPlugin};
mod comps; mod comps;
@ -30,7 +33,8 @@ fn setup_plugins(application: &mut App) {
//.add_plugins(bevy_egui::EguiPlugin) //.add_plugins(bevy_egui::EguiPlugin)
//.add_plugins(WorldInspectorPlugin::new()) //.add_plugins(WorldInspectorPlugin::new())
.add_plugins(MainGameUIPlugin) .add_plugins(MainGameUIPlugin)
.add_plugins(MainEditorUiPlugin); .add_plugins(MainEditorUiPlugin)
.add_plugins((SpawnPointPlugin, ItemSpawnPointPlugin));
} }
fn load(application: &mut App) { fn load(application: &mut App) {

View File

@ -1,10 +1,6 @@
use bevy::prelude::*; use bevy::prelude::*;
use bevy_rapier3d::prelude::*; use bevy_rapier3d::prelude::*;
use crate::comps::core::{
grid::UGrid, inventory::any_inventory::AnyInventory, markers::interactable::Interactable,
};
pub fn spawn_obstacles( pub fn spawn_obstacles(
mut commands: Commands, mut commands: Commands,
mut meshes: ResMut<Assets<Mesh>>, mut meshes: ResMut<Assets<Mesh>>,
@ -101,7 +97,7 @@ pub fn spawn_obstacles(
transform: Transform::from_xyz(20.0, 2.0, 20.0), transform: Transform::from_xyz(20.0, 2.0, 20.0),
..default() ..default()
}) })
.insert(Interactable::Lootable(AnyInventory::new( /*.insert(Interactable::Lootable(AnyInventory::new(
UGrid::new_square(10), UGrid::new_square(10),
))); )))*/;
} }

View File

@ -1,20 +1,16 @@
use bevy::prelude::*; use bevy::prelude::*;
use crate::{ use crate::{
comps::core::{ comps::core::markers::player::{Player, PlayerData},
items::guns::m4a1::M4a1GunItem, setup::spawners::{player::PlayerSpawnPoint, guns::m4a1_spawner::M4a1SpawnPoint},
markers::player::{Player, PlayerData},
},
setup::spawn::SpawnPoint,
}; };
pub fn set_spawn_points(mut commands: Commands) { pub fn set_spawn_points(mut commands: Commands) {
commands.spawn(SpawnPoint { commands.spawn(PlayerSpawnPoint {
at: Transform::from_xyz(3.0, 5.0, 2.0), transform: Transform::from_xyz(3.0, 5.0, 2.0),
what: Player(PlayerData::default()), player: Player(PlayerData::default()),
}); });
commands.spawn(SpawnPoint { commands.spawn(M4a1SpawnPoint {
at: Transform::from_xyz(20.0, 10.0, 10.0), transform: Transform::from_xyz(20.0, 10.0, 10.0),
what: M4a1GunItem,
}); });
} }

View File

@ -1,22 +1,16 @@
use bevy::prelude::*; use bevy::prelude::*;
use crate::comps::core::items::{guns::m4a1::M4a1GunItem, item::Item}; use super::spawners::{item::item_spawner, player::player_spawner};
use super::{
equipment::change_equipment,
spawners::{item::item_spawner, player::player_spawner},
};
/// Where some Bundle T will replace this. /// Where some Bundle T will replace this.
#[derive(Component, Reflect)] #[derive(Component, Reflect)]
pub struct SpawnPoint<T: Bundle> { pub struct SpawnPoint {
pub at: Transform, pub at: Transform,
pub what: T,
} }
pub fn add_all_spawners(application: &mut App) { pub fn add_all_spawners(application: &mut App) {
application.add_systems( application.add_systems(
Update, Update,
(player_spawner, item_spawner::<M4a1GunItem>).after(change_equipment), (player_spawner, item_spawner),
); );
} }

View File

@ -0,0 +1,18 @@
use bevy::prelude::*;
use crate::{setup::spawners::item::ItemSpawnPoint, comps::core::items::{guns::m4a1::M4a1GunItem, item::Item}};
#[derive(Component)]
pub struct M4a1SpawnPoint {
pub transform: Transform,
}
impl ItemSpawnPoint for M4a1SpawnPoint {
fn get_transform(&self) -> Transform {
self.transform
}
fn get_item(&self) -> Box<dyn Item> {
Box::new(M4a1GunItem)
}
}

View File

@ -0,0 +1 @@
pub mod m4a1_spawner;

View File

@ -1,22 +1,37 @@
use bevy::{gltf::Gltf, prelude::*}; use bevy::{prelude::*, gltf::Gltf};
use crate::{ use crate::{setup::{load_state::GameLoadState, assets::GltfAssets, spawners::guns::m4a1_spawner::M4a1SpawnPoint}, comps::core::items::item::Item};
comps::core::items::{guns::m4a1::M4a1GunItem, item::Item},
setup::{assets::GltfAssets, load_state::GameLoadState, spawn::SpawnPoint},
};
pub fn item_spawner<T: Item>( #[bevy_trait_query::queryable]
pub trait ItemSpawnPoint {
fn get_transform(&self) -> Transform;
fn get_item(&self) -> Box<dyn Item>;
}
pub fn item_spawner(
mut commands: Commands, mut commands: Commands,
item_sp_query: Query<(Entity, &SpawnPoint<T>)>, item_sp_query: Query<(Entity, &dyn ItemSpawnPoint)>,
game_load_state: ResMut<GameLoadState>, game_load_state: ResMut<GameLoadState>,
assets_gltf: Res<GltfAssets>, assets_gltf: Res<GltfAssets>,
loaded_gltf_assets: Res<Assets<Gltf>>, loaded_gltf_assets: Res<Assets<Gltf>>,
) { ) {
if game_load_state.is_everything_except_player_loaded() { if game_load_state.is_everything_except_player_loaded() {
for (entity, item_sp) in item_sp_query.iter() { for (entity, item_sp_entity) in item_sp_query.iter() {
let m4 = M4a1GunItem; for component_sp in item_sp_entity {
m4.spawn(&mut commands, item_sp.at, &assets_gltf, &loaded_gltf_assets); println!("Spawning item");
component_sp.get_item().spawn(&mut commands, component_sp.get_transform(), &assets_gltf, &loaded_gltf_assets)
}
//m4.spawn(&mut commands, item_sp.at, &assets_gltf, &loaded_gltf_assets);
commands.entity(entity).despawn(); commands.entity(entity).despawn();
} }
} }
} }
pub struct ItemSpawnPointPlugin;
impl Plugin for ItemSpawnPointPlugin {
fn build(&self, app: &mut App) {
use bevy_trait_query::RegisterExt;
app
.register_component_as::<dyn ItemSpawnPoint, M4a1SpawnPoint>();
}
}

View File

@ -1,2 +1,4 @@
pub mod item; pub mod item;
pub mod player; pub mod player;
pub mod spawn_point;
pub mod guns;

View File

@ -16,13 +16,25 @@ use crate::{
setup::{equipment::EquipmentChangeEvent, load_state::GameLoadState}, setup::{equipment::EquipmentChangeEvent, load_state::GameLoadState},
}; };
use crate::setup::spawn::SpawnPoint; use super::spawn_point::SpawnPoint;
#[derive(Component)]
pub struct PlayerSpawnPoint {
pub transform: Transform,
pub player: Player,
}
impl SpawnPoint for PlayerSpawnPoint {
fn get_transform(&self) -> Transform {
self.transform
}
}
/// System that runs every fame checking if player has been spawned. /// System that runs every fame checking if player has been spawned.
/// For player to spawn, everything inside GameLoadState must be loaded Except player. /// For player to spawn, everything inside GameLoadState must be loaded Except player.
pub fn player_spawner( pub fn player_spawner(
mut commands: Commands, mut commands: Commands,
player_sp_query: Query<(Entity, &SpawnPoint<Player>)>, player_sp_query: Query<(Entity, &PlayerSpawnPoint)>,
mut game_load_state: ResMut<GameLoadState>, mut game_load_state: ResMut<GameLoadState>,
mut equipment_change_event_writer: EventWriter<EquipmentChangeEvent>, mut equipment_change_event_writer: EventWriter<EquipmentChangeEvent>,
player_values_state: Res<PlayerValuesState>, player_values_state: Res<PlayerValuesState>,
@ -72,7 +84,7 @@ pub fn player_spawner(
combine_rule: CoefficientCombineRule::Multiply, combine_rule: CoefficientCombineRule::Multiply,
}) })
.insert(TransformBundle { .insert(TransformBundle {
local: player_spawn_point.at, local: player_spawn_point.get_transform(),
..Default::default() ..Default::default()
}) })
.insert(Velocity::zero()) .insert(Velocity::zero())
@ -106,7 +118,7 @@ pub fn player_spawner(
game_load_state.player_loaded = true; game_load_state.player_loaded = true;
equipment_change_event_writer.send(EquipmentChangeEvent( equipment_change_event_writer.send(EquipmentChangeEvent(
player_spawn_point.what.0.equipment.clone(), player_spawn_point.player.0.equipment.clone()
)); ));
commands.entity(player_spawn_point_entity).despawn(); commands.entity(player_spawn_point_entity).despawn();
} }

View File

@ -0,0 +1,18 @@
use bevy::prelude::*;
use crate::setup::spawners::player::PlayerSpawnPoint;
#[bevy_trait_query::queryable]
pub trait SpawnPoint {
fn get_transform(&self) -> Transform;
}
pub struct SpawnPointPlugin;
impl Plugin for SpawnPointPlugin {
fn build(&self, app: &mut App) {
use bevy_trait_query::RegisterExt;
app.
register_component_as::<dyn SpawnPoint, PlayerSpawnPoint>();
}
}

View File

@ -1,6 +1,6 @@
use bevy::prelude::*; use bevy::prelude::*;
use crate::comps::core::events::loot_container::LootContainerEvent; //use crate::comps::core::events::loot_container::LootContainerEvent;
/// # Inventory Screen /// # Inventory Screen
/// Should contain player inventory and if player is looting something as well /// Should contain player inventory and if player is looting something as well
@ -8,9 +8,7 @@ pub fn setup_inventory_screen(mut commands: Commands) {}
pub fn update_inventory_screen( pub fn update_inventory_screen(
mut commands: Commands, mut commands: Commands,
mut event_reader: EventReader<LootContainerEvent>, //mut event_reader: EventReader<LootContainerEvent>,
) { ) {
for loot_container_event in event_reader.read() {
//let a = loot_container_event.0.clone();
}
} }

View File

@ -1,6 +1,6 @@
use bevy::prelude::*; use bevy::prelude::*;
use crate::comps::core::events::loot_container::LootContainerEvent; //use crate::comps::core::events::loot_container::LootContainerEvent;
use super::menu::{setup_inventory_screen, update_inventory_screen}; use super::menu::{setup_inventory_screen, update_inventory_screen};
@ -8,7 +8,7 @@ pub struct InventoryMenuPlugin;
impl Plugin for InventoryMenuPlugin { impl Plugin for InventoryMenuPlugin {
fn build(&self, app: &mut App) { fn build(&self, app: &mut App) {
app.add_event::<LootContainerEvent>(); //app.add_event::<LootContainerEvent>();
app.add_systems(Startup, setup_inventory_screen); app.add_systems(Startup, setup_inventory_screen);
app.add_systems(Update, update_inventory_screen); app.add_systems(Update, update_inventory_screen);
} }