@@ -1,6 +1,6 @@
|
|||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
|
|
||||||
mod objects;
|
pub mod objects;
|
||||||
mod ui;
|
mod ui;
|
||||||
|
|
||||||
#[derive(Component)]
|
#[derive(Component)]
|
||||||
|
|||||||
@@ -2,52 +2,76 @@ use bevy::prelude::*;
|
|||||||
use bevy_rapier3d::prelude::ColliderDisabled;
|
use bevy_rapier3d::prelude::ColliderDisabled;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
level_instantiation::Door, player::{toolbar::Item, Player, PlayerAction}, util::single_mut
|
player::{Player, PlayerAction, toolbar::Item},
|
||||||
|
util::single_mut,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{Interact, ui::InteractionOpportunity};
|
use super::{Interact, ui::InteractionOpportunity};
|
||||||
|
#[derive(Component, Clone, Copy)]
|
||||||
|
pub struct PickUpAble;
|
||||||
|
|
||||||
pub fn plugin(_app: &mut App) {}
|
#[derive(Component, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
|
||||||
|
pub struct KeyCardId(pub usize);
|
||||||
|
|
||||||
|
#[derive(Component, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
|
||||||
|
pub struct OpenedByKey(pub KeyCardId);
|
||||||
|
|
||||||
|
#[derive(Resource, Default, Clone, Copy)]
|
||||||
|
pub struct WrongKey(pub bool);
|
||||||
|
|
||||||
|
impl OpenedByKey {
|
||||||
|
pub fn can_be_opened_by(&self, card: KeyCardId) -> bool {
|
||||||
|
self.0 == card
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn plugin(app: &mut App) {
|
||||||
|
app.init_resource::<WrongKey>();
|
||||||
|
}
|
||||||
|
|
||||||
pub fn handle_pick_up(
|
pub fn handle_pick_up(
|
||||||
mut commands: Commands,
|
mut commands: Commands,
|
||||||
// current action
|
// current action
|
||||||
mut player_query: Query<(&PlayerAction, &Transform, &mut Item), With<Player>>,
|
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>,
|
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
|
// current interactable
|
||||||
mut interaction_opportunity: ResMut<InteractionOpportunity>,
|
mut interaction_opportunity: ResMut<InteractionOpportunity>,
|
||||||
) {
|
) {
|
||||||
let (action, transform, mut item) = single_mut!(player_query);
|
let (PlayerAction::PickUp, transform, mut item) = single_mut!(player_query) else {
|
||||||
if *action == PlayerAction::PickUp {
|
return;
|
||||||
// take out the interaction, because we are picking it up
|
};
|
||||||
let Some(target) = interaction_opportunity.0.take() else {
|
// take out the interaction, because we are picking it up
|
||||||
return;
|
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
|
||||||
*vis = Visibility::Hidden;
|
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);
|
||||||
}
|
}
|
||||||
if let Ok(colliders) = children.get(target) {
|
}
|
||||||
|
let replaced = item.set_item(target);
|
||||||
|
if let Some(dropped) = replaced {
|
||||||
|
if let Ok(mut vis) = vis_query.get_mut(dropped) {
|
||||||
|
*vis = Visibility::Visible;
|
||||||
|
}
|
||||||
|
if let Ok(colliders) = children.get(dropped) {
|
||||||
for &collider in colliders {
|
for &collider in colliders {
|
||||||
commands.entity(collider).insert(ColliderDisabled);
|
commands.entity(collider).remove::<ColliderDisabled>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Some(dropped) = replaced {
|
// for simplicities sake, set the transform of the item that is dropped to that of the player
|
||||||
if let Ok(mut vis) = vis_query.get_mut(dropped) {
|
let mut item_transform = item_transform.get_mut(dropped).unwrap();
|
||||||
*vis = Visibility::Visible;
|
*item_transform = *transform;
|
||||||
}
|
|
||||||
if let Ok(colliders) = children.get(dropped) {
|
|
||||||
for &collider in colliders {
|
|
||||||
commands.entity(collider).remove::<ColliderDisabled>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 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(dropped).unwrap();
|
|
||||||
*item_transform = *transform;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -59,37 +83,58 @@ pub fn handle_drop(
|
|||||||
mut item_transform: Query<&mut Transform, (With<Interact>, Without<Player>)>,
|
mut item_transform: Query<&mut Transform, (With<Interact>, Without<Player>)>,
|
||||||
children: Query<&mut Children>,
|
children: Query<&mut Children>,
|
||||||
) {
|
) {
|
||||||
let (action, transform, mut item) = single_mut!(player_query);
|
let (PlayerAction::Drop, transform, mut item) = single_mut!(player_query) else {
|
||||||
if *action == PlayerAction::Drop {
|
return;
|
||||||
let Some(item) = item.take() else {
|
};
|
||||||
return;
|
let Some(item) = item.take() else {
|
||||||
};
|
return;
|
||||||
if let Ok(mut vis) = vis_query.get_mut(item) {
|
};
|
||||||
*vis = Visibility::Visible;
|
if let Ok(mut vis) = vis_query.get_mut(item) {
|
||||||
}
|
*vis = Visibility::Visible;
|
||||||
if let Ok(colliders) = children.get(item) {
|
|
||||||
for &collider in colliders {
|
|
||||||
commands.entity(collider).remove::<ColliderDisabled>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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;
|
|
||||||
}
|
}
|
||||||
|
if let Ok(colliders) = children.get(item) {
|
||||||
|
for &collider in colliders {
|
||||||
|
commands.entity(collider).remove::<ColliderDisabled>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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(
|
pub fn handle_door_interaction(
|
||||||
player_query: Query<&PlayerAction, With<Player>>, mut doors: Query<&mut Door>
|
mut commands: Commands,
|
||||||
|
mut player_query: Query<(&PlayerAction, &mut Item), With<Player>>,
|
||||||
|
card_query: Query<&KeyCardId>,
|
||||||
|
mut wrong_key: ResMut<WrongKey>,
|
||||||
|
// 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, mut item)) = player_query.get_single_mut() else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
if *action != PlayerAction::OpenDoor {
|
let Some(current_card) = item.inner().and_then(|e| card_query.get(e).ok()) else {
|
||||||
return;
|
return;
|
||||||
}
|
};
|
||||||
|
|
||||||
for mut door in doors.iter_mut() {
|
// the door
|
||||||
door.is_open = !door.is_open;
|
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();
|
||||||
|
item.take();
|
||||||
|
} else {
|
||||||
|
// wrong key :)
|
||||||
|
wrong_key.0 = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
use crate::GameState;
|
|
||||||
use crate::player::Player;
|
use crate::player::Player;
|
||||||
use crate::util::single;
|
use crate::util::single;
|
||||||
|
use crate::{GameState, level_instantiation::Door};
|
||||||
use bevy::{prelude::*, window::PrimaryWindow};
|
use bevy::{prelude::*, window::PrimaryWindow};
|
||||||
use bevy_egui::{EguiContexts, EguiPlugin, egui};
|
use bevy_egui::{EguiContexts, EguiPlugin, egui};
|
||||||
use bevy_rapier3d::prelude::*;
|
use bevy_rapier3d::prelude::*;
|
||||||
use bevy_rapier3d::rapier::prelude::CollisionEventFlags;
|
use bevy_rapier3d::rapier::prelude::CollisionEventFlags;
|
||||||
use std::iter;
|
use std::iter;
|
||||||
|
|
||||||
|
use super::objects::WrongKey;
|
||||||
use super::{Interact, objects};
|
use super::{Interact, objects};
|
||||||
|
|
||||||
pub(super) fn plugin(app: &mut App) {
|
pub(super) fn plugin(app: &mut App) {
|
||||||
@@ -17,7 +18,11 @@ pub(super) fn plugin(app: &mut App) {
|
|||||||
(
|
(
|
||||||
update_interaction_opportunities,
|
update_interaction_opportunities,
|
||||||
display_interaction_prompt,
|
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()
|
.chain()
|
||||||
.run_if(in_state(GameState::Playing)),
|
.run_if(in_state(GameState::Playing)),
|
||||||
@@ -31,6 +36,7 @@ fn update_interaction_opportunities(
|
|||||||
mut collision_events: EventReader<CollisionEvent>,
|
mut collision_events: EventReader<CollisionEvent>,
|
||||||
player_query: Query<Entity, With<Player>>,
|
player_query: Query<Entity, With<Player>>,
|
||||||
parents: Query<&Parent>,
|
parents: Query<&Parent>,
|
||||||
|
mut wrong_key: ResMut<WrongKey>,
|
||||||
target_query: Query<Entity, (Without<Player>, With<Interact>)>,
|
target_query: Query<Entity, (Without<Player>, With<Interact>)>,
|
||||||
mut interaction_opportunity: ResMut<InteractionOpportunity>,
|
mut interaction_opportunity: ResMut<InteractionOpportunity>,
|
||||||
) {
|
) {
|
||||||
@@ -59,6 +65,8 @@ fn update_interaction_opportunities(
|
|||||||
if started {
|
if started {
|
||||||
interaction_opportunity.0.replace(interactable);
|
interaction_opportunity.0.replace(interactable);
|
||||||
} else {
|
} else {
|
||||||
|
// reset when gone
|
||||||
|
wrong_key.0 = false;
|
||||||
interaction_opportunity.0.take_if(|t| *t == interactable);
|
interaction_opportunity.0.take_if(|t| *t == interactable);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -68,17 +76,20 @@ fn display_interaction_prompt(
|
|||||||
interaction_opportunity: Res<InteractionOpportunity>,
|
interaction_opportunity: Res<InteractionOpportunity>,
|
||||||
mut egui_contexts: EguiContexts,
|
mut egui_contexts: EguiContexts,
|
||||||
primary_windows: Query<&Window, With<PrimaryWindow>>,
|
primary_windows: Query<&Window, With<PrimaryWindow>>,
|
||||||
names: Query<&Name, With<Interact>>, // only the interactables ofcourse
|
wrong_key: Res<WrongKey>,
|
||||||
|
names: Query<(&Name, Option<&Door>), With<Interact>>, // only the interactables ofcourse
|
||||||
) {
|
) {
|
||||||
let Some(opportunity) = interaction_opportunity.0 else {
|
let Some(opportunity) = interaction_opportunity.0 else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
let window = single!(primary_windows);
|
let window = single!(primary_windows);
|
||||||
|
|
||||||
let entity_name = names
|
let Ok(interaction_str) = names.get(opportunity).map(|(name, door)| match door {
|
||||||
.get(opportunity)
|
Some(_) => "T: Open Door".into(),
|
||||||
.map(|name| name.as_str())
|
None => format!("E: Pick Up {name}"),
|
||||||
.expect("A named Interactable object");
|
}) else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
// objective or item
|
// objective or item
|
||||||
egui::Window::new("Interaction")
|
egui::Window::new("Interaction")
|
||||||
@@ -87,6 +98,9 @@ fn display_interaction_prompt(
|
|||||||
.auto_sized()
|
.auto_sized()
|
||||||
.fixed_pos(egui::Pos2::new(window.width() / 2., window.height() / 2.))
|
.fixed_pos(egui::Pos2::new(window.width() / 2., window.height() / 2.))
|
||||||
.show(egui_contexts.ctx_mut(), |ui| {
|
.show(egui_contexts.ctx_mut(), |ui| {
|
||||||
ui.label(format!("E: Pick Up {entity_name}"));
|
ui.label(interaction_str);
|
||||||
|
if wrong_key.0 {
|
||||||
|
ui.label("Wrong Key :)");
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,13 @@ use bevy_rapier3d::prelude::*;
|
|||||||
use rand::{Rng, seq::IteratorRandom};
|
use rand::{Rng, seq::IteratorRandom};
|
||||||
|
|
||||||
use crate::{
|
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) {
|
pub fn map_plugin(app: &mut App) {
|
||||||
@@ -589,11 +595,59 @@ fn spawn_objects(
|
|||||||
} else {
|
} else {
|
||||||
Transform::from_xyz(2.0 * x as f32, 0.5, -2.0 * z as f32)
|
Transform::from_xyz(2.0 * x as f32, 0.5, -2.0 * z as f32)
|
||||||
};
|
};
|
||||||
|
// Correct Key Card
|
||||||
commands
|
commands
|
||||||
.spawn((
|
.spawn((
|
||||||
transform,
|
transform,
|
||||||
Interact,
|
Interact,
|
||||||
|
PickUpAble,
|
||||||
RigidBody::Dynamic,
|
RigidBody::Dynamic,
|
||||||
|
KeyCardId(i),
|
||||||
|
Name::new(format!("Id Card {i}")),
|
||||||
|
Visibility::Visible,
|
||||||
|
ItemIcon::new(image_assets.id_card.clone()),
|
||||||
|
SceneRoot(asset.clone()),
|
||||||
|
))
|
||||||
|
.with_children(|parent| {
|
||||||
|
parent.spawn((
|
||||||
|
ColliderMassProperties::Mass(10.0),
|
||||||
|
Collider::cuboid(0.05, 0.05, 0.01),
|
||||||
|
Transform::from_rotation(Quat::from_euler(
|
||||||
|
EulerRot::XYZ,
|
||||||
|
-10.0f32.to_radians(), // X-axis rotation (tilt)
|
||||||
|
-5.0f32.to_radians(), // Y-axis rotation
|
||||||
|
10.0f32.to_radians(), // Z-axis rotation
|
||||||
|
)),
|
||||||
|
));
|
||||||
|
parent.spawn((
|
||||||
|
ActiveEvents::COLLISION_EVENTS,
|
||||||
|
Transform::default(),
|
||||||
|
Collider::ball(0.5), // Interaction radius
|
||||||
|
Sensor,
|
||||||
|
));
|
||||||
|
});
|
||||||
|
|
||||||
|
// wrong key card
|
||||||
|
let (x, z) = loop {
|
||||||
|
let positions = level.nodes.keys();
|
||||||
|
let random_pos = positions.choose(&mut rand::rng()).unwrap().clone();
|
||||||
|
if random_pos != begin_node && random_pos != end_node {
|
||||||
|
break random_pos;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let transform = if x <= z {
|
||||||
|
Transform::from_xyz(2.0 * x as f32, 0.5, -2.0 * z as f32)
|
||||||
|
.with_rotation(Quat::from_rotation_y(90.0_f32.to_radians()))
|
||||||
|
} else {
|
||||||
|
Transform::from_xyz(2.0 * x as f32, 0.5, -2.0 * z as f32)
|
||||||
|
};
|
||||||
|
commands
|
||||||
|
.spawn((
|
||||||
|
transform,
|
||||||
|
Interact,
|
||||||
|
PickUpAble,
|
||||||
|
RigidBody::Dynamic,
|
||||||
|
KeyCardId(usize::MAX),
|
||||||
Name::new(format!("Id Card {i}")),
|
Name::new(format!("Id Card {i}")),
|
||||||
Visibility::Visible,
|
Visibility::Visible,
|
||||||
ItemIcon::new(image_assets.id_card.clone()),
|
ItemIcon::new(image_assets.id_card.clone()),
|
||||||
@@ -624,7 +678,7 @@ fn spawn_objects(
|
|||||||
pub struct Door {
|
pub struct Door {
|
||||||
pub is_open: bool,
|
pub is_open: bool,
|
||||||
pub open_direction: (i32, i32),
|
pub open_direction: (i32, i32),
|
||||||
pub position: (i32, i32)
|
pub position: (i32, i32),
|
||||||
}
|
}
|
||||||
|
|
||||||
fn spawn_doors(
|
fn spawn_doors(
|
||||||
@@ -644,43 +698,55 @@ fn spawn_doors(
|
|||||||
let asset = gltf.default_scene.as_ref().unwrap();
|
let asset = gltf.default_scene.as_ref().unwrap();
|
||||||
let scene_root = SceneRoot(asset.clone());
|
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 (x, z) = level.end_node;
|
||||||
let (direction, transform) = if x >= z {
|
let (direction, transform) = if x >= z {
|
||||||
(
|
(
|
||||||
(0, 1),
|
(0, 1),
|
||||||
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)
|
||||||
.with_rotation(Quat::from_rotation_y(90.0_f32.to_radians()))
|
.with_rotation(Quat::from_rotation_y(-90.0_f32.to_radians())),
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
(
|
(
|
||||||
(1, 0),
|
(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
|
||||||
RigidBody::Fixed,
|
.spawn((
|
||||||
Door {
|
// very scuff but need this
|
||||||
is_open: false,
|
OpenedByKey(KeyCardId(i)),
|
||||||
open_direction: direction,
|
Interact,
|
||||||
position: (x, z)
|
RigidBody::Fixed,
|
||||||
},
|
Name::new("Door"),
|
||||||
transform,
|
Door {
|
||||||
scene_root.clone(),
|
is_open: false,
|
||||||
)).with_children(|parent| {
|
open_direction: direction,
|
||||||
for (collider, transform) in collider.clone() {
|
position: (x, z),
|
||||||
parent.spawn((collider, transform));
|
},
|
||||||
}
|
transform,
|
||||||
});
|
scene_root.clone(),
|
||||||
|
))
|
||||||
|
.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,
|
||||||
|
));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_door_pos(mut query: Query<(&Door, &mut Transform)>) {
|
fn handle_door_pos(mut query: Query<(&Door, &mut Transform)>) {
|
||||||
for (door, mut transform) in query.iter_mut() {
|
for (door, mut transform) in query.iter_mut() {
|
||||||
if door.is_open {
|
if door.is_open {
|
||||||
transform.translation.y = 2.0
|
transform.translation.y = 2.0
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
transform.translation.y = 0.0;
|
transform.translation.y = 0.0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,9 @@
|
|||||||
use bevy::{
|
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_kira_audio::{Audio, AudioControl};
|
||||||
use bevy_rapier3d::prelude::*;
|
use bevy_rapier3d::prelude::*;
|
||||||
@@ -62,8 +66,7 @@ pub struct Flashlight {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Component)]
|
#[derive(Debug, Component)]
|
||||||
pub struct SpotlightFlashlight {
|
pub struct SpotlightFlashlight {}
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Component)]
|
#[derive(Component)]
|
||||||
pub struct FlashlightButtonAnimation {
|
pub struct FlashlightButtonAnimation {
|
||||||
@@ -91,7 +94,12 @@ pub fn plugin(app: &mut App) {
|
|||||||
apply_head_bob,
|
apply_head_bob,
|
||||||
on_resize_system,
|
on_resize_system,
|
||||||
(handle_flashlight, handle_spotlight).chain(),
|
(handle_flashlight, handle_spotlight).chain(),
|
||||||
(update_flashlight_button_animation, update_flashlight_charge, update_flashlight_sprite).chain(),
|
(
|
||||||
|
update_flashlight_button_animation,
|
||||||
|
update_flashlight_charge,
|
||||||
|
update_flashlight_sprite,
|
||||||
|
)
|
||||||
|
.chain(),
|
||||||
)
|
)
|
||||||
.run_if(in_state(GameState::Playing)),
|
.run_if(in_state(GameState::Playing)),
|
||||||
)
|
)
|
||||||
@@ -159,7 +167,10 @@ pub fn init_player(
|
|||||||
let window = window.single();
|
let window = window.single();
|
||||||
let transform = flashlight_base_transform(window.width(), window.height());
|
let transform = flashlight_base_transform(window.width(), window.height());
|
||||||
parent.spawn((
|
parent.spawn((
|
||||||
Flashlight { charge: 4.0, is_on: false },
|
Flashlight {
|
||||||
|
charge: 4.0,
|
||||||
|
is_on: false,
|
||||||
|
},
|
||||||
Sprite::from_image(flashlights.flash_hold_4.clone()),
|
Sprite::from_image(flashlights.flash_hold_4.clone()),
|
||||||
transform.0.clone(),
|
transform.0.clone(),
|
||||||
transform,
|
transform,
|
||||||
@@ -169,15 +180,15 @@ pub fn init_player(
|
|||||||
|
|
||||||
// feitelijke pitslamp
|
// feitelijke pitslamp
|
||||||
parent.spawn((
|
parent.spawn((
|
||||||
SpotlightFlashlight{},
|
SpotlightFlashlight {},
|
||||||
SpotLight {
|
SpotLight {
|
||||||
intensity: 0.0,
|
intensity: 0.0,
|
||||||
color: Color::srgba(0.9, 0.628, 0.392, 1.0),
|
color: Color::srgba(0.9, 0.628, 0.392, 1.0),
|
||||||
range: 5.0,
|
range: 5.0,
|
||||||
outer_angle: 28.0_f32.to_radians(), // wide cone for flashlight
|
outer_angle: 28.0_f32.to_radians(), // wide cone for flashlight
|
||||||
inner_angle: 12.0_f32.to_radians(), // narrower inner cone
|
inner_angle: 12.0_f32.to_radians(), // narrower inner cone
|
||||||
shadows_enabled: false, // (set to true for realism)
|
shadows_enabled: false, // (set to true for realism)
|
||||||
radius: 0.35, // low value for hard light
|
radius: 0.35, // low value for hard light
|
||||||
..default()
|
..default()
|
||||||
},
|
},
|
||||||
Transform::from_xyz(0.0, -0.15, 0.5),
|
Transform::from_xyz(0.0, -0.15, 0.5),
|
||||||
@@ -300,7 +311,7 @@ pub fn handle_input(
|
|||||||
if keyboard_input.just_pressed(KeyCode::KeyF) {
|
if keyboard_input.just_pressed(KeyCode::KeyF) {
|
||||||
*action = PlayerAction::ToggleFlashlight;
|
*action = PlayerAction::ToggleFlashlight;
|
||||||
}
|
}
|
||||||
if keyboard_input.just_pressed(KeyCode::KeyK) {
|
if keyboard_input.just_pressed(KeyCode::KeyT) {
|
||||||
*action = PlayerAction::OpenDoor;
|
*action = PlayerAction::OpenDoor;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -413,7 +424,7 @@ pub fn handle_flashlight(
|
|||||||
let Ok(action) = player_query.get_single() else {
|
let Ok(action) = player_query.get_single() else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
if *action != PlayerAction::ToggleFlashlight {
|
if *action != PlayerAction::ToggleFlashlight {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if let Ok(flashlight) = flashlight_query.get_single() {
|
if let Ok(flashlight) = flashlight_query.get_single() {
|
||||||
@@ -435,19 +446,15 @@ pub fn handle_spotlight(
|
|||||||
mut spotlight_query: Query<&mut SpotLight, With<SpotlightFlashlight>>,
|
mut spotlight_query: Query<&mut SpotLight, With<SpotlightFlashlight>>,
|
||||||
mut flashlight_query: Query<&mut Flashlight>,
|
mut flashlight_query: Query<&mut Flashlight>,
|
||||||
) {
|
) {
|
||||||
if let (Ok(mut spotlight), Ok(flashlight)) = (spotlight_query.get_single_mut(), flashlight_query.get_single_mut()) {
|
if let (Ok(mut spotlight), Ok(flashlight)) = (
|
||||||
spotlight.intensity = if !flashlight.is_on {
|
spotlight_query.get_single_mut(),
|
||||||
0.0
|
flashlight_query.get_single_mut(),
|
||||||
} else {
|
) {
|
||||||
320_000.0
|
spotlight.intensity = if !flashlight.is_on { 0.0 } else { 320_000.0 };
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update_flashlight_charge(
|
pub fn update_flashlight_charge(time: Res<Time>, mut flashlight_query: Query<&mut Flashlight>) {
|
||||||
time: Res<Time>,
|
|
||||||
mut flashlight_query: Query<&mut Flashlight>,
|
|
||||||
) {
|
|
||||||
for mut flashlight in flashlight_query.iter_mut() {
|
for mut flashlight in flashlight_query.iter_mut() {
|
||||||
if flashlight.is_on {
|
if flashlight.is_on {
|
||||||
flashlight.charge = flashlight.charge - time.delta_secs() * 0.1;
|
flashlight.charge = flashlight.charge - time.delta_secs() * 0.1;
|
||||||
@@ -479,7 +486,7 @@ pub fn update_flashlight_button_animation(
|
|||||||
pub fn update_flashlight_sprite(
|
pub fn update_flashlight_sprite(
|
||||||
mut query: Query<(&FlashlightButtonAnimation, &mut Sprite, &Flashlight)>,
|
mut query: Query<(&FlashlightButtonAnimation, &mut Sprite, &Flashlight)>,
|
||||||
flashlights: Res<FlashlightAssets>,
|
flashlights: Res<FlashlightAssets>,
|
||||||
){
|
) {
|
||||||
for (animation, mut image, flashlight) in query.iter_mut() {
|
for (animation, mut image, flashlight) in query.iter_mut() {
|
||||||
let charge = flashlight.charge.round() as i32;
|
let charge = flashlight.charge.round() as i32;
|
||||||
let sprite_image = match (charge, animation.is_pressed) {
|
let sprite_image = match (charge, animation.is_pressed) {
|
||||||
@@ -493,7 +500,7 @@ pub fn update_flashlight_sprite(
|
|||||||
(1, false) => flashlights.flash_hold_1.clone(),
|
(1, false) => flashlights.flash_hold_1.clone(),
|
||||||
(0, true) => flashlights.flash_hold_0_pressed.clone(),
|
(0, true) => flashlights.flash_hold_0_pressed.clone(),
|
||||||
(0, false) => flashlights.flash_hold_0.clone(),
|
(0, false) => flashlights.flash_hold_0.clone(),
|
||||||
_ => flashlights.flash_hold_0.clone()
|
_ => flashlights.flash_hold_0.clone(),
|
||||||
};
|
};
|
||||||
*image = Sprite::from_image(sprite_image);
|
*image = Sprite::from_image(sprite_image);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,10 @@ impl Item {
|
|||||||
pub fn take(&mut self) -> Option<Entity> {
|
pub fn take(&mut self) -> Option<Entity> {
|
||||||
self.0.take()
|
self.0.take()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn inner(&self) -> Option<Entity> {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Component, Default, Debug)]
|
#[derive(Component, Default, Debug)]
|
||||||
|
|||||||
Reference in New Issue
Block a user