pickup shows in toolbar
This commit is contained in:
@@ -3,20 +3,20 @@ use bevy::{prelude::*, utils::HashMap};
|
||||
use crate::GameState;
|
||||
use bevy_asset_loader::prelude::*;
|
||||
// use bevy_egui::{EguiContexts, egui, egui::ProgressBar};
|
||||
// use bevy_kira_audio::AudioSource;
|
||||
use bevy_kira_audio::{AudioPlugin, AudioSource};
|
||||
// use iyes_progress::{ProgressCounter, ProgressPlugin};
|
||||
|
||||
/// Loads resources and assets for the game.
|
||||
/// See assets/main.assets.ron for the actual paths used.
|
||||
pub(super) fn plugin(app: &mut App) {
|
||||
app.add_loading_state(
|
||||
app.add_plugins(AudioPlugin).add_loading_state(
|
||||
LoadingState::new(GameState::Loading)
|
||||
.continue_to_state(GameState::Menu)
|
||||
.with_dynamic_assets_file::<StandardDynamicAssetCollection>("main.assets.ron")
|
||||
.load_collection::<ImageAssets>()
|
||||
.load_collection::<FlashlightAssets>()
|
||||
.load_collection::<GltfAssets>(),
|
||||
// .load_collection::<AudioAssets>()
|
||||
.load_collection::<GltfAssets>()
|
||||
.load_collection::<AudioAssets>(),
|
||||
// .load_collection::<TextureAssets>()
|
||||
// .load_collection::<GrassAssets>()
|
||||
// .load_collection::<ConfigAssets>(),
|
||||
@@ -27,7 +27,10 @@ pub(super) fn plugin(app: &mut App) {
|
||||
// when done loading, they will be inserted as resources (see <https://github.com/NiklasEi/bevy_asset_loader>)
|
||||
|
||||
#[derive(AssetCollection, Resource, Clone)]
|
||||
pub(crate) struct AudioAssets {}
|
||||
pub(crate) struct AudioAssets {
|
||||
#[asset(key = "flashlight_click")]
|
||||
pub(crate) flash_click: Handle<AudioSource>,
|
||||
}
|
||||
|
||||
#[derive(AssetCollection, Resource, Clone)]
|
||||
pub(crate) struct GltfAssets {
|
||||
@@ -58,4 +61,6 @@ pub(crate) struct ImageAssets {
|
||||
pub(crate) struct FlashlightAssets {
|
||||
#[asset(key = "flash_hold_4")]
|
||||
pub(crate) flash_hold_4: Handle<Image>,
|
||||
#[asset(key = "flash_hold_4_pressed")]
|
||||
pub(crate) flash_hold_4_pressed: Handle<Image>,
|
||||
}
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
use bevy::{prelude::*, reflect::DynamicTypePath};
|
||||
use bevy::{image, prelude::*, reflect::DynamicTypePath};
|
||||
use bevy_rapier3d::prelude::*;
|
||||
|
||||
use crate::{GameState, asset_loading::GltfAssets, interaction::Interact};
|
||||
use crate::{
|
||||
GameState,
|
||||
asset_loading::{GltfAssets, ImageAssets},
|
||||
interaction::Interact,
|
||||
player::toolbar::ItemIcon,
|
||||
};
|
||||
|
||||
pub fn map_plugin(app: &mut App) {
|
||||
app.add_systems(
|
||||
@@ -112,7 +117,12 @@ fn spawn_level(mut commands: Commands, models: Res<Assets<Gltf>>, gltf_assets: R
|
||||
));
|
||||
}
|
||||
|
||||
fn spawn_objects(mut commands: Commands, models: Res<Assets<Gltf>>, gltf_assets: Res<GltfAssets>) {
|
||||
fn spawn_objects(
|
||||
mut commands: Commands,
|
||||
models: Res<Assets<Gltf>>,
|
||||
gltf_assets: Res<GltfAssets>,
|
||||
image_assets: Res<ImageAssets>,
|
||||
) {
|
||||
// let hammer = gltf_assets
|
||||
// .library
|
||||
// .get("meshes/library/hammer.glb")
|
||||
@@ -147,6 +157,7 @@ fn spawn_objects(mut commands: Commands, models: Res<Assets<Gltf>>, gltf_assets:
|
||||
Interact,
|
||||
RigidBody::Dynamic,
|
||||
Name::new("Id Card"),
|
||||
ItemIcon::new(image_assets.id_card.clone()),
|
||||
SceneRoot(asset.clone()),
|
||||
))
|
||||
.with_children(|parent| {
|
||||
|
||||
16
src/main.rs
16
src/main.rs
@@ -22,7 +22,7 @@ fn main() {
|
||||
RapierPhysicsPlugin::<NoUserData>::default(),
|
||||
RapierDebugRenderPlugin::default(),
|
||||
player::plugin,
|
||||
debugging::plugin,
|
||||
// debugging::plugin
|
||||
))
|
||||
.init_state::<GameState>()
|
||||
.add_systems(OnEnter(GameState::Playing), setup)
|
||||
@@ -62,11 +62,11 @@ fn setup(
|
||||
Collider::cuboid(0.5, 0.5, 0.5),
|
||||
));
|
||||
// light
|
||||
commands.spawn((
|
||||
PointLight {
|
||||
shadows_enabled: true,
|
||||
..default()
|
||||
},
|
||||
Transform::from_xyz(4.0, 8.0, 4.0),
|
||||
));
|
||||
// commands.spawn((
|
||||
// PointLight {
|
||||
// shadows_enabled: true,
|
||||
// ..default()
|
||||
// },
|
||||
// Transform::from_xyz(4.0, 8.0, 4.0),
|
||||
// ));
|
||||
}
|
||||
|
||||
104
src/player.rs
104
src/player.rs
@@ -2,11 +2,12 @@
|
||||
use bevy::{
|
||||
input::mouse::AccumulatedMouseMotion, prelude::*, render::view::RenderLayers, window::{PrimaryWindow, WindowResized}
|
||||
};
|
||||
use bevy_kira_audio::{Audio, AudioControl};
|
||||
use bevy_rapier3d::prelude::*;
|
||||
|
||||
pub mod toolbar;
|
||||
|
||||
use crate::{asset_loading::FlashlightAssets, GameState};
|
||||
use crate::{asset_loading::{AudioAssets, FlashlightAssets}, GameState};
|
||||
|
||||
#[derive(Debug, Component, Default)]
|
||||
pub struct Player {
|
||||
@@ -51,12 +52,38 @@ impl Default for HeadBob {
|
||||
#[derive(Component, Debug)]
|
||||
pub struct BaseTransform(pub Transform);
|
||||
|
||||
#[derive(Debug, Component)]
|
||||
pub struct Flashlight;
|
||||
|
||||
#[derive(Component)]
|
||||
pub struct FlashlightButtonAnimation {
|
||||
pub timer: Timer,
|
||||
pub is_pressed: bool,
|
||||
}
|
||||
|
||||
impl Default for FlashlightButtonAnimation {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
timer: Timer::from_seconds(0.20, TimerMode::Once),
|
||||
is_pressed: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub fn plugin(app: &mut App) {
|
||||
app.add_plugins(toolbar::plugin)
|
||||
.add_systems(OnEnter(GameState::Playing), (init_player, hide_cursor))
|
||||
.add_systems(
|
||||
Update,
|
||||
(move_camera, handle_input, apply_head_bob, on_resize_system).run_if(in_state(GameState::Playing)),
|
||||
(
|
||||
move_camera,
|
||||
handle_input,
|
||||
apply_head_bob,
|
||||
on_resize_system,
|
||||
handle_flashlight,
|
||||
update_flashlight_button_animation,
|
||||
).run_if(in_state(GameState::Playing)),
|
||||
)
|
||||
.add_systems(
|
||||
FixedUpdate,
|
||||
@@ -112,6 +139,7 @@ pub fn init_player(
|
||||
RenderLayers::layer(STATIC_LAYER),
|
||||
));
|
||||
|
||||
// pitslamp sprite
|
||||
let window = window.single();
|
||||
let transform = flashlight_base_transform(window.width(), window.height());
|
||||
parent.spawn((
|
||||
@@ -119,6 +147,24 @@ pub fn init_player(
|
||||
transform.0.clone(),
|
||||
transform,
|
||||
RenderLayers::layer(STATIC_LAYER),
|
||||
FlashlightButtonAnimation::default(),
|
||||
));
|
||||
|
||||
// feitelijke pitslamp
|
||||
parent.spawn((
|
||||
Flashlight,
|
||||
SpotLight {
|
||||
intensity: 0.0,
|
||||
color: Color::WHITE,
|
||||
range: 4.0,
|
||||
outer_angle: 30.0_f32.to_radians(), // wide cone for flashlight
|
||||
inner_angle: 10.0_f32.to_radians(), // narrower inner cone
|
||||
shadows_enabled: false, // (set to true for realism)
|
||||
radius: 0.35, // low value for hard light
|
||||
..default()
|
||||
},
|
||||
Transform::from_xyz(0.0, -0.15, 0.5),
|
||||
GlobalTransform::default(),
|
||||
));
|
||||
});
|
||||
}
|
||||
@@ -194,6 +240,8 @@ pub fn handle_input(
|
||||
mut query: Query<(&Transform, &mut PlayerInput, &mut PlayerAction, &mut Player), With<Player>>,
|
||||
) {
|
||||
for (transform, mut input, mut action, mut player) in query.iter_mut() {
|
||||
*action = PlayerAction::Move;
|
||||
|
||||
let forward = transform.forward();
|
||||
let right = transform.right();
|
||||
let mut movement_direction = Vec3::ZERO;
|
||||
@@ -221,10 +269,10 @@ pub fn handle_input(
|
||||
} else {
|
||||
player.speed_factor = 1.0;
|
||||
}
|
||||
if keyboard_input.pressed(KeyCode::KeyE) {
|
||||
if keyboard_input.just_pressed(KeyCode::KeyE) {
|
||||
*action = PlayerAction::Interact
|
||||
}
|
||||
if keyboard_input.pressed(KeyCode::KeyA) {
|
||||
if keyboard_input.just_pressed(KeyCode::KeyF) {
|
||||
*action = PlayerAction::ToggleFlashlight;
|
||||
}
|
||||
|
||||
@@ -295,7 +343,7 @@ pub fn apply_head_bob(
|
||||
if is_moving {
|
||||
transform.translation.x = horizontal_offset;
|
||||
} else {
|
||||
// decrease bobbing magnitued
|
||||
// decrease bobbing magnitude
|
||||
transform.translation.x *= 0.8;
|
||||
}
|
||||
}
|
||||
@@ -320,4 +368,50 @@ pub fn apply_head_bob(
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn handle_flashlight(
|
||||
player_query: Query<&PlayerAction, With<Player>>,
|
||||
mut flashlight_query: Query<&mut SpotLight, With<Flashlight>>,
|
||||
mut flashlight_sprite_query: Query<&mut FlashlightButtonAnimation>,
|
||||
audio_assets: Res<AudioAssets>,
|
||||
audio: Res<Audio>,
|
||||
) {
|
||||
let Ok(action) = player_query.get_single() else {
|
||||
return;
|
||||
};
|
||||
if *action != PlayerAction::ToggleFlashlight {
|
||||
return;
|
||||
}
|
||||
if let Ok(mut animation) = flashlight_sprite_query.get_single_mut() {
|
||||
animation.is_pressed = true;
|
||||
animation.timer.reset();
|
||||
}
|
||||
if let Ok(mut spotlight) = flashlight_query.get_single_mut() {
|
||||
audio.play(audio_assets.flash_click.clone());
|
||||
|
||||
spotlight.intensity = if spotlight.intensity > 0.0 {
|
||||
0.0
|
||||
} else {
|
||||
300_000.0
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update_flashlight_button_animation(
|
||||
time: Res<Time>,
|
||||
mut query: Query<(&mut FlashlightButtonAnimation, &mut Sprite)>,
|
||||
flashlights: Res<FlashlightAssets>,
|
||||
) {
|
||||
for (mut animation, mut image) in query.iter_mut() {
|
||||
if animation.is_pressed {
|
||||
animation.timer.tick(time.delta());
|
||||
if animation.timer.finished() {
|
||||
*image = Sprite::from_image(flashlights.flash_hold_4.clone());
|
||||
animation.is_pressed = false;
|
||||
} else {
|
||||
*image = Sprite::from_image(flashlights.flash_hold_4_pressed.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -12,6 +12,12 @@ pub struct Item(Option<Entity>);
|
||||
#[derive(Component, Default, Debug)]
|
||||
pub struct ItemIcon(Handle<Image>);
|
||||
|
||||
impl ItemIcon {
|
||||
pub fn new(h: Handle<Image>) -> Self {
|
||||
Self(h)
|
||||
}
|
||||
}
|
||||
|
||||
impl Item {
|
||||
pub fn none() -> Self {
|
||||
Default::default()
|
||||
@@ -31,9 +37,19 @@ fn bottom_panel(
|
||||
mut egui_ctx: EguiContexts,
|
||||
player_item_query: Query<&Item, With<Player>>,
|
||||
item_query: Query<(&Name, &ItemIcon), With<Interact>>,
|
||||
models: Res<Assets<Image>>,
|
||||
gltf_assets: Res<ImageAssets>,
|
||||
) {
|
||||
let item = single!(player_item_query);
|
||||
let item = item.0.and_then(|id| item_query.get(id).ok());
|
||||
let (name, icon) = item.map_or_else(
|
||||
|| (Name::new(""), None),
|
||||
|(name, handle)| {
|
||||
(
|
||||
name.clone(),
|
||||
Some(egui_ctx.add_image(handle.0.clone_weak())),
|
||||
)
|
||||
},
|
||||
);
|
||||
|
||||
egui::TopBottomPanel::bottom("inventory_toolbar")
|
||||
.frame(egui::Frame {
|
||||
fill: egui::Color32::from_rgba_premultiplied(0, 0, 0, 0),
|
||||
@@ -52,7 +68,7 @@ fn bottom_panel(
|
||||
|
||||
// Create a frame for the slot
|
||||
let slot_frame = egui::Frame {
|
||||
fill: egui::Color32::from_rgba_premultiplied(50, 50, 50, 100),
|
||||
fill: egui::Color32::from_rgba_premultiplied(75, 75, 75, 100),
|
||||
stroke: egui::Stroke::new(2.0, egui::Color32::WHITE),
|
||||
..Default::default()
|
||||
};
|
||||
@@ -61,20 +77,24 @@ fn bottom_panel(
|
||||
ui.add_sized([50.0, 50.0], |ui: &mut egui::Ui| {
|
||||
// Display the item
|
||||
ui.vertical_centered(|ui| {
|
||||
let item = single!(player_item_query);
|
||||
let item = item.0.and_then(|id| item_query.get(id).ok());
|
||||
// Placeholder for texture - in a real app, load the texture
|
||||
ui.label(egui::RichText::new("🔨").size(24.0));
|
||||
// let (name, icon) = item.map_or_else((Name::new(""), ), |(name, handle)|{
|
||||
|
||||
// });
|
||||
|
||||
// Item count (display only if > 1)
|
||||
ui.label(
|
||||
egui::RichText::new("")
|
||||
.color(egui::Color32::WHITE)
|
||||
.size(12.0),
|
||||
);
|
||||
ui.horizontal_centered(|ui| {
|
||||
match icon {
|
||||
Some(image) => {
|
||||
ui.add(egui::widgets::Image::new(
|
||||
egui::load::SizedTexture::new(image, [50.0, 30.0]),
|
||||
));
|
||||
}
|
||||
None => {
|
||||
ui.label(egui::RichText::new("➖").size(24.0));
|
||||
ui.label(egui::RichText::new("Empty").size(12.0));
|
||||
}
|
||||
}
|
||||
ui.label(
|
||||
egui::RichText::new(name)
|
||||
.color(egui::Color32::WHITE)
|
||||
.size(12.0),
|
||||
);
|
||||
});
|
||||
});
|
||||
ui.allocate_response(ui.available_size(), egui::Sense::click())
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user