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

View File

@@ -1,5 +1,8 @@
use bevy::{image, prelude::*, reflect::DynamicTypePath};
use std::collections::HashMap;
use bevy::prelude::*;
use bevy_rapier3d::prelude::*;
use rand::Rng;
use crate::{
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 collider: Vec<(Collider, Transform)> = match mesh_name {
"corner_inside" => 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, 0.1, 1.0),
Transform::from_xyz(0.0, 0.0, 0.0),
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())),
)],
"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![(
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![(
Collider::cuboid(1.0, 0.1, 1.0),
Transform::from_xyz(0.0, 0.0, 0.0),
Collider::cuboid(1.0, 1.0, 0.1),
Transform::from_xyz(0.0, 1.0, -1.0),
)],
"round_door" => vec![(
Collider::cuboid(1.0, 0.1, 1.0),
Transform::from_xyz(0.0, 0.0, 0.0),
)],
"round_hole" => vec![(
Collider::cuboid(1.0, 0.1, 1.0),
Transform::from_xyz(0.0, 0.0, 0.0),
Collider::cuboid(1.0, 1.0, 0.1),
Transform::from_xyz(0.0, 1.0, -1.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![(
Collider::cuboid(1.0, 0.1, 1.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,
round_door,
round_hole,
] = shapes;
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));
}
});
}
] = shapes.clone();
// huge floor
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),
Transform::from_xyz(-500.0, 0.0, -500.0),
));
commands.spawn((
RigidBody::Fixed,
Collider::cuboid(1000.0, 0.1, 1000.0),
Transform::from_xyz(-500.0, 3.0, -500.0),
));
// huge roof
// commands.spawn((
// RigidBody::Fixed,
// 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(
@@ -156,14 +562,13 @@ fn spawn_objects(
Transform::from_xyz(0.0, 2.0, 2.0),
Interact,
RigidBody::Dynamic,
Name::new("Id Card"),
Name::new("Id Card 1"),
Visibility::Visible,
ItemIcon::new(image_assets.id_card.clone()),
SceneRoot(asset.clone()),
))
.with_children(|parent| {
parent.spawn((
Visibility::Inherited,
ColliderMassProperties::Mass(10.0),
Collider::cuboid(0.05, 0.05, 0.01),
Transform::from_rotation(Quat::from_euler(
@@ -174,7 +579,6 @@ fn spawn_objects(
)),
));
parent.spawn((
Visibility::Inherited,
ActiveEvents::COLLISION_EVENTS,
Transform::default(),
Collider::ball(0.5), // Interaction radius