docs: add comments

This commit is contained in:
Kristofers Solo 2025-01-05 20:10:01 +02:00
parent cfaf565891
commit 3d158a4e7c
9 changed files with 147 additions and 15 deletions

View File

@ -10,6 +10,12 @@ use crate::{
use bevy::prelude::*; use bevy::prelude::*;
/// Move floor entities to their target Y positions based on movement speed
///
/// # Behavior
/// - Calculates movement distance based on player speed and delta time
/// - Moves floors towards their target Y position
/// - Removes FloorYTarget component when floor reaches destination
pub fn move_floors( pub fn move_floors(
mut commands: Commands, mut commands: Commands,
mut maze_query: Query<(Entity, &mut Transform, &FloorYTarget), With<FloorYTarget>>, mut maze_query: Query<(Entity, &mut Transform, &FloorYTarget), With<FloorYTarget>>,
@ -30,6 +36,13 @@ pub fn move_floors(
} }
} }
/// Handle floor transition events by setting up floor movement targets
///
/// # Behavior
/// - Checks if any floors are currently moving
/// - Processes floor transition events
/// - Sets target Y positions for all maze entities
/// - Updates current and next floor designations
pub fn handle_floor_transition_events( pub fn handle_floor_transition_events(
mut commands: Commands, mut commands: Commands,
mut maze_query: Query<(Entity, &Transform, &Floor, Option<&FloorYTarget>), With<HexMaze>>, mut maze_query: Query<(Entity, &Transform, &Floor, Option<&FloorYTarget>), With<HexMaze>>,

View File

@ -1,8 +1,14 @@
//! Maze asset management and generation.
//!
//! Module handles the creation and management of meshes and materials
//! used in the maze visualization, including hexagonal tiles and walls.
use super::resources::GlobalMazeConfig; use super::resources::GlobalMazeConfig;
use crate::{ use crate::{
constants::WALL_OVERLAP_MODIFIER, constants::WALL_OVERLAP_MODIFIER,
theme::{palette::rose_pine::RosePineDawn, prelude::ColorScheme}, theme::{palette::rose_pine::RosePineDawn, prelude::ColorScheme},
}; };
use bevy::{prelude::*, utils::HashMap}; use bevy::{prelude::*, utils::HashMap};
use std::f32::consts::FRAC_PI_2; use std::f32::consts::FRAC_PI_2;
use strum::IntoEnumIterator; use strum::IntoEnumIterator;
@ -10,15 +16,26 @@ use strum::IntoEnumIterator;
const HEX_SIDES: u32 = 6; const HEX_SIDES: u32 = 6;
const WHITE_EMISSION_INTENSITY: f32 = 10.; const WHITE_EMISSION_INTENSITY: f32 = 10.;
/// Collection of mesh and material assets used in maze rendering.
///
/// This struct contains all the necessary assets for rendering maze components,
/// including hexagonal tiles, walls, and custom colored materials.
#[derive(Debug)]
pub struct MazeAssets { pub struct MazeAssets {
/// Mesh for hexagonal floor tiles
pub hex_mesh: Handle<Mesh>, pub hex_mesh: Handle<Mesh>,
/// Mesh for wall segments
pub wall_mesh: Handle<Mesh>, pub wall_mesh: Handle<Mesh>,
/// Default material for hexagonal tiles
pub hex_material: Handle<StandardMaterial>, pub hex_material: Handle<StandardMaterial>,
/// Default material for walls
pub wall_material: Handle<StandardMaterial>, pub wall_material: Handle<StandardMaterial>,
/// Custom materials mapped to specific colors from the RosePineDawn palette
pub custom_materials: HashMap<RosePineDawn, Handle<StandardMaterial>>, pub custom_materials: HashMap<RosePineDawn, Handle<StandardMaterial>>,
} }
impl MazeAssets { impl MazeAssets {
/// Creates a new instance of MazeAssets with all necessary meshes and materials.
pub fn new( pub fn new(
meshes: &mut ResMut<Assets<Mesh>>, meshes: &mut ResMut<Assets<Mesh>>,
materials: &mut ResMut<Assets<StandardMaterial>>, materials: &mut ResMut<Assets<StandardMaterial>>,
@ -43,6 +60,7 @@ impl MazeAssets {
} }
} }
/// Generates a hexagonal mesh for floor tiles.
fn generate_hex_mesh(radius: f32, depth: f32) -> Mesh { fn generate_hex_mesh(radius: f32, depth: f32) -> Mesh {
let hexagon = RegularPolygon { let hexagon = RegularPolygon {
sides: HEX_SIDES, sides: HEX_SIDES,
@ -54,6 +72,7 @@ fn generate_hex_mesh(radius: f32, depth: f32) -> Mesh {
Mesh::from(prism_shape).rotated_by(rotation) Mesh::from(prism_shape).rotated_by(rotation)
} }
/// Generates a square mesh for wall segments.
fn generate_square_mesh(depth: f32, wall_size: f32) -> Mesh { fn generate_square_mesh(depth: f32, wall_size: f32) -> Mesh {
let square = Rectangle::new(wall_size, wall_size); let square = Rectangle::new(wall_size, wall_size);
let rectangular_prism = Extrusion::new(square, depth); let rectangular_prism = Extrusion::new(square, depth);
@ -62,6 +81,7 @@ fn generate_square_mesh(depth: f32, wall_size: f32) -> Mesh {
Mesh::from(rectangular_prism).rotated_by(rotation) Mesh::from(rectangular_prism).rotated_by(rotation)
} }
/// Creates a glowing white material for default tile appearance.
pub fn white_material() -> StandardMaterial { pub fn white_material() -> StandardMaterial {
StandardMaterial { StandardMaterial {
emissive: LinearRgba::new( emissive: LinearRgba::new(

View File

@ -1,6 +1,11 @@
//! Maze components and configuration.
//!
//! Module defines the core components and configuration structures used
//! for maze generation and rendering, including hexagonal maze layouts,
//! tiles, walls, and maze configuration.
use super::GlobalMazeConfig;
use crate::floor::components::Floor; use crate::floor::components::Floor;
use super::GlobalMazeConfig;
use bevy::prelude::*; use bevy::prelude::*;
use hexlab::Maze; use hexlab::Maze;
use hexx::{Hex, HexLayout, HexOrientation}; use hexx::{Hex, HexLayout, HexOrientation};
@ -19,17 +24,27 @@ pub struct Tile;
#[reflect(Component)] #[reflect(Component)]
pub struct Wall; pub struct Wall;
/// Configuration for a single maze instance.
///
/// Contains all necessary parameters to generate and position a maze,
/// including its size, start/end positions, random seed, and layout.
#[derive(Debug, Reflect, Component, Clone)] #[derive(Debug, Reflect, Component, Clone)]
#[reflect(Component)] #[reflect(Component)]
pub struct MazeConfig { pub struct MazeConfig {
/// Radius of the hexagonal maze
pub radius: u16, pub radius: u16,
/// Starting position in hex coordinates
pub start_pos: Hex, pub start_pos: Hex,
/// Ending position in hex coordinates
pub end_pos: Hex, pub end_pos: Hex,
/// Random seed for maze generation
pub seed: u64, pub seed: u64,
/// Layout configuration for hex-to-world space conversion
pub layout: HexLayout, pub layout: HexLayout,
} }
impl MazeConfig { impl MazeConfig {
/// Creates a new maze configuration with the specified parameters.
fn new( fn new(
radius: u16, radius: u16,
orientation: HexOrientation, orientation: HexOrientation,
@ -71,6 +86,7 @@ impl MazeConfig {
} }
} }
/// Updates the maze configuration with new global settings.
pub fn update(&mut self, global_conig: &GlobalMazeConfig) { pub fn update(&mut self, global_conig: &GlobalMazeConfig) {
self.layout.hex_size = Vec2::splat(global_conig.hex_size); self.layout.hex_size = Vec2::splat(global_conig.hex_size);
} }
@ -88,6 +104,10 @@ impl Default for MazeConfig {
} }
} }
/// Generates a random position within a hexagonal radius.
///
/// # Returns
/// A valid Hex coordinate within the specified radius
fn generate_pos<R: Rng>(radius: u16, rng: &mut R) -> Hex { fn generate_pos<R: Rng>(radius: u16, rng: &mut R) -> Hex {
let radius = radius as i32; let radius = radius as i32;
loop { loop {

View File

@ -1,10 +1,23 @@
use crate::maze::{ //! Common maze generation utilities.
components::MazeConfig, use crate::maze::{components::MazeConfig, errors::MazeError};
errors::{MazeError, MazeResult},
};
use hexlab::prelude::*; use hexlab::prelude::*;
pub fn generate_maze(config: &MazeConfig) -> MazeResult<Maze> { /// Generates a new maze based on the provided configuration.
///
/// This function uses a recursive backtracking algorithm to generate
/// a hexagonal maze with the specified parameters.
///
/// # Arguments
/// - `config` - Configuration parameters for maze generation including radius and seed.
///
/// # Returns
/// `Result<Maze, MazeError>` - The generated maze or an error if generation fails.
///
/// # Errors
/// Returns `MazeError::GenerationFailed` if:
/// - The maze builder fails to create a valid maze
/// - The provided radius or seed results in an invalid configuration
pub fn generate_maze(config: &MazeConfig) -> Result<Maze, MazeError> {
MazeBuilder::new() MazeBuilder::new()
.with_radius(config.radius) .with_radius(config.radius)
.with_seed(config.seed) .with_seed(config.seed)

View File

@ -1,7 +1,13 @@
//! Maze despawning functionality.
//!
//! Module handles the cleanup of maze entities when they need to be removed,
//! ensuring proper cleanup of both the maze and all its child entities.
use crate::{floor::components::Floor, maze::events::DespawnMaze}; use crate::{floor::components::Floor, maze::events::DespawnMaze};
use bevy::prelude::*; use bevy::prelude::*;
pub(super) fn despawn_maze( /// Despawns a maze and all its associated entities for a given floor.
pub fn despawn_maze(
trigger: Trigger<DespawnMaze>, trigger: Trigger<DespawnMaze>,
mut commands: Commands, mut commands: Commands,
query: Query<(Entity, &Floor)>, query: Query<(Entity, &Floor)>,

View File

@ -1,3 +1,8 @@
//! Maze respawning functionality.
//!
//! Module provides the ability to regenerate mazes for existing floors,
//! maintaining the same floor entity but replacing its internal maze structure.
use super::{common::generate_maze, spawn::spawn_maze_tiles}; use super::{common::generate_maze, spawn::spawn_maze_tiles};
use crate::{ use crate::{
floor::components::Floor, floor::components::Floor,
@ -6,7 +11,15 @@ use crate::{
use bevy::prelude::*; use bevy::prelude::*;
use hexlab::Maze; use hexlab::Maze;
pub(super) fn respawn_maze( /// Respawns a maze for an existing floor with a new configuration.
///
/// # Behavior:
/// - Finds the target floor
/// - Generates a new maze configuration
/// - Cleans up existing maze tiles
/// - Spawns new maze tiles
/// - Updates the floor's configuration
pub fn respawn_maze(
trigger: Trigger<RespawnMaze>, trigger: Trigger<RespawnMaze>,
mut commands: Commands, mut commands: Commands,
mut meshes: ResMut<Assets<Mesh>>, mut meshes: ResMut<Assets<Mesh>>,

View File

@ -1,3 +1,7 @@
//! Maze spawning and rendering functionality.
//!
//! Module handles the creation and visualization of hexagonal mazes.
use super::common::generate_maze; use super::common::generate_maze;
use crate::{ use crate::{
constants::FLOOR_Y_OFFSET, constants::FLOOR_Y_OFFSET,
@ -20,6 +24,7 @@ use hexlab::prelude::{Tile as HexTile, *};
use hexx::HexOrientation; use hexx::HexOrientation;
use std::f32::consts::{FRAC_PI_2, FRAC_PI_3, FRAC_PI_6}; use std::f32::consts::{FRAC_PI_2, FRAC_PI_3, FRAC_PI_6};
/// Spawns a new maze for the specified floor on [`SpawnMaze`] event.
pub fn spawn_maze( pub fn spawn_maze(
trigger: Trigger<SpawnMaze>, trigger: Trigger<SpawnMaze>,
mut commands: Commands, mut commands: Commands,
@ -44,9 +49,10 @@ pub fn spawn_maze(
} }
}; };
// Calculate vertical offset based on floor number
let y_offset = match *floor { let y_offset = match *floor {
1 => 0, 1 => 0, // Ground/Initial floor (floor 1) is at y=0
_ => FLOOR_Y_OFFSET, _ => FLOOR_Y_OFFSET, // Other floors are offset vertically
} as f32; } as f32;
let entity = commands let entity = commands
@ -60,7 +66,7 @@ pub fn spawn_maze(
Visibility::Visible, Visibility::Visible,
StateScoped(Screen::Gameplay), StateScoped(Screen::Gameplay),
)) ))
.insert_if(CurrentFloor, || *floor == 1) .insert_if(CurrentFloor, || *floor == 1) // Only floor 1 gets CurrentFloor
.id(); .id();
let assets = MazeAssets::new(&mut meshes, &mut materials, &global_config); let assets = MazeAssets::new(&mut meshes, &mut materials, &global_config);
@ -79,6 +85,7 @@ pub fn spawn_maze(
} }
} }
/// Spawns all tiles for a maze as children of the parent maze entity
pub fn spawn_maze_tiles( pub fn spawn_maze_tiles(
commands: &mut Commands, commands: &mut Commands,
parent_entity: Entity, parent_entity: Entity,
@ -94,6 +101,7 @@ pub fn spawn_maze_tiles(
}); });
} }
/// Spawns a single hexagonal tile with appropriate transforms and materials
pub(super) fn spawn_single_hex_tile( pub(super) fn spawn_single_hex_tile(
parent: &mut ChildBuilder, parent: &mut ChildBuilder,
assets: &MazeAssets, assets: &MazeAssets,
@ -107,6 +115,7 @@ pub(super) fn spawn_single_hex_tile(
HexOrientation::Flat => Quat::from_rotation_y(FRAC_PI_6), // 30 degrees rotation HexOrientation::Flat => Quat::from_rotation_y(FRAC_PI_6), // 30 degrees rotation
}; };
// Select material based on tile position: start, end, or default
let material = match tile.pos() { let material = match tile.pos() {
pos if pos == maze_config.start_pos => assets pos if pos == maze_config.start_pos => assets
.custom_materials .custom_materials
@ -132,12 +141,14 @@ pub(super) fn spawn_single_hex_tile(
.with_children(|parent| spawn_walls(parent, assets, tile.walls(), global_config)); .with_children(|parent| spawn_walls(parent, assets, tile.walls(), global_config));
} }
/// Spawns walls around a hexagonal tile based on the walls configuration
fn spawn_walls( fn spawn_walls(
parent: &mut ChildBuilder, parent: &mut ChildBuilder,
assets: &MazeAssets, assets: &MazeAssets,
walls: &Walls, walls: &Walls,
global_config: &GlobalMazeConfig, global_config: &GlobalMazeConfig,
) { ) {
// Base rotation for wall alignment (90 degrees counter-clockwise)
let z_rotation = Quat::from_rotation_z(-FRAC_PI_2); let z_rotation = Quat::from_rotation_z(-FRAC_PI_2);
let y_offset = global_config.height / 2.; let y_offset = global_config.height / 2.;
@ -146,12 +157,25 @@ fn spawn_walls(
continue; continue;
} }
// Calculate the angle for this wall
// FRAC_PI_3 = 60 deg
// Negative because going clockwise
// i * 60 produces: 0, 60, 120, 180, 240, 300
let wall_angle = -FRAC_PI_3 * i as f32; let wall_angle = -FRAC_PI_3 * i as f32;
// cos(angle) gives x coordinate on unit circle
// sin(angle) gives z coordinate on unit circle
// Multiply by wall_offset to get actual distance from center
let x_offset = global_config.wall_offset() * f32::cos(wall_angle); let x_offset = global_config.wall_offset() * f32::cos(wall_angle);
let z_offset = global_config.wall_offset() * f32::sin(wall_angle); let z_offset = global_config.wall_offset() * f32::sin(wall_angle);
// x: distance along x-axis from center
// y: vertical offset from center
// z: distance along z-axis from center
let pos = Vec3::new(x_offset, y_offset, z_offset); let pos = Vec3::new(x_offset, y_offset, z_offset);
// 1. Rotate around x-axis to align wall with angle
// 2. Add FRAC_PI_2 (90) to make wall perpendicular to angle
let x_rotation = Quat::from_rotation_x(wall_angle + FRAC_PI_2); let x_rotation = Quat::from_rotation_x(wall_angle + FRAC_PI_2);
let final_rotation = z_rotation * x_rotation; let final_rotation = z_rotation * x_rotation;
@ -159,6 +183,7 @@ fn spawn_walls(
} }
} }
/// Spawns a single wall segment with the specified rotation and position
fn spawn_single_wall(parent: &mut ChildBuilder, assets: &MazeAssets, rotation: Quat, offset: Vec3) { fn spawn_single_wall(parent: &mut ChildBuilder, assets: &MazeAssets, rotation: Quat, offset: Vec3) {
parent.spawn(( parent.spawn((
Name::new("Wall"), Name::new("Wall"),

View File

@ -1,13 +1,22 @@
//! Player movement system and related utilities.
//!
//! This module handles smooth player movement between hexagonal tiles,
//! including position interpolation and movement completion detection.
use crate::{ use crate::{
constants::MOVEMENT_THRESHOLD, constants::MOVEMENT_THRESHOLD,
floor::components::CurrentFloor, floor::components::CurrentFloor,
maze::components::MazeConfig, maze::components::MazeConfig,
player::components::{CurrentPosition, MovementSpeed, MovementTarget, Player}, player::components::{CurrentPosition, MovementSpeed, MovementTarget, Player},
}; };
use bevy::prelude::*; use bevy::prelude::*;
use hexx::Hex; use hexx::Hex;
pub(super) fn player_movement( /// System handles player movement between hexagonal tiles.
///
/// Smoothly interpolates player position between hexagonal tiles,
/// handling movement target acquisition, position updates, and movement completion.
pub fn player_movement(
time: Res<Time>, time: Res<Time>,
mut query: Query< mut query: Query<
( (
@ -48,10 +57,12 @@ pub(super) fn player_movement(
} }
} }
/// Determines if the movement should be completed based on proximity to target.
fn should_complete_movement(current_pos: Vec3, target_pos: Vec3) -> bool { fn should_complete_movement(current_pos: Vec3, target_pos: Vec3) -> bool {
(target_pos - current_pos).length() < MOVEMENT_THRESHOLD (target_pos - current_pos).length() < MOVEMENT_THRESHOLD
} }
/// Updates the player's position based on movement parameters.
fn update_position( fn update_position(
transform: &mut Transform, transform: &mut Transform,
current_pos: Vec3, current_pos: Vec3,
@ -69,6 +80,7 @@ fn update_position(
transform.translation += movement; transform.translation += movement;
} }
/// Calculates the world position for a given hex coordinate.
fn calculate_target_position(maze_config: &MazeConfig, target_hex: Hex, y: f32) -> Vec3 { fn calculate_target_position(maze_config: &MazeConfig, target_hex: Hex, y: f32) -> Vec3 {
let world_pos = maze_config.layout.hex_to_world_pos(target_hex); let world_pos = maze_config.layout.hex_to_world_pos(target_hex);
Vec3::new(world_pos.x, y, world_pos.y) Vec3::new(world_pos.x, y, world_pos.y)

View File

@ -1,4 +1,8 @@
use bevy::prelude::*; //! Floor transition handling system.
//!
//! This module manages player transitions between different maze floors,
//! handling both ascending and descending movements based on player position
//! and input.
use crate::{ use crate::{
floor::{ floor::{
@ -9,6 +13,12 @@ use crate::{
player::components::{CurrentPosition, Player}, player::components::{CurrentPosition, Player},
}; };
use bevy::prelude::*;
/// Handles floor transitions when a player reaches start/end positions.
///
/// System checks if the player is at a valid transition point (start or end position)
/// and triggers floor transitions when the appropriate input is received.
pub fn handle_floor_transition( pub fn handle_floor_transition(
mut player_query: Query<&CurrentPosition, With<Player>>, mut player_query: Query<&CurrentPosition, With<Player>>,
maze_query: Query<(&MazeConfig, &Floor), With<CurrentFloor>>, maze_query: Query<(&MazeConfig, &Floor), With<CurrentFloor>>,
@ -25,13 +35,13 @@ pub fn handle_floor_transition(
}; };
for current_hex in player_query.iter_mut() { for current_hex in player_query.iter_mut() {
// Check for ascending // Check for ascending (at end position)
if current_hex.0 == config.end_pos { if current_hex.0 == config.end_pos {
info!("Ascending"); info!("Ascending");
event_writer.send(TransitionFloor::Ascend); event_writer.send(TransitionFloor::Ascend);
} }
// Check for descending // Check for descending (at start position, not on first floor)
if current_hex.0 == config.start_pos && floor.0 != 1 { if current_hex.0 == config.start_pos && floor.0 != 1 {
info!("Descending"); info!("Descending");
event_writer.send(TransitionFloor::Descend); event_writer.send(TransitionFloor::Descend);