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",
]
[[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]]
name = "bevy_a11y"
version = "0.12.0"
@ -1885,6 +1910,7 @@ version = "0.1.0"
dependencies = [
"bevy",
"bevy-inspector-egui",
"bevy-trait-query",
"bevy_editor_pls",
"bevy_hanabi",
"bevy_rapier3d",

View File

@ -20,3 +20,4 @@ bevy-inspector-egui = "0.21.0"
bevy_editor_pls = "0.6"
bevy_rapier3d = { path = "../bevy_rapier/bevy_rapier3d", features = ["debug-render-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;

View File

@ -1,4 +1,8 @@
use std::sync::Arc;
use bevy::prelude::*;
use crate::comps::core::items::item::Item;
#[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 super::inventory_item::InventoryItem;
@ -19,7 +17,7 @@ impl AnyInventory {
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?
// Does position + item size exceed bounds?
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));
}
// 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);
for inventory_item in self.items.iter() {
if inventory_item.is_in_range(&spots_to_occupy) {
@ -44,7 +42,7 @@ impl AnyInventory {
}
pub fn get_spots_from_item_at_pos(
position: UGrid,
item: &impl Item<Storage = SparseStorage>,
item: &impl Item,
) -> Vec<UGrid> {
let end_position = position + item.inventory_size();
let mut spots = Vec::new();
@ -61,7 +59,7 @@ impl AnyInventory {
pub fn valid_item_and_size_for_inventory(
&self,
position: UGrid,
item: &impl Item<Storage = SparseStorage>,
item: &impl Item,
) -> bool {
let item_bounds = position + item.inventory_size();
!(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)]
pub struct InventoryItem {
item: Arc<dyn Item<Storage = SparseStorage>>,
item: Arc<dyn Item>,
/// Coordinates that this InventoryItem occupies inside an AnyInventory
occupied_spots: Vec<UGrid>,
rotated: Option<bool>,
@ -14,13 +14,13 @@ pub struct InventoryItem {
#[allow(unused)]
impl InventoryItem {
pub fn item(&self) -> &dyn Item<Storage = SparseStorage> {
pub fn item(&self) -> &dyn Item {
self.item.as_ref()
}
pub fn rotated(&self) -> Option<bool> {
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 rotated = item.inventory_rotatable().then(|| false);
Self {

View File

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

View File

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

View File

@ -1,22 +1,20 @@
use bevy::prelude::*;
use crate::comps::core::grid::UGrid;
use super::{any_inventory::AnyInventory, item_inventory::ItemInventory};
use super::item_inventory::ItemInventory;
#[derive(Component)]
pub struct PlayerInventory {
pub primary: ItemInventory,
pub secondary: ItemInventory,
pub backpack: AnyInventory,
pub struct PlayerInventory<'a> {
pub primary: ItemInventory<'a>,
pub secondary: ItemInventory<'a>,
//pub backpack: AnyInventory,
}
impl Default for PlayerInventory {
impl<'a> Default for PlayerInventory<'a> {
fn default() -> Self {
Self {
primary: 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,
}
pub trait Item: Component {
#[bevy_trait_query::queryable]
pub trait Item {
fn get_type(&self) -> ItemType;
fn asset_path(&self) -> &str;
/// 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 crate::comps::core::inventory::any_inventory::AnyInventory;
//use crate::comps::core::inventory::any_inventory::AnyInventory;
#[allow(unused)]
#[derive(Component)]
pub enum Interactable {
Holdable,
Lootable(AnyInventory),
//Lootable(AnyInventory),
Item,
}
@ -16,7 +16,7 @@ impl Display for Interactable {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Interactable::Holdable => write!(f, "Holdable"),
Interactable::Lootable(_) => write!(f, "Lootable"),
//Interactable::Lootable(_) => write!(f, "Lootable"),
Interactable::Item => write!(f, "Item"),
}
}

View File

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

View File

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

View File

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

View File

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

View File

@ -1,22 +1,16 @@
use bevy::prelude::*;
use crate::comps::core::items::{guns::m4a1::M4a1GunItem, item::Item};
use super::{
equipment::change_equipment,
spawners::{item::item_spawner, player::player_spawner},
};
use super::spawners::{item::item_spawner, player::player_spawner};
/// Where some Bundle T will replace this.
#[derive(Component, Reflect)]
pub struct SpawnPoint<T: Bundle> {
pub struct SpawnPoint {
pub at: Transform,
pub what: T,
}
pub fn add_all_spawners(application: &mut App) {
application.add_systems(
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::{
comps::core::items::{guns::m4a1::M4a1GunItem, item::Item},
setup::{assets::GltfAssets, load_state::GameLoadState, spawn::SpawnPoint},
};
use crate::{setup::{load_state::GameLoadState, assets::GltfAssets, spawners::guns::m4a1_spawner::M4a1SpawnPoint}, comps::core::items::item::Item};
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,
item_sp_query: Query<(Entity, &SpawnPoint<T>)>,
item_sp_query: Query<(Entity, &dyn ItemSpawnPoint)>,
game_load_state: ResMut<GameLoadState>,
assets_gltf: Res<GltfAssets>,
loaded_gltf_assets: Res<Assets<Gltf>>,
) {
if game_load_state.is_everything_except_player_loaded() {
for (entity, item_sp) in item_sp_query.iter() {
let m4 = M4a1GunItem;
m4.spawn(&mut commands, item_sp.at, &assets_gltf, &loaded_gltf_assets);
for (entity, item_sp_entity) in item_sp_query.iter() {
for component_sp in item_sp_entity {
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();
}
}
}
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 player;
pub mod spawn_point;
pub mod guns;

View File

@ -16,13 +16,25 @@ use crate::{
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.
/// For player to spawn, everything inside GameLoadState must be loaded Except player.
pub fn player_spawner(
mut commands: Commands,
player_sp_query: Query<(Entity, &SpawnPoint<Player>)>,
player_sp_query: Query<(Entity, &PlayerSpawnPoint)>,
mut game_load_state: ResMut<GameLoadState>,
mut equipment_change_event_writer: EventWriter<EquipmentChangeEvent>,
player_values_state: Res<PlayerValuesState>,
@ -72,7 +84,7 @@ pub fn player_spawner(
combine_rule: CoefficientCombineRule::Multiply,
})
.insert(TransformBundle {
local: player_spawn_point.at,
local: player_spawn_point.get_transform(),
..Default::default()
})
.insert(Velocity::zero())
@ -106,7 +118,7 @@ pub fn player_spawner(
game_load_state.player_loaded = true;
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();
}

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 crate::comps::core::events::loot_container::LootContainerEvent;
//use crate::comps::core::events::loot_container::LootContainerEvent;
/// # Inventory Screen
/// 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(
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 crate::comps::core::events::loot_container::LootContainerEvent;
//use crate::comps::core::events::loot_container::LootContainerEvent;
use super::menu::{setup_inventory_screen, update_inventory_screen};
@ -8,7 +8,7 @@ pub struct InventoryMenuPlugin;
impl Plugin for InventoryMenuPlugin {
fn build(&self, app: &mut App) {
app.add_event::<LootContainerEvent>();
//app.add_event::<LootContainerEvent>();
app.add_systems(Startup, setup_inventory_screen);
app.add_systems(Update, update_inventory_screen);
}