diff --git a/src/level_instantiation/mod.rs b/src/level_instantiation/mod.rs index 9012b09..777b8bf 100644 --- a/src/level_instantiation/mod.rs +++ b/src/level_instantiation/mod.rs @@ -2,7 +2,7 @@ use std::collections::HashMap; use bevy::prelude::*; use bevy_rapier3d::prelude::*; -use rand::Rng; +use rand::{Rng, seq::IteratorRandom}; use crate::{ GameState, @@ -18,13 +18,12 @@ pub fn map_plugin(app: &mut App) { ); } - fn spawn_level( mut commands: Commands, mut meshes: ResMut>, mut materials: ResMut>, models: Res>, - gltf_assets: Res + gltf_assets: Res, ) { println!("LIBRARY: {:?}", gltf_assets.library); let mesh_names = [ @@ -128,138 +127,228 @@ fn spawn_level( // 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::{Connection, Closed}; + 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()))) + ( + 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()))) + ( + 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()))) + ( + 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()))) + ( + 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()))) + ( + 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()))) + ( + 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()))) + ( + 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()))) + ( + 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()))) + ( + 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()))) + ( + 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()))) + ( + 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()))), + ( + 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())), + ), ] } - _ => vec![] + (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)); - } - }); + commands + .spawn((RigidBody::Fixed, scene_root, pos)) + .with_children(|parent| { + for (collider, transform) in colliders { + parent.spawn((collider, transform)); + } + }); } } - let (x,z) = level.end_node; + let (x, z) = level.end_node; commands.spawn(( Mesh3d(meshes.add(Cuboid::new(1.0, 20.0, 1.0))), MeshMaterial3d(materials.add(Color::srgb_u8(255, 0, 0))), - 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), )); } - commands.insert_resource(GameLevels {levels}); + commands.insert_resource(GameLevels { levels }); } - fn create_levels(n: i32) -> Vec { let mut maps = Vec::new(); let mut initial_node = LevelNode::new(); @@ -274,7 +363,7 @@ fn create_levels(n: i32) -> Vec { maps.push(map); - for _ in 0..n-1 { + for _ in 0..n - 1 { let map = maps.last().unwrap(); let mut pos = map.end_node.clone(); @@ -330,35 +419,40 @@ impl LevelNode { #[derive(Resource)] struct GameLevels { - pub levels: Vec + pub levels: Vec, } struct GameLevel { nodes: HashMap<(i32, i32), LevelNode>, end_node: (i32, i32), grid_size: i32, - initial_point: (i32, i32) + initial_point: (i32, i32), } impl GameLevel { fn new(initial_point: (i32, i32), node: LevelNode, grid_size: i32) -> Self { let mut nodes = HashMap::new(); nodes.insert(initial_point, node); - let mut m = GameLevel { initial_point, nodes, grid_size, end_node: initial_point}; + let mut m = GameLevel { + initial_point, + nodes, + grid_size, + end_node: initial_point, + }; m.generate_map(); m } fn generate_map(&mut self) { let mut first_point = self.initial_point.clone(); first_point.1 += 1; - self.create_node(first_point); // North + self.create_node(first_point); // North } fn pos_within_boundaries(&self, pos: (i32, i32)) -> bool { pos.0 > self.grid_size + self.initial_point.0 - || pos.1 > self.grid_size + self.initial_point.1 - || pos.0 < self.initial_point.0 - || pos.1 < self.initial_point.1 + || pos.1 > self.grid_size + self.initial_point.1 + || pos.0 < self.initial_point.0 + || pos.1 < self.initial_point.1 } fn choose_side(&self, pos: (i32, i32)) -> Side { @@ -374,22 +468,19 @@ impl GameLevel { } fn ensure_connection(&self, node: &mut LevelNode, (x, y): (i32, i32)) { - let am_connections = (node.north == Side::Connection) as u8 + - (node.south == Side::Connection) as u8 + - (node.east == Side::Connection) as u8 + - (node.west == Side::Connection) as u8; + let am_connections = (node.north == Side::Connection) as u8 + + (node.south == Side::Connection) as u8 + + (node.east == Side::Connection) as u8 + + (node.west == Side::Connection) as u8; if am_connections <= 2 { if node.north != Side::Connection && !self.nodes.contains_key(&(x, y + 1)) { node.north = Side::Connection - } - else if node.south != Side::Connection && !self.nodes.contains_key(&(x, y - 1)) { + } else if node.south != Side::Connection && !self.nodes.contains_key(&(x, y - 1)) { node.south = Side::Connection - } - else if node.east != Side::Connection && !self.nodes.contains_key(&(x + 1, y)) { + } else if node.east != Side::Connection && !self.nodes.contains_key(&(x + 1, y)) { node.east = Side::Connection - } - else if node.west != Side::Connection && !self.nodes.contains_key(&(x - 1, y)) { + } else if node.west != Side::Connection && !self.nodes.contains_key(&(x - 1, y)) { node.west = Side::Connection } } @@ -442,8 +533,7 @@ impl GameLevel { let end_node = self.nodes.get_mut(&self.end_node).unwrap(); if self.end_node.1 >= self.end_node.0 { end_node.north = Side::Connection; - } - else if self.end_node.0 >= self.end_node.1 { + } else if self.end_node.0 >= self.end_node.1 { end_node.east = Side::Connection; } } @@ -475,6 +565,7 @@ impl GameLevel { fn spawn_objects( mut commands: Commands, + levels: Res, models: Res>, gltf_assets: Res, image_assets: Res, @@ -483,86 +574,98 @@ fn spawn_objects( let card = models.get(&gltf_assets.card).unwrap(); let asset = card.default_scene.as_ref().unwrap(); - commands - .spawn(( - Transform::from_xyz(0.0, 2.0, 2.0), - Interact, - RigidBody::Dynamic, - Name::new("Id Card 1"), - 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, - )); - }); + for (i, level) in levels.levels.iter().enumerate() { + let begin_node = level.initial_point; + let end_node = level.end_node; + // take a random position that is not the beginning or end_node + 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, + RigidBody::Dynamic, + 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, + )); + }); + } } - fn spawn_doors( mut commands: Commands, levels: Res, models: Res>, - gltf_assets: Res -){ + gltf_assets: Res, +) { let collider: Vec<(Collider, Transform)> = vec![( Collider::cuboid(1.0, 1.0, 0.1), Transform::from_xyz(0.0, 1.0, -1.0), )]; - let path = format!("meshes/library/space_round_door.glb", ); - let handle = gltf_assets - .library - .get(&path) - .unwrap(); - let gltf = models - .get(handle) - .unwrap(); + let path = format!("meshes/library/space_round_door.glb",); + let handle = gltf_assets.library.get(&path).unwrap(); + let gltf = models.get(handle).unwrap(); - let asset = gltf - .default_scene - .as_ref() - .unwrap(); + let asset = gltf.default_scene.as_ref().unwrap(); let scene_root = SceneRoot(asset.clone()); - for level in levels.levels.iter() { let (x, z) = level.end_node; if x <= z { - commands.spawn(( - RigidBody::Fixed, - 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())), - scene_root.clone(), - )).with_children(|parent| { - for (collider, transform) in collider.clone() { - parent.spawn((collider, transform)); - } - }); + commands + .spawn(( + RigidBody::Fixed, + 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())), + scene_root.clone(), + )) + .with_children(|parent| { + for (collider, transform) in collider.clone() { + parent.spawn((collider, transform)); + } + }); } else { - commands.spawn(( - RigidBody::Dynamic, - Transform::from_xyz(2.0 * x as f32, 0.0, -2.0 * z as f32), - scene_root.clone(), - )).with_children(|parent| { - for (collider, transform) in collider.clone() { - parent.spawn((collider, transform)); - } - }); + commands + .spawn(( + RigidBody::Dynamic, + Transform::from_xyz(2.0 * x as f32, 0.0, -2.0 * z as f32), + scene_root.clone(), + )) + .with_children(|parent| { + for (collider, transform) in collider.clone() { + parent.spawn((collider, transform)); + } + }); } } }