diff --git a/Cargo.lock b/Cargo.lock index 90d8ee5..eee077a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2673,10 +2673,11 @@ dependencies = [ [[package]] name = "maze-ascension" -version = "0.1.0" +version = "0.0.6" dependencies = [ "bevy", "bevy-inspector-egui", + "bevy_egui", "hexlab", "hexx", "log", diff --git a/Cargo.toml b/Cargo.toml index e4b23c0..8f92d8a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "maze-ascension" authors = ["Kristofers Solo "] -version = "0.1.0" +version = "0.0.6" edition = "2021" [dependencies] @@ -20,6 +20,7 @@ tracing = { version = "0.1", features = [ hexx = { version = "0.18", features = ["bevy_reflect", "grid"] } hexlab = { version = "0.1", features = ["bevy"] } bevy-inspector-egui = { version = "0.27", optional = true } +bevy_egui = { version = "0.30", optional = true } [features] @@ -32,6 +33,7 @@ dev = [ "bevy/dynamic_linking", "bevy/bevy_dev_tools", "dep:bevy-inspector-egui", + "dep:bevy_egui", ] dev_native = [ "dev", diff --git a/src/maze/assets.rs b/src/maze/assets.rs new file mode 100644 index 0000000..539f4a6 --- /dev/null +++ b/src/maze/assets.rs @@ -0,0 +1,56 @@ +use std::f32::consts::FRAC_PI_2; + +use bevy::prelude::*; + +use super::{ + resources::{HEX_SIZE, WALL_SIZE}, + MazeConfig, +}; + +pub(crate) struct MazeAssets { + pub(crate) hex_mesh: Handle, + pub(crate) wall_mesh: Handle, + pub(crate) hex_material: Handle, + pub(crate) wall_material: Handle, +} + +pub(crate) fn create_base_assets( + meshes: &mut ResMut>, + materials: &mut ResMut>, + config: &Res, +) -> MazeAssets { + MazeAssets { + hex_mesh: meshes.add(generate_hex_mesh(HEX_SIZE, config.height)), + wall_mesh: meshes.add(generate_square_mesh(HEX_SIZE)), + hex_material: materials.add(white_material()), + wall_material: materials.add(Color::BLACK), + } +} + +fn generate_hex_mesh(radius: f32, depth: f32) -> Mesh { + let hexagon = RegularPolygon { + sides: 6, + circumcircle: Circle::new(radius), + }; + let prism_shape = Extrusion::new(hexagon, depth); + let rotation = Quat::from_rotation_x(FRAC_PI_2); + + Mesh::from(prism_shape).rotated_by(rotation) +} + +fn generate_square_mesh(depth: f32) -> Mesh { + let square = Rectangle::new(WALL_SIZE, WALL_SIZE); + let rectangular_prism = Extrusion::new(square, depth); + let rotation = Quat::from_rotation_x(FRAC_PI_2); + + Mesh::from(rectangular_prism).rotated_by(rotation) +} + +fn white_material() -> StandardMaterial { + let val = 10.; + StandardMaterial { + base_color: Color::WHITE, + emissive: LinearRgba::new(val, val, val, val), + ..default() + } +} diff --git a/src/maze/components.rs b/src/maze/components.rs new file mode 100644 index 0000000..2cb53b4 --- /dev/null +++ b/src/maze/components.rs @@ -0,0 +1,9 @@ +use bevy::prelude::*; + +#[derive(Debug, Reflect, Component)] +#[reflect(Component)] +pub(crate) struct MazeWall; + +#[derive(Debug, Reflect, Component)] +#[reflect(Component)] +pub(crate) struct MazeTile; diff --git a/src/maze/mod.rs b/src/maze/mod.rs index 94f0bdd..23064f0 100644 --- a/src/maze/mod.rs +++ b/src/maze/mod.rs @@ -1,8 +1,12 @@ use bevy::{ecs::world::Command, prelude::*}; use plugin::MazePlugin; +mod assets; +mod components; pub mod plugin; -pub mod prism; -pub mod resource; +mod resources; +mod systems; + +pub use resources::MazeConfig; pub fn spawn_grid(world: &mut World) { MazePlugin.apply(world); diff --git a/src/maze/plugin.rs b/src/maze/plugin.rs index ad31ce9..b08bb06 100644 --- a/src/maze/plugin.rs +++ b/src/maze/plugin.rs @@ -3,27 +3,19 @@ use bevy::{ prelude::*, }; -use super::prism; +use super::{resources::Layout, systems, MazeConfig}; #[derive(Default)] pub(crate) struct MazePlugin; impl Plugin for MazePlugin { fn build(&self, app: &mut App) { - app.add_plugins(prism::plugin); - // app.add_plugins(grid::plugin); - // app.insert_resource(AmbientLight { - // brightness: f32::MAX, - // color: Color::WHITE, - // }); + app.init_resource::().init_resource::(); } } impl Command for MazePlugin { fn apply(self, world: &mut World) { - // world.run_system_once(spawn_hex_grid); - // world.run_system_once(generate_maze); - // world.run_system_once(render_maze); - world.run_system_once(prism::setup); + world.run_system_once(systems::setup::setup); } } diff --git a/src/maze/prism.rs b/src/maze/prism.rs deleted file mode 100644 index cc3e7e8..0000000 --- a/src/maze/prism.rs +++ /dev/null @@ -1,154 +0,0 @@ -use super::resource::{Layout, MazeConfig, HEX_SIZE}; -use bevy::prelude::*; -use core::f32; -use hexlab::prelude::*; -use hexx::{HexLayout, HexOrientation}; -use std::f32::consts::{FRAC_PI_2, FRAC_PI_3, FRAC_PI_6}; - -pub(super) fn plugin(app: &mut App) { - app.init_resource::(); - app.init_resource::(); -} -const WALL_SIZE: f32 = 1.0; - -pub(super) fn setup( - mut commands: Commands, - mut meshes: ResMut>, - mut materials: ResMut>, - config: Res, - layout: Res, -) { - let maze = MazeBuilder::new() - .with_radius(config.radius) - // .with_seed(0) - .with_generator(GeneratorType::RecursiveBacktracking) - .build() - .expect("Something went wrong while creating maze"); - - let assets = create_base_assets(&mut meshes, &mut materials, &config); - commands - .spawn(( - Name::new("Floor"), - SpatialBundle { - transform: Transform::from_translation(Vec3::ZERO), - ..default() - }, - )) - .with_children(|parent| { - for tile in maze.values() { - spawn_single_hex_tile(parent, &assets, tile, &layout.0, config.height) - } - }); -} - -fn spawn_single_hex_tile( - parent: &mut ChildBuilder, - assets: &MazeAssets, - tile: &HexTile, - layout: &HexLayout, - hex_height: f32, -) { - let world_pos = tile.to_vec3(layout); - let rotation = match layout.orientation { - HexOrientation::Pointy => Quat::from_rotation_y(0.0), - HexOrientation::Flat => Quat::from_rotation_y(FRAC_PI_6), // 30 degrees rotation - }; - - parent - .spawn(( - Name::new(format!("Hex {}", tile.to_string())), - PbrBundle { - mesh: assets.hex_mesh.clone(), - material: assets.hex_material.clone(), - transform: Transform::from_translation(world_pos).with_rotation(rotation), - ..default() - }, - )) - .with_children(|parent| spawn_walls(parent, assets, hex_height / 2., &tile.walls())); -} - -fn spawn_walls(parent: &mut ChildBuilder, assets: &MazeAssets, y_offset: f32, walls: &Walls) { - let z_rotation = Quat::from_rotation_z(-FRAC_PI_2); - - for i in 0..6 { - if !walls.contains(i) { - continue; - } - - let wall_angle = -FRAC_PI_3 * i as f32; - - let x_offset = (HEX_SIZE - WALL_SIZE) * f32::cos(wall_angle); - let z_offset = (HEX_SIZE - WALL_SIZE) * f32::sin(wall_angle); - let pos = Vec3::new(x_offset, y_offset, z_offset); - - let x_rotation = Quat::from_rotation_x(wall_angle + FRAC_PI_2); - let final_rotation = z_rotation * x_rotation; - - spawn_single_wall(parent, assets, final_rotation, pos); - } -} - -fn spawn_single_wall( - parent: &mut ChildBuilder, - asstets: &MazeAssets, - rotation: Quat, - offset: Vec3, -) { - parent.spawn(( - Name::new("Wall"), - PbrBundle { - mesh: asstets.wall_mesh.clone(), - material: asstets.wall_material.clone(), - transform: Transform::from_translation(offset).with_rotation(rotation), - ..default() - }, - )); -} - -fn create_base_assets( - meshes: &mut ResMut>, - materials: &mut ResMut>, - config: &Res, -) -> MazeAssets { - MazeAssets { - hex_mesh: meshes.add(generate_hex_mesh(HEX_SIZE, config.height)), - wall_mesh: meshes.add(generate_square_mesh(HEX_SIZE)), - hex_material: materials.add(white_material()), - wall_material: materials.add(Color::BLACK), - } -} - -fn generate_hex_mesh(radius: f32, depth: f32) -> Mesh { - let hexagon = RegularPolygon { - sides: 6, - circumcircle: Circle::new(radius), - }; - let prism_shape = Extrusion::new(hexagon, depth); - let rotation = Quat::from_rotation_x(FRAC_PI_2); - - Mesh::from(prism_shape).rotated_by(rotation) -} - -fn generate_square_mesh(depth: f32) -> Mesh { - let square = Rectangle::new(WALL_SIZE, WALL_SIZE); - let rectangular_prism = Extrusion::new(square, depth); - let rotation = Quat::from_rotation_x(FRAC_PI_2); - - Mesh::from(rectangular_prism).rotated_by(rotation) -} - -fn white_material() -> StandardMaterial { - let val = 10.; - StandardMaterial { - base_color: Color::WHITE, - emissive: LinearRgba::new(val, val, val, val), - ..default() - } -} - -struct MazeAssets { - hex_mesh: Handle, - wall_mesh: Handle, - hex_material: Handle, - wall_material: Handle, -} diff --git a/src/maze/resource.rs b/src/maze/resources.rs similarity index 97% rename from src/maze/resource.rs rename to src/maze/resources.rs index 0bc2f84..ccc9d6b 100644 --- a/src/maze/resource.rs +++ b/src/maze/resources.rs @@ -3,6 +3,7 @@ use hexx::{Hex, HexLayout, HexOrientation}; use rand::{thread_rng, Rng}; pub(crate) const HEX_SIZE: f32 = 6.; +pub(crate) const WALL_SIZE: f32 = 1.0; #[derive(Debug, Reflect, Resource)] #[reflect(Resource)] diff --git a/src/maze/systems/mod.rs b/src/maze/systems/mod.rs new file mode 100644 index 0000000..c525b54 --- /dev/null +++ b/src/maze/systems/mod.rs @@ -0,0 +1,2 @@ +pub mod setup; +mod spawn; diff --git a/src/maze/systems/setup.rs b/src/maze/systems/setup.rs new file mode 100644 index 0000000..c00ee92 --- /dev/null +++ b/src/maze/systems/setup.rs @@ -0,0 +1,36 @@ +use bevy::prelude::*; +use hexlab::{GeneratorType, MazeBuilder}; + +use crate::maze::{assets::create_base_assets, resources::Layout, MazeConfig}; + +use super::spawn::spawn_single_hex_tile; + +pub(crate) fn setup( + mut commands: Commands, + mut meshes: ResMut>, + mut materials: ResMut>, + config: Res, + layout: Res, +) { + let maze = MazeBuilder::new() + .with_radius(config.radius) + // .with_seed(0) + .with_generator(GeneratorType::RecursiveBacktracking) + .build() + .expect("Something went wrong while creating maze"); + + let assets = create_base_assets(&mut meshes, &mut materials, &config); + commands + .spawn(( + Name::new("Floor"), + SpatialBundle { + transform: Transform::from_translation(Vec3::ZERO), + ..default() + }, + )) + .with_children(|parent| { + for tile in maze.values() { + spawn_single_hex_tile(parent, &assets, tile, &layout.0, config.height) + } + }); +} diff --git a/src/maze/systems/spawn.rs b/src/maze/systems/spawn.rs new file mode 100644 index 0000000..25b13db --- /dev/null +++ b/src/maze/systems/spawn.rs @@ -0,0 +1,74 @@ +use std::f32::consts::{FRAC_PI_2, FRAC_PI_3, FRAC_PI_6}; + +use bevy::prelude::*; +use hexlab::prelude::*; +use hexx::HexOrientation; + +use crate::maze::{ + assets::MazeAssets, + resources::{HEX_SIZE, WALL_SIZE}, +}; + +pub(super) fn spawn_single_hex_tile( + parent: &mut ChildBuilder, + assets: &MazeAssets, + tile: &HexTile, + layout: &HexLayout, + hex_height: f32, +) { + let world_pos = tile.to_vec3(layout); + let rotation = match layout.orientation { + HexOrientation::Pointy => Quat::from_rotation_y(0.0), + HexOrientation::Flat => Quat::from_rotation_y(FRAC_PI_6), // 30 degrees rotation + }; + + parent + .spawn(( + Name::new(format!("Hex {}", tile.to_string())), + PbrBundle { + mesh: assets.hex_mesh.clone(), + material: assets.hex_material.clone(), + transform: Transform::from_translation(world_pos).with_rotation(rotation), + ..default() + }, + )) + .with_children(|parent| spawn_walls(parent, assets, hex_height / 2., &tile.walls())); +} + +fn spawn_walls(parent: &mut ChildBuilder, assets: &MazeAssets, y_offset: f32, walls: &Walls) { + let z_rotation = Quat::from_rotation_z(-FRAC_PI_2); + + for i in 0..6 { + if !walls.contains(i) { + continue; + } + + let wall_angle = -FRAC_PI_3 * i as f32; + + let x_offset = (HEX_SIZE - WALL_SIZE) * f32::cos(wall_angle); + let z_offset = (HEX_SIZE - WALL_SIZE) * f32::sin(wall_angle); + let pos = Vec3::new(x_offset, y_offset, z_offset); + + let x_rotation = Quat::from_rotation_x(wall_angle + FRAC_PI_2); + let final_rotation = z_rotation * x_rotation; + + spawn_single_wall(parent, assets, final_rotation, pos); + } +} + +fn spawn_single_wall( + parent: &mut ChildBuilder, + asstets: &MazeAssets, + rotation: Quat, + offset: Vec3, +) { + parent.spawn(( + Name::new("Wall"), + PbrBundle { + mesh: asstets.wall_mesh.clone(), + material: asstets.wall_material.clone(), + transform: Transform::from_translation(offset).with_rotation(rotation), + ..default() + }, + )); +}