Inspectable UI and functionality done. Working on Optic pos persistence

This commit is contained in:
Franklin 2023-11-24 12:43:01 -04:00
parent fa481130b0
commit 223d81d8f7
11 changed files with 256 additions and 34 deletions

View File

@ -24,8 +24,9 @@ Multiplayer
- [x] Issue with moving around quickly
- [x] Bring Crouching back
- [x] Inspect animation & state (procedural)
- [ ] TODO: Attachment editor system when in inspect mode
- [ ] TODO: remove Start and End optic from Slots, instead make one slot, and have code that checks for the starter slot and the end slot
- [x] Attachment editor system when in inspect mode
- [x] remove Start and End optic from Slots, instead make one slot, and have code that checks for the starter slot and the end slot
- [ ] SightSlot not retaining position when dropped or switched.
- [x] High Ready & Low Ready system with state
- [x] High ready animation (procedural)
- [x] Low ready animation (procedural)

View File

@ -5,5 +5,16 @@
/// - Aim Speed
/// -
pub trait Attachment {
/// Starts at 1
fn current_attachment_index(&self) -> u32;
fn all_attachments() -> Vec<Self> where Self: Sized;
}
/// Used to switch attachments.
///
/// - Next == Next attachment
/// - Previous == Previous attachment
pub enum Position {
Next,
Previous,
}

View File

@ -1,9 +1,23 @@
use bevy::{reflect::{Reflect, std_traits::ReflectDefault}, ecs::{component::Component, reflect::ReflectComponent}};
use super::attachment::Attachment;
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Reflect, Component, Debug, Default)]
#[reflect(Component, Default)]
pub enum Compensator {
#[default]
FirstCompensator,
}
impl Attachment for Compensator {
fn current_attachment_index(&self) -> u32 {
match self {
Compensator::FirstCompensator => 1,
}
}
fn all_attachments() -> Vec<Self> where Self: Sized {
Vec::from([Self::FirstCompensator])
}
}

View File

@ -1,9 +1,23 @@
use bevy::{reflect::{Reflect, std_traits::ReflectDefault}, ecs::{component::Component, reflect::ReflectComponent}};
use super::attachment::Attachment;
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Reflect, Component, Debug, Default)]
#[reflect(Component, Default)]
pub enum ForeGrip {
#[default]
Pk5,
}
impl Attachment for ForeGrip {
fn current_attachment_index(&self) -> u32 {
match self {
ForeGrip::Pk5 => 1,
}
}
fn all_attachments() -> Vec<Self> where Self: Sized {
Vec::from([Self::Pk5])
}
}

View File

@ -2,6 +2,8 @@ use bevy::{reflect::{Reflect, std_traits::ReflectDefault}, ecs::{component::Comp
use crate::comps::core::weapons::magazine_data::MagazineData;
use super::attachment::Attachment;
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Reflect, Component, Debug, Default)]
#[reflect(Component, Default)]
@ -19,4 +21,16 @@ impl Magazine {
Magazine::Ak105 => 30,
}
}
}
impl Attachment for Magazine {
fn current_attachment_index(&self) -> u32 {
match self {
Self::Ak105 => 1,
}
}
fn all_attachments() -> Vec<Self> where Self: Sized {
Vec::from([Self::Ak105])
}
}

View File

@ -1,9 +1,23 @@
use bevy::{reflect::{Reflect, std_traits::ReflectDefault}, ecs::{component::Component, reflect::ReflectComponent}};
use super::attachment::Attachment;
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Reflect, Component, Debug, Default)]
#[reflect(Component, Default)]
pub enum Optic {
#[default]
AimpointT1,
}
impl Attachment for Optic {
fn current_attachment_index(&self) -> u32 {
match self {
Self::AimpointT1 => 1,
}
}
fn all_attachments() -> Vec<Self> where Self: Sized {
Vec::from([Self::AimpointT1])
}
}

View File

@ -1,9 +1,23 @@
use bevy::{reflect::{Reflect, std_traits::ReflectDefault}, ecs::{component::Component, reflect::ReflectComponent}};
use super::attachment::Attachment;
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Reflect, Component, Debug, Default)]
#[reflect(Component, Default)]
pub enum Silencer {
#[default]
FirstSilencer
}
impl Attachment for Silencer {
fn current_attachment_index(&self) -> u32 {
match self {
Self::FirstSilencer => 1,
}
}
fn all_attachments() -> Vec<Self> where Self: Sized {
Vec::from([Self::FirstSilencer])
}
}

View File

@ -1,9 +1,23 @@
use bevy::{reflect::{Reflect, std_traits::ReflectDefault}, ecs::{component::Component, reflect::ReflectComponent}};
use super::attachment::Attachment;
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Reflect, Component, Debug, Default)]
#[reflect(Component, Default)]
pub enum Stock {
#[default]
MagpullTan,
}
impl Attachment for Stock {
fn current_attachment_index(&self) -> u32 {
match self {
Self::MagpullTan => 1,
}
}
fn all_attachments() -> Vec<Self> where Self: Sized {
Vec::from([Self::MagpullTan])
}
}

View File

@ -2,7 +2,7 @@ use bevy::prelude::*;
use crate::comps::core::weapons::{attachment_slot::AttachmentSlot, slot::slot::WeaponSlot};
use super::{compensator::Compensator, magazine::Magazine, stock::Stock, foregrip::ForeGrip, optic::Optic};
use super::{compensator::Compensator, magazine::Magazine, stock::Stock, foregrip::ForeGrip, optic::Optic, attachment::{Attachment, Position}};
#[derive(Component, PartialEq, Eq, PartialOrd, Ord, Clone, Reflect, Debug)]
#[reflect(Component, Default)]
@ -67,4 +67,73 @@ impl WeaponAttachment {
WeaponAttachment::Optic(_) => slot == &WeaponSlot::SightSlot,
}
}
/* */
pub fn next_attachment(&self) -> Self {
match self {
WeaponAttachment::Compensator(compensator) => {
let next_index = compensator.current_attachment_index() + 1;
let all_compensators = Compensator::all_attachments();
WeaponAttachment::Compensator(if next_index > all_compensators.len() as u32 { all_compensators.get(0).unwrap().clone() } else { all_compensators.get((next_index - 1) as usize).unwrap().clone() })
},
WeaponAttachment::Magazine(magazine) => {
let next_index = magazine.current_attachment_index() + 1;
let all_magazines = Magazine::all_attachments();
WeaponAttachment::Magazine(if next_index > all_magazines.len() as u32 { all_magazines.get(0).unwrap().clone() } else { all_magazines.get((next_index - 1) as usize).unwrap().clone() })
},
WeaponAttachment::Stock(stock) => {
let next_index = stock.current_attachment_index() + 1;
let all_stocks = Stock::all_attachments();
WeaponAttachment::Stock(if next_index > all_stocks.len() as u32 { all_stocks.get(0).unwrap().clone() } else { all_stocks.get((next_index - 1) as usize).unwrap().clone() })
},
WeaponAttachment::ForeGrip(foregrip) => {
let next_index = foregrip.current_attachment_index() + 1;
let all_foregrips = ForeGrip::all_attachments();
WeaponAttachment::ForeGrip(if next_index > all_foregrips.len() as u32 { all_foregrips.get(0).unwrap().clone() } else { all_foregrips.get((next_index - 1) as usize).unwrap().clone() })
},
WeaponAttachment::Optic(optic) => {
let next_index = optic.current_attachment_index() + 1;
let all_optics = Optic::all_attachments();
WeaponAttachment::Optic(if next_index > all_optics.len() as u32 { all_optics.get(0).unwrap().clone() } else { all_optics.get((next_index - 1) as usize).unwrap().clone() })
},
}
}
pub fn previous_attachment(&self) -> Self {
match self {
WeaponAttachment::Compensator(compensator) => {
let next_index = compensator.current_attachment_index() - 1;
let all_compensators = Compensator::all_attachments();
WeaponAttachment::Compensator(if next_index == 0 { all_compensators.get(all_compensators.len() - 1).unwrap().clone() } else { all_compensators.get((next_index - 1) as usize).unwrap().clone() })
},
WeaponAttachment::Magazine(magazine) => {
let next_index = magazine.current_attachment_index() - 1;
let all_magazines = Magazine::all_attachments();
WeaponAttachment::Magazine(if next_index == 0 { all_magazines.get(all_magazines.len() - 1).unwrap().clone() } else { all_magazines.get((next_index - 1) as usize).unwrap().clone() })
},
WeaponAttachment::Stock(stock) => {
let next_index = stock.current_attachment_index() - 1;
let all_stocks = Stock::all_attachments();
WeaponAttachment::Stock(if next_index == 0 { all_stocks.get(all_stocks.len() - 1).unwrap().clone() } else { all_stocks.get((next_index - 1) as usize).unwrap().clone() })
},
WeaponAttachment::ForeGrip(foregrip) => {
let next_index = foregrip.current_attachment_index() - 1;
let all_foregrips = ForeGrip::all_attachments();
WeaponAttachment::ForeGrip(if next_index == 0{ all_foregrips.get(all_foregrips.len() - 1).unwrap().clone() } else { all_foregrips.get((next_index - 1) as usize).unwrap().clone() })
},
WeaponAttachment::Optic(optic) => {
let next_index = optic.current_attachment_index() - 1;
let all_optics = Optic::all_attachments();
WeaponAttachment::Optic(if next_index == 0 { all_optics.get(all_optics.len() - 1).unwrap().clone() } else { all_optics.get((next_index - 1) as usize).unwrap().clone() })
},
}
}
pub fn get_from_slot(slot: &WeaponSlot) -> Option<Self> {
match slot {
WeaponSlot::ForeGripSlot => Some(WeaponAttachment::ForeGrip(Default::default())),
WeaponSlot::MagazineSlot => Some(WeaponAttachment::Magazine(Default::default())),
WeaponSlot::CompensatorSlot => Some(WeaponAttachment::Compensator(Default::default())),
WeaponSlot::SightSlot => Some(WeaponAttachment::Optic(Default::default())),
WeaponSlot::StockSlot => Some(WeaponAttachment::Stock(Default::default())),
WeaponSlot::UtilitySlot => None,
}
}
}

View File

@ -1,16 +1,55 @@
use bevy::prelude::*;
use super::{attachment_slot::AttachmentSlot, slot::slot::WeaponSlot, magazine_data::MagazineData};
use super::{attachment_slot::AttachmentSlot, slot::slot::WeaponSlot, magazine_data::MagazineData, attachments::{weapon_attachment::WeaponAttachment, attachment::Position}};
#[derive(Component, Reflect, PartialEq, Debug, Clone)]
pub struct FirearmState {
pub attachment_slots: Vec<AttachmentSlot>,
pub magazine_data: Option<MagazineData>,
pub optic_pos: Option<Vec3>,
}
impl FirearmState {
pub fn new(attachment_slots: Vec<AttachmentSlot>, magazine_data: Option<MagazineData>) -> Self {
Self { attachment_slots, magazine_data: None }
Self { attachment_slots, magazine_data: None, optic_pos: None }
}
}
/// Call this function when a user requests to switch an attachment in a specific slot.
/// This function assumes you already took the necessary validations regarding if the user has the attachments or not.
///
/// Passing a None value will remove the attachment from the AttachmentSlot with the WeaponSlot specified.
/// Passing a Some(true/false) value will switch the attachment +/- one position
pub fn switch_attachment_by_pos(&mut self, slot: &WeaponSlot, pos_opt: Option<Position>) {
for attachment_slot in self.attachment_slots.iter_mut() {
if &attachment_slot.slot_type == slot {
match pos_opt {
Some(ref pos) => {
match attachment_slot.attachment {
Some(ref attachment) => match pos {
Position::Next => attachment_slot.attachment = Some(attachment.next_attachment()),
Position::Previous => attachment_slot.attachment = Some(attachment.previous_attachment()),
},
None => attachment_slot.attachment = WeaponAttachment::get_from_slot(slot),
}
},
None => attachment_slot.attachment = None,
}
}
}
}
}
/*
Some(add) => {
let add_by = if add { 1 } else { -1 };
match attachment_slot.attachment {
Some(attachment) => ,
None => { // This means there was no attachment there. pass -1 to the from_index() fn. It will return the last one
},
}
},
None => {
attachment_slot.attachment = None;
},
*/

View File

@ -1,16 +1,17 @@
use bevy::{prelude::*, input::mouse::MouseWheel, ecs::system::SystemParam};
use crate::{comps::core::{markers::{proxy::{character::in_player_hands_parent::InPlayerHandsParent, physics::utils::TransformExt, weapons::sight_placement::{SightPlacementStart, SightPlacementEnd}}, player::Player, inspect_screen::InspectScreenSlotUiMarker}, weapons::slot::slot::WeaponSlot}, ui::game::game_ui_state::GameUiState, utils::hierarchy::find_child_in_parent_children};
use crate::{comps::core::{markers::{proxy::{character::in_player_hands_parent::InPlayerHandsParent, physics::utils::TransformExt, weapons::sight_placement::{SightPlacementStart, SightPlacementEnd}}, player::Player, inspect_screen::InspectScreenSlotUiMarker}, weapons::{slot::slot::WeaponSlot, firearm_state::FirearmState, attachments::attachment::Position}}, ui::game::game_ui_state::GameUiState, utils::hierarchy::find_child_in_parent_children};
use super::player_firing::PlayerFiringInfo;
#[derive(SystemParam)]
pub struct InspectFirearmQueryParams<'w, 's> {
children: Query<'w, 's, &'static Children>,
in_player_hands_parent_query: Query<'w, 's, (&'static mut Transform, Entity, &'static Parent), (With<InPlayerHandsParent>, Without<WeaponSlot>, Without<SightPlacementEnd>, Without<SightPlacementStart>)>,
player_firing_info_query: Query<'w, 's, (&'static mut PlayerFiringInfo, Entity), With<Player>>,
in_player_hands_parent_query: Query<'w, 's, (&'static mut Transform, Entity), (With<InPlayerHandsParent>, Without<WeaponSlot>, Without<SightPlacementEnd>, Without<SightPlacementStart>)>,
player_firing_info_query: Query<'w, 's, &'static mut PlayerFiringInfo, With<Player>>,
inspectable_slot_query: Query<'w, 's, &'static mut InspectScreenSlotUiMarker>,
slot_query: Query<'w, 's, (&'static mut Transform, &'static Parent, &'static Children, &'static WeaponSlot), (Without<SightPlacementEnd>, Without<SightPlacementStart>)>,
firearm_query: Query<'w, 's, (Entity, &'static mut FirearmState)>,
slot_query: Query<'w, 's, (&'static mut Transform, &'static Parent, &'static WeaponSlot), (Without<SightPlacementEnd>, Without<SightPlacementStart>)>,
sight_placement_query: Query<'w, 's, (&'static Parent, &'static mut Transform), (Or<(With<SightPlacementStart>, With<SightPlacementEnd>)>, Without<WeaponSlot>)>,
}
@ -22,11 +23,8 @@ pub fn inspect_firearm(
keyboard_input: Res<Input<KeyCode>>,
mut mouse_wheel_events: EventReader<MouseWheel>,
) {
for (mut player_firing_info, player_entity) in queries.player_firing_info_query.iter_mut() {
for (mut in_player_hands_parent_transform, in_player_hands_entity, in_player_hands_parent) in queries.in_player_hands_parent_query.iter_mut() {
//if !find_child_in_parent_children(&mut commands, player_entity, in_player_hands_parent.get(), &queries.children) {
// continue;
//}
for mut player_firing_info in queries.player_firing_info_query.iter_mut() {
for (mut in_player_hands_parent_transform, in_player_hands_entity) in queries.in_player_hands_parent_query.iter_mut() {
if player_firing_info.is_inspecting {
let inspect_hand_transform: Transform = Transform {
translation: Vec3 { x: 0.0, y: -0.1, z: -0.8 },
@ -51,28 +49,44 @@ pub fn inspect_firearm(
}
for mut inspectable_slot in queries.inspectable_slot_query.iter_mut() {
if let Some(selected) = selected { // If user selects a slot
if inspectable_slot.slot.get_index() == selected && inspectable_slot.active {
inspectable_slot.selected = true;
} else {
inspectable_slot.selected = false;
}
inspectable_slot.selected = inspectable_slot.slot.get_index() == selected && inspectable_slot.active;
}
for (mut slot_transform, slot_parent, slot_children, slot) in queries.slot_query.iter_mut() {
if slot != &inspectable_slot.slot { continue; }
for (mut slot_transform, slot_parent, slot) in queries.slot_query.iter_mut() {
if slot != &inspectable_slot.slot || !inspectable_slot.selected { continue; }
if !find_child_in_parent_children(&mut commands, in_player_hands_entity, slot_parent.get(), &queries.children) {
continue;
}
if keyboard_input.just_pressed(KeyCode::A) || keyboard_input.just_pressed(KeyCode::Left) {
} else if keyboard_input.just_pressed(KeyCode::D) || keyboard_input.just_pressed(KeyCode::Right) {
match (keyboard_input.just_pressed(KeyCode::A) || keyboard_input.just_pressed(KeyCode::Left), keyboard_input.just_pressed(KeyCode::D) || keyboard_input.just_pressed(KeyCode::Right)) {
(true, false) => { // -1 to index
for (firearm_entity, mut firearm_state) in queries.firearm_query.iter_mut() {
if !find_child_in_parent_children(&mut commands, in_player_hands_entity, firearm_entity, &queries.children) {
continue;
}
firearm_state.switch_attachment_by_pos(slot, Some(Position::Previous));
}
},
(false, true) => { // +1 to index
for (firearm_entity, mut firearm_state) in queries.firearm_query.iter_mut() {
if !find_child_in_parent_children(&mut commands, in_player_hands_entity, firearm_entity, &queries.children) {
continue;
}
firearm_state.switch_attachment_by_pos(slot, Some(Position::Next));
}
},
_ => {} // On no press or both pressed, do nothing
};
if keyboard_input.just_pressed(KeyCode::Back) {
for (firearm_entity, mut firearm_state) in queries.firearm_query.iter_mut() {
if !find_child_in_parent_children(&mut commands, in_player_hands_entity, firearm_entity, &queries.children) {
continue;
}
firearm_state.switch_attachment_by_pos(slot, None);
if slot == &WeaponSlot::SightSlot {
firearm_state.optic_pos = None;
}
}
}
if inspectable_slot.slot == WeaponSlot::SightSlot && inspectable_slot.selected {
println!("sightslot");
if inspectable_slot.slot == WeaponSlot::SightSlot {
// The optic should sit in between these two transforms
let mut pos_1 = None;
let mut pos_2 = None;
@ -85,7 +99,6 @@ pub fn inspect_firearm(
}
}
for mouse_wheel_event in mouse_wheel_events.read() { // TODO: Specifically for optic, scroll wheel == position change
println!("mouse");
match (pos_1, pos_2) {
(None, None) => break,
(None, Some(pos_2)) => { slot_transform.translation = pos_2 },
@ -93,7 +106,12 @@ pub fn inspect_firearm(
(Some(pos_1), Some(pos_2)) => {
let move_sight_by_y = mouse_wheel_event.y * time.delta_seconds() * 1.0;
slot_transform.translation.y = (move_sight_by_y + slot_transform.translation.y).clamp(pos_1.y.min(pos_2.y), pos_1.y.max(pos_2.y));
println!("moved");
for (firearm_entity, mut firearm_state) in queries.firearm_query.iter_mut() {
if !find_child_in_parent_children(&mut commands, in_player_hands_entity, firearm_entity, &queries.children) {
continue;
}
firearm_state.optic_pos = Some(slot_transform.translation);
}
},
};
// TODO: Translate SightSlot transform by mouse_wheel_event.y * time.delta_time_seconds() * sens_multiplier