This commit is contained in:
LorrensP-2158466
2025-04-06 19:52:57 +02:00
17 changed files with 642 additions and 137 deletions

49
Cargo.lock generated
View File

@@ -149,6 +149,7 @@ dependencies = [
"bevy_egui", "bevy_egui",
"bevy_kira_audio", "bevy_kira_audio",
"bevy_rapier3d", "bevy_rapier3d",
"rand 0.9.0",
] ]
[[package]] [[package]]
@@ -978,7 +979,7 @@ dependencies = [
"derive_more", "derive_more",
"glam", "glam",
"itertools 0.13.0", "itertools 0.13.0",
"rand", "rand 0.8.5",
"rand_distr", "rand_distr",
"serde", "serde",
"smallvec", "smallvec",
@@ -2543,7 +2544,7 @@ checksum = "8babf46d4c1c9d92deac9f7be466f76dfc4482b6452fc5024b5e8daf6ffeb3ee"
dependencies = [ dependencies = [
"bytemuck", "bytemuck",
"mint", "mint",
"rand", "rand 0.8.5",
"serde", "serde",
] ]
@@ -4263,8 +4264,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
dependencies = [ dependencies = [
"libc", "libc",
"rand_chacha", "rand_chacha 0.3.1",
"rand_core", "rand_core 0.6.4",
]
[[package]]
name = "rand"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94"
dependencies = [
"rand_chacha 0.9.0",
"rand_core 0.9.3",
"zerocopy 0.8.24",
] ]
[[package]] [[package]]
@@ -4274,7 +4286,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
dependencies = [ dependencies = [
"ppv-lite86", "ppv-lite86",
"rand_core", "rand_core 0.6.4",
]
[[package]]
name = "rand_chacha"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb"
dependencies = [
"ppv-lite86",
"rand_core 0.9.3",
] ]
[[package]] [[package]]
@@ -4286,6 +4308,15 @@ dependencies = [
"getrandom 0.2.15", "getrandom 0.2.15",
] ]
[[package]]
name = "rand_core"
version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38"
dependencies = [
"getrandom 0.3.2",
]
[[package]] [[package]]
name = "rand_distr" name = "rand_distr"
version = "0.4.3" version = "0.4.3"
@@ -4293,7 +4324,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32cb0b9bc82b0a0876c2dd994a7e7a2683d3e7390ca40e6886785ef0c7e3ee31" checksum = "32cb0b9bc82b0a0876c2dd994a7e7a2683d3e7390ca40e6886785ef0c7e3ee31"
dependencies = [ dependencies = [
"num-traits", "num-traits",
"rand", "rand 0.8.5",
] ]
[[package]] [[package]]
@@ -4358,8 +4389,8 @@ dependencies = [
"once_cell", "once_cell",
"paste", "paste",
"profiling", "profiling",
"rand", "rand 0.8.5",
"rand_chacha", "rand_chacha 0.3.1",
"simd_helpers", "simd_helpers",
"system-deps", "system-deps",
"thiserror 1.0.69", "thiserror 1.0.69",
@@ -5427,7 +5458,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b3758f5e68192bb96cc8f9b7e2c2cfdabb435499a28499a42f8f984092adad4b" checksum = "b3758f5e68192bb96cc8f9b7e2c2cfdabb435499a28499a42f8f984092adad4b"
dependencies = [ dependencies = [
"getrandom 0.2.15", "getrandom 0.2.15",
"rand", "rand 0.8.5",
"serde", "serde",
] ]

View File

@@ -9,3 +9,4 @@ bevy_asset_loader = { version ="0.22.0", features = ["standard_dynamic_assets"]
bevy_egui = "0.33.0" bevy_egui = "0.33.0"
bevy_kira_audio = "0.22.0" bevy_kira_audio = "0.22.0"
bevy_rapier3d = "0.29.0" bevy_rapier3d = "0.29.0"
rand = "0.9.0"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 18 KiB

View File

@@ -1,3 +1,80 @@
use bevy::prelude::*; use bevy::prelude::*;
use bevy_rapier3d::prelude::ColliderDisabled;
use crate::{
player::{Player, PlayerAction, toolbar::Item},
util::single_mut,
};
use super::{Interact, ui::InteractionOpportunity};
pub fn plugin(_app: &mut App) {} pub fn plugin(_app: &mut App) {}
pub fn handle_pick_up(
mut commands: Commands,
// current action
mut action: Query<(&PlayerAction, &mut Item), With<Player>>,
mut vis_query: Query<&mut Visibility>,
children: Query<&mut Children>,
// current interactable
mut interaction_opportunity: ResMut<InteractionOpportunity>,
) {
let (action, mut item) = single_mut!(action);
if *action == PlayerAction::PickUp {
// 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) {
*vis = Visibility::Hidden;
}
if let Ok(colliders) = children.get(target) {
for &collider in colliders {
commands.entity(collider).insert(ColliderDisabled);
}
}
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 {
commands.entity(collider).remove::<ColliderDisabled>();
}
}
}
}
}
pub fn handle_drop(
mut commands: Commands,
// current action
mut action: Query<(&PlayerAction, &Transform, &mut Item), With<Player>>,
mut vis_query: Query<&mut Visibility>,
mut item_transform: Query<&mut Transform, With<Interact>>,
children: Query<&mut Children>,
) {
// let (action, transform, mut item) = single_mut!(action);
// if *action == PlayerAction::Drop {
// if let Ok(mut vis) = vis_query.get_mut(target) {
// *vis = Visibility::Hidden;
// }
// if let Ok(colliders) = children.get(target) {
// for &collider in colliders {
// commands.entity(collider).insert(ColliderDisabled);
// }
// }
// 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 {
// commands.entity(collider).remove::<ColliderDisabled>();
// }
// }
// }
// }
}

View File

@@ -8,7 +8,7 @@ use bevy_rapier3d::prelude::*;
use bevy_rapier3d::rapier::prelude::CollisionEventFlags; use bevy_rapier3d::rapier::prelude::CollisionEventFlags;
use std::iter; use std::iter;
use super::Interact; use super::{Interact, objects};
pub(super) fn plugin(app: &mut App) { pub(super) fn plugin(app: &mut App) {
app.add_plugins(EguiPlugin) app.add_plugins(EguiPlugin)
@@ -18,7 +18,7 @@ pub(super) fn plugin(app: &mut App) {
( (
update_interaction_opportunities, update_interaction_opportunities,
display_interaction_prompt, display_interaction_prompt,
handle_pick_up, (objects::handle_pick_up, objects::handle_drop),
) )
.chain() .chain()
.run_if(in_state(GameState::Playing)), .run_if(in_state(GameState::Playing)),
@@ -26,7 +26,7 @@ pub(super) fn plugin(app: &mut App) {
} }
#[derive(Debug, Clone, Eq, PartialEq, Resource, Default)] #[derive(Debug, Clone, Eq, PartialEq, Resource, Default)]
struct InteractionOpportunity(Option<Entity>); pub struct InteractionOpportunity(pub Option<Entity>);
fn update_interaction_opportunities( fn update_interaction_opportunities(
mut collision_events: EventReader<CollisionEvent>, mut collision_events: EventReader<CollisionEvent>,
@@ -81,6 +81,7 @@ fn display_interaction_prompt(
.map(|name| name.as_str()) .map(|name| name.as_str())
.expect("A named Interactable object"); .expect("A named Interactable object");
// objective or item
egui::Window::new("Interaction") egui::Window::new("Interaction")
.collapsible(false) .collapsible(false)
.title_bar(false) .title_bar(false)
@@ -90,27 +91,3 @@ fn display_interaction_prompt(
ui.label(format!("E: Pick Up {entity_name}")); ui.label(format!("E: Pick Up {entity_name}"));
}); });
} }
fn handle_pick_up(
// current action
mut action: Query<(&PlayerAction, &mut Item), With<Player>>,
mut item_query: Query<&mut Visibility, With<Interact>>,
// current interactable
interaction_opportunity: Res<InteractionOpportunity>,
) {
let Some(target) = interaction_opportunity.0 else {
return;
};
let (action, mut item) = single_mut!(action);
if *action == PlayerAction::Interact {
let replaced = item.set_item(target);
if let Ok(mut vis) = item_query.get_mut(target) {
*vis = Visibility::Hidden;
}
if let Some(dropped) = replaced {
if let Ok(mut vis) = item_query.get_mut(dropped) {
*vis = Visibility::Visible;
}
}
}
}

View File

@@ -1,5 +1,8 @@
use bevy::{image, prelude::*, reflect::DynamicTypePath}; use std::collections::HashMap;
use bevy::prelude::*;
use bevy_rapier3d::prelude::*; use bevy_rapier3d::prelude::*;
use rand::Rng;
use crate::{ use crate::{
GameState, GameState,
@@ -28,29 +31,45 @@ fn spawn_level(mut commands: Commands, models: Res<Assets<Gltf>>, gltf_assets: R
let shapes = mesh_names.map(|mesh_name| { let shapes = mesh_names.map(|mesh_name| {
let collider: Vec<(Collider, Transform)> = match mesh_name { let collider: Vec<(Collider, Transform)> = match mesh_name {
"corner_inside" => vec![( "corner_inside" => vec![(
Collider::cuboid(1.0, 0.1, 1.0), Collider::cuboid(0.2, 1.0, 0.2),
Transform::from_xyz(0.0, 0.0, 0.0), Transform::from_xyz(1.0, 1.0, 1.0)
)], .with_rotation(Quat::from_rotation_y(45.0_f32.to_radians())),
"corner_outside" => vec![(
Collider::cuboid(1.0, 0.1, 1.0),
Transform::from_xyz(0.0, 0.0, 0.0),
)], )],
"corner_outside" => vec![
(
Collider::cuboid(1.0, 1.0, 0.1),
Transform::from_xyz(0.0, 1.0, -1.0),
),
(
Collider::cuboid(1.0, 1.0, 0.1),
Transform::from_xyz(-1.0, 1.0, 0.0)
.with_rotation(Quat::from_rotation_y(90.0_f32.to_radians())),
),
],
"wall" => vec![( "wall" => vec![(
Collider::cuboid(1.0, 1.0, 0.1), Collider::cuboid(1.0, 1.0, 0.1),
Transform::from_xyz(0.0, 0.5, -1.0), Transform::from_xyz(0.0, 1.0, -1.0),
)], )],
"door" => vec![( "door" => vec![(
Collider::cuboid(1.0, 0.1, 1.0), Collider::cuboid(1.0, 1.0, 0.1),
Transform::from_xyz(0.0, 0.0, 0.0), Transform::from_xyz(0.0, 1.0, -1.0),
)], )],
"round_door" => vec![( "round_door" => vec![(
Collider::cuboid(1.0, 0.1, 1.0), Collider::cuboid(1.0, 1.0, 0.1),
Transform::from_xyz(0.0, 0.0, 0.0), Transform::from_xyz(0.0, 1.0, -1.0),
)],
"round_hole" => vec![(
Collider::cuboid(1.0, 0.1, 1.0),
Transform::from_xyz(0.0, 0.0, 0.0),
)], )],
"round_hole" => vec![
(
Collider::cuboid(0.2, 1.0, 0.2),
Transform::from_xyz(1.0, 1.0, -1.0)
.with_rotation(Quat::from_rotation_y(45.0_f32.to_radians())),
),
(
Collider::cuboid(0.2, 1.0, 0.2),
Transform::from_xyz(-1.0, 1.0, -1.0)
.with_rotation(Quat::from_rotation_y(45.0_f32.to_radians())),
),
],
_ => vec![( _ => vec![(
Collider::cuboid(1.0, 0.1, 1.0), Collider::cuboid(1.0, 0.1, 1.0),
Transform::from_xyz(0.0, 0.0, 0.0), Transform::from_xyz(0.0, 0.0, 0.0),
@@ -78,31 +97,7 @@ fn spawn_level(mut commands: Commands, models: Res<Assets<Gltf>>, gltf_assets: R
door, door,
round_door, round_door,
round_hole, round_hole,
] = shapes; ] = shapes.clone();
for i in 0..30 {
commands
.spawn((
wall.0.clone(),
Transform::from_xyz(i as f32 * 2.0, 0.0, 0.0),
))
.with_children(|parent| {
for ele in wall.1.clone() {
parent.spawn((RigidBody::Fixed, ele.0, ele.1));
}
});
commands
.spawn((
wall.0.clone(),
Transform::from_xyz(i as f32 * 2.0, 0.0, 0.0)
.with_rotation(Quat::from_rotation_y(std::f32::consts::PI)),
))
.with_children(|parent| {
for ele in wall.1.clone() {
parent.spawn((RigidBody::Fixed, ele.0, ele.1));
}
});
}
// huge floor // huge floor
commands.spawn(( commands.spawn((
@@ -110,11 +105,422 @@ fn spawn_level(mut commands: Commands, models: Res<Assets<Gltf>>, gltf_assets: R
Collider::cuboid(1000.0, 0.1, 1000.0), Collider::cuboid(1000.0, 0.1, 1000.0),
Transform::from_xyz(-500.0, 0.0, -500.0), Transform::from_xyz(-500.0, 0.0, -500.0),
)); ));
commands.spawn(( // huge roof
RigidBody::Fixed, // commands.spawn((
Collider::cuboid(1000.0, 0.1, 1000.0), // RigidBody::Fixed,
Transform::from_xyz(-500.0, 3.0, -500.0), // Collider::cuboid(1000.0, 0.1, 1000.0),
)); // Transform::from_xyz(-500.0, 3.0, -500.0),
// ));
// let map = GameMap::test();
let map = GameMap::new(100);
map.print_map();
for ((x, z), node) in map.nodes.into_iter() {
let values = {
// corners are handled later, for now just a wall to test
let node = node.clone();
let pos = Transform::from_xyz(2.0 * x as f32, 0.0, -2.0 * z as f32);
use Side::{Closed, Connection};
match (node.north, node.east, node.south, node.west) {
// hallway horizontal
(Closed, Connection, Closed, Connection) => {
vec![
(wall.clone(), pos),
(
wall.clone(),
pos.with_rotation(Quat::from_rotation_y(180.0_f32.to_radians())),
),
]
}
// hallway vertical
(Connection, Closed, Connection, Closed) => {
vec![
(
wall.clone(),
pos.with_rotation(Quat::from_rotation_y(90.0_f32.to_radians())),
),
(
wall.clone(),
pos.with_rotation(Quat::from_rotation_y(270.0_f32.to_radians())),
),
]
}
// dead ends
(Connection, Closed, Closed, Closed) => {
vec![
(
wall.clone(),
pos.with_rotation(Quat::from_rotation_y(90.0_f32.to_radians())),
),
(
round_door.clone(),
pos.with_rotation(Quat::from_rotation_y(180.0_f32.to_radians())),
),
(
wall.clone(),
pos.with_rotation(Quat::from_rotation_y(270.0_f32.to_radians())),
),
]
}
(Closed, Closed, Connection, Closed) => {
vec![
(
wall.clone(),
pos.with_rotation(Quat::from_rotation_y(90.0_f32.to_radians())),
),
(
round_door.clone(),
pos.with_rotation(Quat::from_rotation_y(0.0_f32.to_radians())),
),
(
wall.clone(),
pos.with_rotation(Quat::from_rotation_y(270.0_f32.to_radians())),
),
]
}
(Closed, Connection, Closed, Closed) => {
vec![
(wall.clone(), pos),
(
round_door.clone(),
pos.with_rotation(Quat::from_rotation_y(90.0_f32.to_radians())),
),
(
wall.clone(),
pos.with_rotation(Quat::from_rotation_y(180.0_f32.to_radians())),
),
]
}
(Closed, Closed, Closed, Connection) => {
vec![
(wall.clone(), pos),
(
round_door.clone(),
pos.with_rotation(Quat::from_rotation_y(270.0_f32.to_radians())),
),
(
wall.clone(),
pos.with_rotation(Quat::from_rotation_y(180.0_f32.to_radians())),
),
]
}
// T hallways
(Closed, Connection, Connection, Connection) => {
vec![
(wall.clone(), pos),
(
round_hole.clone(),
pos.with_rotation(Quat::from_rotation_y(180.0_f32.to_radians())),
),
]
}
(Connection, Closed, Connection, Connection) => {
vec![
(
round_hole.clone(),
pos.with_rotation(Quat::from_rotation_y(90.0_f32.to_radians())),
),
(
wall.clone(),
pos.with_rotation(Quat::from_rotation_y(270.0_f32.to_radians())),
),
]
}
(Connection, Connection, Closed, Connection) => {
vec![
(round_hole.clone(), pos),
(
wall.clone(),
pos.with_rotation(Quat::from_rotation_y(180.0_f32.to_radians())),
),
]
}
(Connection, Connection, Connection, Closed) => {
vec![
(
wall.clone(),
pos.with_rotation(Quat::from_rotation_y(90.0_f32.to_radians())),
),
(
round_hole.clone(),
pos.with_rotation(Quat::from_rotation_y(270.0_f32.to_radians())),
),
]
}
// fourway
(Connection, Connection, Connection, Connection) => {
vec![
(
corner_inside.clone(),
pos.with_rotation(Quat::from_rotation_y(0.0_f32.to_radians())),
),
(
corner_inside.clone(),
pos.with_rotation(Quat::from_rotation_y(90.0_f32.to_radians())),
),
(
corner_inside.clone(),
pos.with_rotation(Quat::from_rotation_y(180.0_f32.to_radians())),
),
(
corner_inside.clone(),
pos.with_rotation(Quat::from_rotation_y(270.0_f32.to_radians())),
),
]
}
// corners
(Connection, Connection, Closed, Closed) => {
vec![
(
corner_outside.clone(),
pos.with_rotation(Quat::from_rotation_y(90.0_f32.to_radians())),
),
(
corner_inside.clone(),
pos.with_rotation(Quat::from_rotation_y(90.0_f32.to_radians())),
),
]
}
(Closed, Connection, Connection, Closed) => {
vec![
(
corner_outside.clone(),
pos.with_rotation(Quat::from_rotation_y(0.0_f32.to_radians())),
),
(
corner_inside.clone(),
pos.with_rotation(Quat::from_rotation_y(0.0_f32.to_radians())),
),
]
}
(Closed, Closed, Connection, Connection) => {
vec![
(
corner_outside.clone(),
pos.with_rotation(Quat::from_rotation_y(270.0_f32.to_radians())),
),
(
corner_inside.clone(),
pos.with_rotation(Quat::from_rotation_y(270.0_f32.to_radians())),
),
]
}
(Connection, Closed, Closed, Connection) => {
vec![
(
corner_outside.clone(),
pos.with_rotation(Quat::from_rotation_y(180.0_f32.to_radians())),
),
(
corner_inside.clone(),
pos.with_rotation(Quat::from_rotation_y(180.0_f32.to_radians())),
),
]
}
_ => vec![],
}
};
for ((scene_root, colliders), pos) in values {
commands
.spawn((RigidBody::Fixed, scene_root, pos))
.with_children(|parent| {
for (collider, transform) in colliders {
parent.spawn((collider, transform));
}
});
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
enum Side {
Empty,
Connection,
Closed,
}
#[derive(Clone, Debug)]
struct MapNode {
north: Side,
south: Side,
east: Side,
west: Side,
collapsed: bool,
}
impl MapNode {
fn new() -> Self {
MapNode {
north: Side::Empty,
south: Side::Empty,
east: Side::Empty,
west: Side::Empty,
collapsed: false,
}
}
}
struct GameMap {
nodes: HashMap<(i32, i32), MapNode>,
max_nodes: i32,
}
impl GameMap {
fn new(max_nodes: i32) -> Self {
let mut nodes = HashMap::new();
let mut start_node = MapNode::new();
start_node.north = Side::Connection;
start_node.south = Side::Connection;
start_node.east = Side::Connection;
start_node.west = Side::Connection;
nodes.insert((0, 0), start_node);
let mut m = GameMap { nodes, max_nodes };
m.generate_map();
m
}
fn test() -> Self {
let mut nodes = HashMap::new();
let mut wall_node0 = MapNode::new();
wall_node0.north = Side::Connection;
wall_node0.south = Side::Closed;
wall_node0.east = Side::Closed;
wall_node0.west = Side::Closed;
nodes.insert((0, -1), wall_node0);
let mut wall_node1 = MapNode::new();
wall_node1.north = Side::Connection;
wall_node1.south = Side::Connection;
wall_node1.east = Side::Connection;
wall_node1.west = Side::Closed;
nodes.insert((0, 0), wall_node1);
let mut wall_node2 = MapNode::new();
wall_node2.north = Side::Connection;
wall_node2.south = Side::Connection;
wall_node2.east = Side::Closed;
wall_node2.west = Side::Connection;
nodes.insert((0, 1), wall_node2);
let mut corner_node = MapNode::new();
corner_node.south = Side::Connection;
corner_node.east = Side::Connection;
corner_node.north = Side::Closed;
corner_node.west = Side::Closed;
nodes.insert((0, 2), corner_node);
let mut wall_node3 = MapNode::new();
wall_node3.west = Side::Connection;
wall_node3.east = Side::Connection;
wall_node3.north = Side::Closed;
wall_node3.south = Side::Connection;
nodes.insert((1, 2), wall_node3);
let mut wall_node4 = MapNode::new();
wall_node4.west = Side::Connection;
wall_node4.east = Side::Connection;
wall_node4.north = Side::Connection;
wall_node4.south = Side::Closed;
nodes.insert((2, 2), wall_node4);
let mut wall_node5 = MapNode::new();
wall_node5.west = Side::Connection;
wall_node5.east = Side::Closed;
wall_node5.north = Side::Closed;
wall_node5.south = Side::Connection;
nodes.insert((3, 2), wall_node5);
GameMap {
nodes,
max_nodes: 7,
}
}
fn generate_map(&mut self) {
self.create_node(&(0, 1)); // North
// self.create_node(&(0, -1)); // South
// self.create_node(&(1, 0)); // East
// self.create_node(&(-1, 0)); // West
}
fn choose_side(&self) -> Side {
if self.nodes.len() > self.max_nodes as usize {
Side::Closed
} else {
if rand::rng().random_bool(0.5) {
Side::Connection
} else {
Side::Closed
}
}
}
fn create_node(&mut self, idx: &(i32, i32)) {
let mut nodes_to_process = vec![*idx];
let mut nodes_created = 0;
while let Some(current_idx) = nodes_to_process.pop() {
if self.nodes.contains_key(&current_idx) {
continue;
}
let (x, y) = current_idx;
let mut new_node = MapNode::new();
let north = self.nodes.get(&(x, y + 1));
let south = self.nodes.get(&(x, y - 1));
let east = self.nodes.get(&(x + 1, y));
let west = self.nodes.get(&(x - 1, y));
new_node.north = north.map_or_else(|| self.choose_side(), |n| n.south);
new_node.south = south.map_or_else(|| self.choose_side(), |s| s.north);
new_node.east = east.map_or_else(|| self.choose_side(), |e| e.west);
new_node.west = west.map_or_else(|| self.choose_side(), |w| w.east);
if new_node.north == Side::Connection && !self.nodes.contains_key(&(x, y + 1)) {
nodes_to_process.push((x, y + 1));
}
if new_node.south == Side::Connection && !self.nodes.contains_key(&(x, y - 1)) {
nodes_to_process.push((x, y - 1));
}
if new_node.east == Side::Connection && !self.nodes.contains_key(&(x + 1, y)) {
nodes_to_process.push((x + 1, y));
}
if new_node.west == Side::Connection && !self.nodes.contains_key(&(x - 1, y)) {
nodes_to_process.push((x - 1, y));
}
self.nodes.insert(current_idx, new_node);
nodes_created += 1;
}
}
fn print_map(&self) {
let mut min_x = 0;
let mut max_x = 0;
let mut min_y = 0;
let mut max_y = 0;
for &(x, y) in self.nodes.keys() {
min_x = min_x.min(x);
max_x = max_x.max(x);
min_y = min_y.min(y);
max_y = max_y.max(y);
}
for y in (min_y..=max_y).rev() {
for x in min_x..=max_x {
match self.nodes.get(&(x, y)) {
Some(node) => print!("[+]"),
None => print!(" "),
}
}
println!();
}
}
} }
fn spawn_objects( fn spawn_objects(
@@ -156,14 +562,13 @@ fn spawn_objects(
Transform::from_xyz(0.0, 2.0, 2.0), Transform::from_xyz(0.0, 2.0, 2.0),
Interact, Interact,
RigidBody::Dynamic, RigidBody::Dynamic,
Name::new("Id Card"), Name::new("Id Card 1"),
Visibility::Visible, Visibility::Visible,
ItemIcon::new(image_assets.id_card.clone()), ItemIcon::new(image_assets.id_card.clone()),
SceneRoot(asset.clone()), SceneRoot(asset.clone()),
)) ))
.with_children(|parent| { .with_children(|parent| {
parent.spawn(( parent.spawn((
Visibility::Inherited,
ColliderMassProperties::Mass(10.0), ColliderMassProperties::Mass(10.0),
Collider::cuboid(0.05, 0.05, 0.01), Collider::cuboid(0.05, 0.05, 0.01),
Transform::from_rotation(Quat::from_euler( Transform::from_rotation(Quat::from_euler(
@@ -174,7 +579,6 @@ fn spawn_objects(
)), )),
)); ));
parent.spawn(( parent.spawn((
Visibility::Inherited,
ActiveEvents::COLLISION_EVENTS, ActiveEvents::COLLISION_EVENTS,
Transform::default(), Transform::default(),
Collider::ball(0.5), // Interaction radius Collider::ball(0.5), // Interaction radius

View File

@@ -1,13 +1,18 @@
use bevy::{ use bevy::{
input::mouse::AccumulatedMouseMotion, prelude::*, render::view::RenderLayers, window::{PrimaryWindow, WindowResized} input::mouse::AccumulatedMouseMotion,
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::*;
pub mod toolbar; pub mod toolbar;
use crate::{asset_loading::{AudioAssets, FlashlightAssets}, GameState}; use crate::{
GameState,
asset_loading::{AudioAssets, FlashlightAssets},
};
#[derive(Debug, Component, Default)] #[derive(Debug, Component, Default)]
pub struct Player { pub struct Player {
@@ -70,7 +75,6 @@ impl Default for FlashlightButtonAnimation {
} }
} }
pub fn plugin(app: &mut App) { pub fn plugin(app: &mut App) {
app.add_plugins(toolbar::plugin) app.add_plugins(toolbar::plugin)
.add_systems(OnEnter(GameState::Playing), (init_player, hide_cursor)) .add_systems(OnEnter(GameState::Playing), (init_player, hide_cursor))
@@ -83,7 +87,8 @@ pub fn plugin(app: &mut App) {
on_resize_system, on_resize_system,
handle_flashlight, handle_flashlight,
update_flashlight_button_animation, update_flashlight_button_animation,
).run_if(in_state(GameState::Playing)), )
.run_if(in_state(GameState::Playing)),
) )
.add_systems( .add_systems(
FixedUpdate, FixedUpdate,
@@ -138,8 +143,6 @@ pub fn init_player(
}, },
RenderLayers::layer(STATIC_LAYER), RenderLayers::layer(STATIC_LAYER),
)); ));
// pitslamp sprite
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((
@@ -184,15 +187,17 @@ fn on_resize_system(
fn flashlight_base_transform(window_width: f32, window_height: f32) -> BaseTransform { fn flashlight_base_transform(window_width: f32, window_height: f32) -> BaseTransform {
let window_size = Vec2::new(window_width, window_height); let window_size = Vec2::new(window_width, window_height);
let sprite_size = Vec2::new(101.0, 101.0); let sprite_size = Vec2::new(404.0, 404.0);
let scale = window_width / 600.0; let scale = window_width / 2400.0;
let world_size = sprite_size * scale; let world_size = sprite_size * scale;
let xoffset = window_size.x / 4.0 - 40.0; let xoffset = window_size.x / 4.0 - 40.0;
let yoffset = 15.0; let yoffset = 15.0;
let mut transform = Transform::from_translation( let mut transform = Transform::from_translation(Vec3::new(
Vec3::new(window_size.x / 2.0 - world_size.x / 2.0 - xoffset, -window_size.y / 2.0 + world_size.y / 2.0 - yoffset, 0.0) window_size.x / 2.0 - world_size.x / 2.0 - xoffset,
); -window_size.y / 2.0 + world_size.y / 2.0 - yoffset,
0.0,
));
transform.scale = Vec3::new(scale, scale, 1.0); transform.scale = Vec3::new(scale, scale, 1.0);
return BaseTransform(transform); return BaseTransform(transform);
} }
@@ -231,8 +236,10 @@ pub(crate) enum PlayerAction {
Move, Move,
Sprint, Sprint,
Jump, Jump,
Interact, ToggleFlashlight,
ToggleFlashlight // Objects and stuff
PickUp,
Drop,
} }
pub fn handle_input( pub fn handle_input(
@@ -270,7 +277,10 @@ pub fn handle_input(
player.speed_factor = 1.0; player.speed_factor = 1.0;
} }
if keyboard_input.just_pressed(KeyCode::KeyE) { if keyboard_input.just_pressed(KeyCode::KeyE) {
*action = PlayerAction::Interact *action = PlayerAction::PickUp;
}
if keyboard_input.just_pressed(KeyCode::KeyQ) {
*action = PlayerAction::Drop;
} }
if keyboard_input.just_pressed(KeyCode::KeyF) { if keyboard_input.just_pressed(KeyCode::KeyF) {
*action = PlayerAction::ToggleFlashlight; *action = PlayerAction::ToggleFlashlight;
@@ -280,7 +290,9 @@ pub fn handle_input(
} }
} }
pub fn apply_player_movement(mut player_query: Query<(&PlayerInput, &mut Velocity, &Player), With<Player>>) { pub fn apply_player_movement(
mut player_query: Query<(&PlayerInput, &mut Velocity, &Player), With<Player>>,
) {
const SPEED: f32 = 2.6; const SPEED: f32 = 2.6;
const JUMP_FORCE: f32 = 4.0; const JUMP_FORCE: f32 = 4.0;
@@ -305,14 +317,18 @@ pub fn apply_head_bob(
time: Res<Time>, time: Res<Time>,
mut query: Query<(&PlayerInput, &mut HeadBob, &Player), With<Player>>, mut query: Query<(&PlayerInput, &mut HeadBob, &Player), With<Player>>,
mut camera_query: Query<&mut Transform, (With<WorldModelCamera>, Without<Player>)>, mut camera_query: Query<&mut Transform, (With<WorldModelCamera>, Without<Player>)>,
mut sprite_query: Query<(&mut Transform, &Sprite, &BaseTransform), (With<Sprite>, Without<WorldModelCamera>, Without<Player>)>, mut sprite_query: Query<
(&mut Transform, &Sprite, &BaseTransform),
(With<Sprite>, Without<WorldModelCamera>, Without<Player>),
>,
) { ) {
let Ok((input, mut head_bob, player)) = query.get_single_mut() else { let Ok((input, mut head_bob, player)) = query.get_single_mut() else {
return; return;
}; };
// bob when moving horizontally // bob when moving horizontally
let horizontal_movement = Vec3::new(input.movement_direction.x, 0.0, input.movement_direction.z); let horizontal_movement =
Vec3::new(input.movement_direction.x, 0.0, input.movement_direction.z);
let is_moving = horizontal_movement.length_squared() > 0.01; let is_moving = horizontal_movement.length_squared() > 0.01;
let bobbing_speed = head_bob.speed * player.speed_factor; let bobbing_speed = head_bob.speed * player.speed_factor;
@@ -353,23 +369,22 @@ pub fn apply_head_bob(
let scale_factor = 40.0 * player.speed_factor; let scale_factor = 40.0 * player.speed_factor;
if is_moving { if is_moving {
transform.translation.x = base_transform.0.translation.x + horizontal_offset * scale_factor; transform.translation.x =
transform.translation.y = base_transform.0.translation.y + vertical_offset * scale_factor; base_transform.0.translation.x + horizontal_offset * scale_factor;
transform.translation.y =
base_transform.0.translation.y + vertical_offset * scale_factor;
transform.rotation = Quat::from_euler( transform.rotation =
EulerRot::XYZ, Quat::from_euler(EulerRot::XYZ, 0.0, 0.0, horizontal_offset * 0.1);
0.0,
0.0,
horizontal_offset * 0.1,
);
} else { } else {
transform.translation = transform.translation.lerp(base_transform.0.translation, 0.1); transform.translation = transform
.translation
.lerp(base_transform.0.translation, 0.1);
transform.rotation = transform.rotation.slerp(Quat::IDENTITY, 0.1); transform.rotation = transform.rotation.slerp(Quat::IDENTITY, 0.1);
} }
} }
} }
} }
pub fn handle_flashlight( pub fn handle_flashlight(
player_query: Query<&PlayerAction, With<Player>>, player_query: Query<&PlayerAction, With<Player>>,
mut flashlight_query: Query<&mut SpotLight, With<Flashlight>>, mut flashlight_query: Query<&mut SpotLight, With<Flashlight>>,

View File

@@ -40,7 +40,7 @@ fn bottom_panel(
) { ) {
let item = single!(player_item_query); let item = single!(player_item_query);
let item = item.0.and_then(|id| item_query.get(id).ok()); let item = item.0.and_then(|id| item_query.get(id).ok());
let (name, icon) = item.map_or((Name::new(""), None), |(name, handle)| { let (name, icon) = item.map_or((Name::new(""), None), |(name, handle)| {
( (
name.clone(), name.clone(),
Some(egui_ctx.add_image(handle.0.clone_weak())), Some(egui_ctx.add_image(handle.0.clone_weak())),
@@ -82,8 +82,8 @@ fn bottom_panel(
)); ));
} }
None => { None => {
ui.label(egui::RichText::new("").size(24.0));
ui.label(egui::RichText::new("Empty").size(12.0)); ui.label(egui::RichText::new("Empty").size(12.0));
return;
} }
} }
ui.label( ui.label(