almost done
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
use bevy::prelude::*;
|
||||
|
||||
mod objects;
|
||||
pub mod objects;
|
||||
mod ui;
|
||||
|
||||
#[derive(Component)]
|
||||
|
||||
@@ -2,16 +2,26 @@ use bevy::prelude::*;
|
||||
use bevy_rapier3d::prelude::ColliderDisabled;
|
||||
|
||||
use crate::{
|
||||
level_instantiation::Door, player::{toolbar::Item, Player, PlayerAction}, util::single_mut
|
||||
level_instantiation::Door,
|
||||
player::{Player, PlayerAction, toolbar::Item},
|
||||
util::single_mut,
|
||||
};
|
||||
|
||||
use super::{Interact, ui::InteractionOpportunity};
|
||||
#[derive(Component, Clone, Copy)]
|
||||
pub struct PickUpAble;
|
||||
|
||||
#[derive(Component, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
|
||||
struct KeyCardId(u64);
|
||||
pub struct KeyCardId(pub usize);
|
||||
|
||||
#[derive(Component, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
|
||||
struct OpenedByKey(KeyCardId);
|
||||
pub struct OpenedByKey(pub KeyCardId);
|
||||
|
||||
impl OpenedByKey {
|
||||
pub fn can_be_opened_by(&self, card: KeyCardId) -> bool {
|
||||
self.0 == card
|
||||
}
|
||||
}
|
||||
|
||||
pub fn plugin(_app: &mut App) {}
|
||||
|
||||
@@ -19,28 +29,33 @@ pub fn handle_pick_up(
|
||||
mut commands: Commands,
|
||||
// current action
|
||||
mut player_query: Query<(&PlayerAction, &Transform, &mut Item), With<Player>>,
|
||||
mut vis_query: Query<&mut Visibility>,
|
||||
mut vis_query: Query<&mut Visibility, With<PickUpAble>>,
|
||||
children: Query<&mut Children>,
|
||||
|
||||
mut item_transform: Query<&mut Transform, (With<Interact>, Without<Player>)>,
|
||||
mut item_transform: Query<&mut Transform, (With<Interact>, Without<Player>, With<PickUpAble>)>,
|
||||
// current interactable
|
||||
mut interaction_opportunity: ResMut<InteractionOpportunity>,
|
||||
) {
|
||||
let (action, transform, mut item) = single_mut!(player_query);
|
||||
if *action == PlayerAction::PickUp {
|
||||
let (PlayerAction::PickUp, transform, mut item) = single_mut!(player_query) else {
|
||||
return;
|
||||
};
|
||||
// take out the interaction, because we are picking it up
|
||||
let Some(target) = interaction_opportunity.0.take() else {
|
||||
return;
|
||||
};
|
||||
let replaced = item.set_item(target);
|
||||
if let Ok(mut vis) = vis_query.get_mut(target) {
|
||||
// check if it is pickable and set visibility
|
||||
let Ok(mut vis) = vis_query.get_mut(target) else {
|
||||
return;
|
||||
};
|
||||
*vis = Visibility::Hidden;
|
||||
}
|
||||
|
||||
// change colliders
|
||||
if let Ok(colliders) = children.get(target) {
|
||||
for &collider in colliders {
|
||||
commands.entity(collider).insert(ColliderDisabled);
|
||||
}
|
||||
}
|
||||
let replaced = item.set_item(target);
|
||||
if let Some(dropped) = replaced {
|
||||
if let Ok(mut vis) = vis_query.get_mut(dropped) {
|
||||
*vis = Visibility::Visible;
|
||||
@@ -54,7 +69,6 @@ pub fn handle_pick_up(
|
||||
let mut item_transform = item_transform.get_mut(dropped).unwrap();
|
||||
*item_transform = *transform;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn handle_drop(
|
||||
@@ -65,8 +79,9 @@ pub fn handle_drop(
|
||||
mut item_transform: Query<&mut Transform, (With<Interact>, Without<Player>)>,
|
||||
children: Query<&mut Children>,
|
||||
) {
|
||||
let (action, transform, mut item) = single_mut!(player_query);
|
||||
if *action == PlayerAction::Drop {
|
||||
let (PlayerAction::Drop, transform, mut item) = single_mut!(player_query) else {
|
||||
return;
|
||||
};
|
||||
let Some(item) = item.take() else {
|
||||
return;
|
||||
};
|
||||
@@ -82,20 +97,35 @@ pub fn handle_drop(
|
||||
// for simplicities sake, set the transform of the item that is dropped to that of the player
|
||||
let mut item_transform = item_transform.get_mut(item).unwrap();
|
||||
*item_transform = *transform;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn handle_door_interaction(
|
||||
player_query: Query<&PlayerAction, With<Player>>, mut doors: Query<&mut Door>
|
||||
mut commands: Commands,
|
||||
player_query: Query<(&PlayerAction, &Item), With<Player>>,
|
||||
card_query: Query<&KeyCardId>,
|
||||
// current interactable
|
||||
interaction_opportunity: ResMut<InteractionOpportunity>,
|
||||
door_query: Query<(Entity, &OpenedByKey), With<Interact>>,
|
||||
) {
|
||||
let Ok(action) = player_query.get_single() else {
|
||||
// the card
|
||||
let Ok((PlayerAction::OpenDoor, item)) = player_query.get_single() else {
|
||||
return;
|
||||
};
|
||||
if *action != PlayerAction::OpenDoor {
|
||||
let Some(current_card) = item.inner().and_then(|e| card_query.get(e).ok()) else {
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
for mut door in doors.iter_mut() {
|
||||
door.is_open = !door.is_open;
|
||||
// the door
|
||||
let Some((door, door_keyhole)) = interaction_opportunity
|
||||
.0
|
||||
.and_then(|e| door_query.get(e).ok())
|
||||
else {
|
||||
return;
|
||||
};
|
||||
|
||||
if door_keyhole.can_be_opened_by(*current_card) {
|
||||
commands.entity(door).despawn_recursive();
|
||||
// unwrap is safe because of the item.inner().and_then
|
||||
commands.entity(item.inner().unwrap()).despawn_recursive();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use crate::GameState;
|
||||
use crate::player::Player;
|
||||
use crate::util::single;
|
||||
use crate::{GameState, level_instantiation::Door};
|
||||
use bevy::{prelude::*, window::PrimaryWindow};
|
||||
use bevy_egui::{EguiContexts, EguiPlugin, egui};
|
||||
use bevy_rapier3d::prelude::*;
|
||||
@@ -17,7 +17,11 @@ pub(super) fn plugin(app: &mut App) {
|
||||
(
|
||||
update_interaction_opportunities,
|
||||
display_interaction_prompt,
|
||||
(objects::handle_pick_up, objects::handle_drop, objects::handle_door_interaction),
|
||||
(
|
||||
objects::handle_pick_up,
|
||||
objects::handle_drop,
|
||||
objects::handle_door_interaction,
|
||||
),
|
||||
)
|
||||
.chain()
|
||||
.run_if(in_state(GameState::Playing)),
|
||||
@@ -68,17 +72,19 @@ fn display_interaction_prompt(
|
||||
interaction_opportunity: Res<InteractionOpportunity>,
|
||||
mut egui_contexts: EguiContexts,
|
||||
primary_windows: Query<&Window, With<PrimaryWindow>>,
|
||||
names: Query<&Name, With<Interact>>, // only the interactables ofcourse
|
||||
names: Query<(&Name, Option<&Door>), With<Interact>>, // only the interactables ofcourse
|
||||
) {
|
||||
let Some(opportunity) = interaction_opportunity.0 else {
|
||||
return;
|
||||
};
|
||||
let window = single!(primary_windows);
|
||||
|
||||
let entity_name = names
|
||||
.get(opportunity)
|
||||
.map(|name| name.as_str())
|
||||
.expect("A named Interactable object");
|
||||
let Ok(interaction_str) = names.get(opportunity).map(|(name, door)| match door {
|
||||
Some(_) => "T: Open Door".into(),
|
||||
None => format!("E: Pick Up {name}"),
|
||||
}) else {
|
||||
return;
|
||||
};
|
||||
|
||||
// objective or item
|
||||
egui::Window::new("Interaction")
|
||||
@@ -87,6 +93,6 @@ fn display_interaction_prompt(
|
||||
.auto_sized()
|
||||
.fixed_pos(egui::Pos2::new(window.width() / 2., window.height() / 2.))
|
||||
.show(egui_contexts.ctx_mut(), |ui| {
|
||||
ui.label(format!("E: Pick Up {entity_name}"));
|
||||
ui.label(interaction_str);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -5,7 +5,13 @@ use bevy_rapier3d::prelude::*;
|
||||
use rand::{Rng, seq::IteratorRandom};
|
||||
|
||||
use crate::{
|
||||
asset_loading::{GltfAssets, ImageAssets}, interaction::Interact, player::{toolbar::ItemIcon, Player, PlayerAction}, GameState
|
||||
GameState,
|
||||
asset_loading::{GltfAssets, ImageAssets},
|
||||
interaction::{
|
||||
Interact,
|
||||
objects::{KeyCardId, OpenedByKey, PickUpAble},
|
||||
},
|
||||
player::{Player, PlayerAction, toolbar::ItemIcon},
|
||||
};
|
||||
|
||||
pub fn map_plugin(app: &mut App) {
|
||||
@@ -593,7 +599,9 @@ fn spawn_objects(
|
||||
.spawn((
|
||||
transform,
|
||||
Interact,
|
||||
PickUpAble,
|
||||
RigidBody::Dynamic,
|
||||
KeyCardId(i),
|
||||
Name::new(format!("Id Card {i}")),
|
||||
Visibility::Visible,
|
||||
ItemIcon::new(image_assets.id_card.clone()),
|
||||
@@ -624,7 +632,7 @@ fn spawn_objects(
|
||||
pub struct Door {
|
||||
pub is_open: bool,
|
||||
pub open_direction: (i32, i32),
|
||||
pub position: (i32, i32)
|
||||
pub position: (i32, i32),
|
||||
}
|
||||
|
||||
fn spawn_doors(
|
||||
@@ -644,33 +652,46 @@ fn spawn_doors(
|
||||
let asset = gltf.default_scene.as_ref().unwrap();
|
||||
let scene_root = SceneRoot(asset.clone());
|
||||
|
||||
for level in levels.levels.iter() {
|
||||
for (i, level) in levels.levels.iter().enumerate() {
|
||||
let (x, z) = level.end_node;
|
||||
let (direction, transform) = if x >= z {
|
||||
(
|
||||
(0, 1),
|
||||
Transform::from_xyz(2.0 * x as f32, 0.0, -2.0 * z as f32)
|
||||
.with_rotation(Quat::from_rotation_y(90.0_f32.to_radians()))
|
||||
.with_rotation(Quat::from_rotation_y(90.0_f32.to_radians())),
|
||||
)
|
||||
} else {
|
||||
(
|
||||
(1, 0),
|
||||
Transform::from_xyz(2.0 * x as f32, 0.0, -2.0 * z as f32)
|
||||
Transform::from_xyz(2.0 * x as f32, 0.0, -2.0 * z as f32),
|
||||
)
|
||||
};
|
||||
commands.spawn((
|
||||
commands
|
||||
.spawn((
|
||||
// very scuff but need this
|
||||
OpenedByKey(KeyCardId(i)),
|
||||
Interact,
|
||||
RigidBody::Fixed,
|
||||
Name::new("Door"),
|
||||
Door {
|
||||
is_open: false,
|
||||
open_direction: direction,
|
||||
position: (x, z)
|
||||
position: (x, z),
|
||||
},
|
||||
transform,
|
||||
scene_root.clone(),
|
||||
)).with_children(|parent| {
|
||||
))
|
||||
.with_children(|parent| {
|
||||
for (collider, transform) in collider.clone() {
|
||||
parent.spawn((collider, transform));
|
||||
}
|
||||
// make it "interactable" in the world
|
||||
parent.spawn((
|
||||
ActiveEvents::COLLISION_EVENTS,
|
||||
Transform::default(),
|
||||
Collider::ball(0.5), // Interaction radius
|
||||
Sensor,
|
||||
));
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -679,8 +700,7 @@ fn handle_door_pos(mut query: Query<(&Door, &mut Transform)>) {
|
||||
for (door, mut transform) in query.iter_mut() {
|
||||
if door.is_open {
|
||||
transform.translation.y = 2.0
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
transform.translation.y = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
use bevy::{
|
||||
input::mouse::AccumulatedMouseMotion, pbr::VolumetricFog, prelude::*, render::view::RenderLayers, window::{PrimaryWindow, WindowResized}
|
||||
input::mouse::AccumulatedMouseMotion,
|
||||
pbr::VolumetricFog,
|
||||
prelude::*,
|
||||
render::view::RenderLayers,
|
||||
window::{PrimaryWindow, WindowResized},
|
||||
};
|
||||
use bevy_kira_audio::{Audio, AudioControl};
|
||||
use bevy_rapier3d::prelude::*;
|
||||
@@ -291,7 +295,7 @@ pub fn handle_input(
|
||||
if keyboard_input.just_pressed(KeyCode::KeyF) {
|
||||
*action = PlayerAction::ToggleFlashlight;
|
||||
}
|
||||
if keyboard_input.just_pressed(KeyCode::KeyK) {
|
||||
if keyboard_input.just_pressed(KeyCode::KeyT) {
|
||||
*action = PlayerAction::OpenDoor;
|
||||
}
|
||||
|
||||
|
||||
@@ -13,6 +13,10 @@ impl Item {
|
||||
pub fn take(&mut self) -> Option<Entity> {
|
||||
self.0.take()
|
||||
}
|
||||
|
||||
pub fn inner(&self) -> Option<Entity> {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Component, Default, Debug)]
|
||||
|
||||
Reference in New Issue
Block a user