From 70579168a2ecd387486c72649009d67dcee42e83 Mon Sep 17 00:00:00 2001 From: Kristofers Solo Date: Tue, 17 Sep 2024 22:10:24 +0300 Subject: [PATCH 01/20] chore: bump version to 0.0.3 --- Cargo.lock | 2 +- Cargo.toml | 2 +- src/lib.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d60e648..3dbaade 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3597,7 +3597,7 @@ dependencies = [ [[package]] name = "the-labyrinth-of-echoes" -version = "0.0.1" +version = "0.0.3" dependencies = [ "bevy", "log", diff --git a/Cargo.toml b/Cargo.toml index 272de97..92fd13f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "the-labyrinth-of-echoes" authors = ["Kristofers Solo "] -version = "0.0.1" +version = "0.0.3" edition = "2021" [dependencies] diff --git a/src/lib.rs b/src/lib.rs index ce0492c..8da505d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -37,7 +37,7 @@ impl Plugin for AppPlugin { }) .set(WindowPlugin { primary_window: Window { - title: "The Labyrinth Of Echoes".to_string(), + title: "The Labyrinth of Echoes".to_string(), canvas: Some("#bevy".to_string()), fit_canvas_to_parent: true, prevent_default_event_handling: true, From 3f0ba6d0d8157a1e1de04580bb6c0b9685f82eef Mon Sep 17 00:00:00 2001 From: Kristofers Solo Date: Tue, 17 Sep 2024 22:10:39 +0300 Subject: [PATCH 02/20] chore: add justfile --- justfile | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 justfile diff --git a/justfile b/justfile new file mode 100644 index 0000000..56e184f --- /dev/null +++ b/justfile @@ -0,0 +1,20 @@ +# Default recipe +default: + @just --list + +# Run native dev +native-dev: + RUST_BACKTRACE=full cargo run + +# Run native release +native-release: + cargo run --release --no-default-features + +# Run web dev +web-dev: + RUST_BACKTRACE=full trunk serve + +# Run web release +web-release: + trunk serve --release --no-default-features + From 0a6464194181cbb393aaedbf05fb675c93fb6e44 Mon Sep 17 00:00:00 2001 From: Kristofers Solo Date: Wed, 18 Sep 2024 13:05:58 +0300 Subject: [PATCH 03/20] feat(hex): generate a hex grid --- Cargo.lock | 12 +++ Cargo.toml | 2 + src/lib.rs | 6 ++ src/screens/gameplay.rs | 9 +- src/screens/loading.rs | 7 +- src/tiles/level.rs | 20 +++++ src/tiles/mod.rs | 8 ++ src/tiles/player.rs | 112 ++++++++++++++++++++++++ src/tiles/tile.rs | 183 ++++++++++++++++++++++++++++++++++++++++ 9 files changed, 349 insertions(+), 10 deletions(-) create mode 100644 src/tiles/level.rs create mode 100644 src/tiles/mod.rs create mode 100644 src/tiles/player.rs create mode 100644 src/tiles/tile.rs diff --git a/Cargo.lock b/Cargo.lock index 3dbaade..aa2a063 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2137,6 +2137,17 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dfa686283ad6dd069f105e5ab091b04c62850d3e4cf5d67debad1933f55023df" +[[package]] +name = "hexx" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c40cfb11c06c0b7051c2c0df030c57c65921db962ee2b8e89de218bb749f173" +dependencies = [ + "bevy_reflect", + "glam", + "serde", +] + [[package]] name = "image" version = "0.25.2" @@ -3600,6 +3611,7 @@ name = "the-labyrinth-of-echoes" version = "0.0.3" dependencies = [ "bevy", + "hexx", "log", "rand", "tracing", diff --git a/Cargo.toml b/Cargo.toml index 92fd13f..322c41b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,6 +17,7 @@ tracing = { version = "0.1", features = [ "max_level_debug", "release_max_level_warn", ] } +hexx = { version = "0.18", features = ["bevy_reflect"] } [features] default = [ @@ -35,6 +36,7 @@ dev_native = [ # Enable embedded asset hot reloading for native dev builds. "bevy/embedded_watcher", ] +demo = [] # Idiomatic Bevy code often triggers these lints, and the CI workflow treats them as errors. diff --git a/src/lib.rs b/src/lib.rs index 8da505d..f673718 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,10 +1,13 @@ mod asset_tracking; pub mod audio; +#[cfg(feature = "demo")] mod demo; #[cfg(feature = "dev")] mod dev_tools; mod screens; mod theme; +#[cfg(not(feature = "demo"))] +mod tiles; use bevy::{ asset::AssetMetaCheck, @@ -57,7 +60,10 @@ impl Plugin for AppPlugin { // Add other plugins. app.add_plugins(( asset_tracking::plugin, + #[cfg(feature = "demo")] demo::plugin, + #[cfg(not(feature = "demo"))] + tiles::plugin, screens::plugin, theme::plugin, )); diff --git a/src/screens/gameplay.rs b/src/screens/gameplay.rs index 0640462..da60175 100644 --- a/src/screens/gameplay.rs +++ b/src/screens/gameplay.rs @@ -2,10 +2,11 @@ use bevy::{input::common_conditions::input_just_pressed, prelude::*}; -use crate::{ - asset_tracking::LoadResource, audio::Music, demo::level::spawn_level as spawn_level_command, - screens::Screen, -}; +#[cfg(feature = "demo")] +use crate::demo::level::spawn_level as spawn_level_command; +#[cfg(not(feature = "demo"))] +use crate::tiles::level::spawn_level as spawn_level_command; +use crate::{asset_tracking::LoadResource, audio::Music, screens::Screen}; pub(super) fn plugin(app: &mut App) { app.add_systems(OnEnter(Screen::Gameplay), spawn_level); diff --git a/src/screens/loading.rs b/src/screens/loading.rs index e6eb5ca..1f2b3aa 100644 --- a/src/screens/loading.rs +++ b/src/screens/loading.rs @@ -4,7 +4,6 @@ use bevy::prelude::*; use crate::{ - demo::player::PlayerAssets, screens::{credits::CreditsMusic, gameplay::GameplayMusic, Screen}, theme::{interaction::InteractionAssets, prelude::*}, }; @@ -35,13 +34,9 @@ fn continue_to_title_screen(mut next_screen: ResMut>) { } fn all_assets_loaded( - player_assets: Option>, interaction_assets: Option>, credits_music: Option>, gameplay_music: Option>, ) -> bool { - player_assets.is_some() - && interaction_assets.is_some() - && credits_music.is_some() - && gameplay_music.is_some() + interaction_assets.is_some() && credits_music.is_some() && gameplay_music.is_some() } diff --git a/src/tiles/level.rs b/src/tiles/level.rs new file mode 100644 index 0000000..2290946 --- /dev/null +++ b/src/tiles/level.rs @@ -0,0 +1,20 @@ +//! Spawn the main level. + +use bevy::{ecs::world::Command, prelude::*}; + +use crate::tiles::player::SpawnPlayer; + +use super::tile::{self, GridSettings, SpawnGrid}; + +pub(super) fn plugin(app: &mut App) { + app.insert_resource(GridSettings::default()); + app.add_plugins(tile::plugin); +} + +/// A [`Command`] to spawn the level. +/// Functions that accept only `&mut World` as their parameter implement [`Command`]. +/// We use this style when a command requires no configuration. +pub fn spawn_level(world: &mut World) { + SpawnGrid.apply(world); + SpawnPlayer.apply(world); +} diff --git a/src/tiles/mod.rs b/src/tiles/mod.rs new file mode 100644 index 0000000..841f267 --- /dev/null +++ b/src/tiles/mod.rs @@ -0,0 +1,8 @@ +use bevy::prelude::*; +pub mod level; +pub mod player; +pub mod tile; + +pub(super) fn plugin(app: &mut App) { + app.add_plugins((player::plugin, level::plugin)); +} diff --git a/src/tiles/player.rs b/src/tiles/player.rs new file mode 100644 index 0000000..db13397 --- /dev/null +++ b/src/tiles/player.rs @@ -0,0 +1,112 @@ +use bevy::{ + color::palettes::css::BLUE, + ecs::{system::RunSystemOnce, world::Command}, + prelude::*, +}; +use hexx::{Hex, HexLayout, HexOrientation}; + +use crate::screens::Screen; + +use super::tile::{GridSettings, HexDirection, Tile}; + +pub(super) fn plugin(app: &mut App) { + app.register_type::(); + // app.add_systems(Update, move_player); +} + +#[derive(Debug)] +pub struct SpawnPlayer; + +impl Command for SpawnPlayer { + fn apply(self, world: &mut World) { + world.run_system_once(spawn_player); + } +} + +#[derive(Debug, Reflect, Component)] +#[reflect(Component)] +pub struct Player { + position: Hex, +} + +fn spawn_player(mut commands: Commands, grid_settings: Res) { + let starting_hex = Hex::ZERO; + let layout = HexLayout { + orientation: HexOrientation::Pointy, + origin: Vec2::ZERO, + hex_size: grid_settings.hex_size, + ..default() + }; + + let world_pos = layout.hex_to_world_pos(starting_hex); + + commands.spawn(( + Name::new("Player"), + SpriteBundle { + sprite: Sprite { + color: BLUE.into(), + custom_size: Some(grid_settings.hex_size * 0.8), + ..default() + }, + transform: Transform::from_translation(world_pos.extend(1.)), + ..default() + }, + Player { + position: starting_hex, + }, + StateScoped(Screen::Gameplay), + )); +} + +fn move_player( + input: Res>, + grid_settings: Res, + mut player_query: Query<&mut Player>, + tile_query: Query<&Tile>, +) { + let mut player = player_query.single_mut(); + + if let Some(direction) = get_move_direction(&input) { + let current_tile = tile_query + .iter() + .find(|tile| tile.position == player.position) + .unwrap(); + if current_tile.has_wall(&direction) { + return; + } + + let hexx_direction = direction.to_hexx_direction(); + player.position = player.position + hexx_direction; + + let layout = HexLayout { + orientation: HexOrientation::Pointy, + origin: Vec2::ZERO, + hex_size: grid_settings.hex_size, + ..default() + }; + + let world_pos = layout.hex_to_world_pos(player.position); + } +} + +fn get_move_direction(input: &Res>) -> Option { + if input.just_pressed(KeyCode::KeyW) { + return Some(HexDirection::Top); + } + if input.just_pressed(KeyCode::KeyE) { + return Some(HexDirection::TopRight); + } + if input.just_pressed(KeyCode::KeyD) { + return Some(HexDirection::BottomRight); + } + if input.just_pressed(KeyCode::KeyS) { + return Some(HexDirection::Bottom); + } + if input.just_pressed(KeyCode::KeyA) { + return Some(HexDirection::BottomLeft); + } + if input.just_pressed(KeyCode::KeyQ) { + return Some(HexDirection::TopLeft); + } + None +} diff --git a/src/tiles/tile.rs b/src/tiles/tile.rs new file mode 100644 index 0000000..98b067d --- /dev/null +++ b/src/tiles/tile.rs @@ -0,0 +1,183 @@ +use bevy::{ + color::palettes::css::GRAY, + ecs::{system::RunSystemOnce, world::Command}, + prelude::*, + utils::hashbrown::{HashMap, HashSet}, +}; +use hexx::{EdgeDirection, Hex, HexLayout, HexOrientation}; +use rand::{seq::IteratorRandom, thread_rng}; + +pub(super) fn plugin(app: &mut App) { + app.add_systems(Startup, generate_maze); +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Reflect)] +pub enum HexDirection { + Top, + TopRight, + BottomRight, + Bottom, + BottomLeft, + TopLeft, +} + +#[derive(Debug)] +pub struct SpawnGrid; + +impl Command for SpawnGrid { + fn apply(self, world: &mut World) { + world.run_system_once(setup_hex_grid); + } +} + +impl HexDirection { + pub fn to_hexx_direction(self) -> EdgeDirection { + self.into() + } + + pub const ALL: [HexDirection; 6] = [ + Self::Top, + Self::TopRight, + Self::BottomRight, + Self::Bottom, + Self::BottomLeft, + Self::TopLeft, + ]; + + pub fn opposite(&self) -> Self { + match self { + Self::Top => Self::Bottom, + Self::TopRight => Self::BottomLeft, + Self::BottomRight => Self::TopLeft, + Self::Bottom => Self::Top, + Self::BottomLeft => Self::TopRight, + Self::TopLeft => Self::BottomRight, + } + } +} + +impl From for EdgeDirection { + fn from(value: HexDirection) -> Self { + match value { + HexDirection::Top => Self::FLAT_NORTH, + HexDirection::TopRight => Self::FLAT_NORTH_EAST, + HexDirection::BottomRight => Self::FLAT_SOUTH_EAST, + HexDirection::Bottom => Self::FLAT_SOUTH, + HexDirection::BottomLeft => Self::FLAT_SOUTH_WEST, + HexDirection::TopLeft => Self::FLAT_NORTH_WEST, + } + } +} + +#[derive(Debug, Reflect, Resource)] +#[reflect(Resource)] +pub struct GridSettings { + pub radius: u32, + pub hex_size: Vec2, +} + +#[derive(Debug, Clone, Reflect, Component)] +#[reflect(Component)] +pub struct Tile { + pub position: Hex, + pub walls: HashMap, +} + +impl Tile { + pub fn new(position: Hex) -> Self { + let mut walls = HashMap::new(); + for direction in HexDirection::ALL { + walls.insert(direction, true); + } + Self { position, walls } + } + + pub fn has_wall(&self, direction: &HexDirection) -> bool { + *self.walls.get(direction).unwrap_or(&false) + } + + pub fn remove_wall(&mut self, direction: HexDirection) { + self.walls.insert(direction, false); + } +} + +impl Default for GridSettings { + fn default() -> Self { + Self { + radius: 5, + hex_size: Vec2::splat(32.), + } + } +} + +pub fn setup_hex_grid(mut commands: Commands, grid_settings: Res) { + let GridSettings { radius, hex_size } = *grid_settings; + let layout = HexLayout { + orientation: HexOrientation::Pointy, + origin: Vec2::ZERO, + hex_size, + ..default() + }; + + let hexes = Hex::ZERO.range(radius); + + for hex in hexes { + let world_pos = layout.hex_to_world_pos(hex); + commands.spawn(( + SpriteBundle { + sprite: Sprite { + color: GRAY.into(), + custom_size: Some(hex_size), + ..default() + }, + transform: Transform::from_translation(world_pos.extend(0.)), + ..default() + }, + Tile::new(hex), + )); + } +} + +pub fn generate_maze(mut tile_query: Query<&mut Tile>, grid_settings: Res) { + let radius = grid_settings.radius; + let mut tiles = tile_query + .iter_mut() + .map(|tile| (tile.position, tile.clone())) + .collect::>(); + + let mut rng = thread_rng(); + let mut visited = HashSet::new(); + let mut stack = Vec::new(); + + let start_hex = Hex::ZERO; + visited.insert(start_hex); + stack.push(start_hex); + + while let Some(current_hex) = stack.pop() { + let mut unvisited_neighbors = Vec::new(); + for direction in HexDirection::ALL { + let neighbor_hex = current_hex + direction.to_hexx_direction(); + if neighbor_hex.distance_to(Hex::ZERO) > radius as i32 { + continue; + } + if !visited.contains(&neighbor_hex) { + unvisited_neighbors.push((neighbor_hex, direction)); + } + } + if !unvisited_neighbors.is_empty() { + stack.push(current_hex); + let &(neighbor_hex, direction) = unvisited_neighbors.iter().choose(&mut rng).unwrap(); + + if let Some(current_tile) = tiles.get_mut(¤t_hex) { + current_tile.remove_wall(direction); + } + + if let Some(neighbor_tile) = tiles.get_mut(&neighbor_hex) { + neighbor_tile.remove_wall(direction.opposite()); + } + + visited.insert(neighbor_hex); + stack.push(neighbor_hex); + } + } +} From 846b2326a3f2f4917897ca6affb82282820400bf Mon Sep 17 00:00:00 2001 From: Kristofers Solo Date: Wed, 18 Sep 2024 15:33:39 +0300 Subject: [PATCH 04/20] feat(camera): add 3d orthogrpahic camera setup --- src/lib.rs | 30 ++++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index f673718..2169048 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,10 +4,10 @@ pub mod audio; mod demo; #[cfg(feature = "dev")] mod dev_tools; +#[cfg(not(feature = "demo"))] +mod grid; mod screens; mod theme; -#[cfg(not(feature = "demo"))] -mod tiles; use bevy::{ asset::AssetMetaCheck, @@ -26,7 +26,10 @@ impl Plugin for AppPlugin { ); // Spawn the main camera. + #[cfg(not(feature = "demo"))] app.add_systems(Startup, spawn_camera); + #[cfg(feature = "demo")] + app.add_systems(Startup, spawn_2d_camera); // Add Bevy plugins. app.add_plugins( @@ -51,7 +54,7 @@ impl Plugin for AppPlugin { }) .set(AudioPlugin { global_volume: GlobalVolume { - volume: Volume::new(0.3), + volume: Volume::new(0.), }, ..default() }), @@ -63,7 +66,7 @@ impl Plugin for AppPlugin { #[cfg(feature = "demo")] demo::plugin, #[cfg(not(feature = "demo"))] - tiles::plugin, + grid::plugin, screens::plugin, theme::plugin, )); @@ -87,7 +90,26 @@ enum AppSet { Update, } +#[cfg(not(feature = "demo"))] fn spawn_camera(mut commands: Commands) { + commands.spawn(( + Name::new("Camera"), + Camera3dBundle { + transform: Transform::from_xyz(0., 60., 0.).looking_at(Vec3::ZERO, Vec3::Y), + ..default() + }, + // Render all UI to this camera. + // Not strictly necessary since we only use one camera, + // but if we don't use this component, our UI will disappear as soon + // as we add another camera. This includes indirect ways of adding cameras like using + // [ui node outlines](https://bevyengine.org/news/bevy-0-14/#ui-node-outline-gizmos) + // for debugging. So it's good to have this here for future-proofing. + IsDefaultUiCamera, + )); +} + +#[cfg(feature = "demo")] +fn spawn_2d_camera(mut commands: Commands) { commands.spawn(( Name::new("Camera"), Camera2dBundle::default(), From 7db07f7e4d3250993c5222c055dec2b5119afc85 Mon Sep 17 00:00:00 2001 From: Kristofers Solo Date: Wed, 18 Sep 2024 15:39:47 +0300 Subject: [PATCH 05/20] Revert 1 commits 846b232 'feat(camera): add 3d orthogrpahic camera setup' --- src/lib.rs | 30 ++++-------------------------- 1 file changed, 4 insertions(+), 26 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 2169048..f673718 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,10 +4,10 @@ pub mod audio; mod demo; #[cfg(feature = "dev")] mod dev_tools; -#[cfg(not(feature = "demo"))] -mod grid; mod screens; mod theme; +#[cfg(not(feature = "demo"))] +mod tiles; use bevy::{ asset::AssetMetaCheck, @@ -26,10 +26,7 @@ impl Plugin for AppPlugin { ); // Spawn the main camera. - #[cfg(not(feature = "demo"))] app.add_systems(Startup, spawn_camera); - #[cfg(feature = "demo")] - app.add_systems(Startup, spawn_2d_camera); // Add Bevy plugins. app.add_plugins( @@ -54,7 +51,7 @@ impl Plugin for AppPlugin { }) .set(AudioPlugin { global_volume: GlobalVolume { - volume: Volume::new(0.), + volume: Volume::new(0.3), }, ..default() }), @@ -66,7 +63,7 @@ impl Plugin for AppPlugin { #[cfg(feature = "demo")] demo::plugin, #[cfg(not(feature = "demo"))] - grid::plugin, + tiles::plugin, screens::plugin, theme::plugin, )); @@ -90,26 +87,7 @@ enum AppSet { Update, } -#[cfg(not(feature = "demo"))] fn spawn_camera(mut commands: Commands) { - commands.spawn(( - Name::new("Camera"), - Camera3dBundle { - transform: Transform::from_xyz(0., 60., 0.).looking_at(Vec3::ZERO, Vec3::Y), - ..default() - }, - // Render all UI to this camera. - // Not strictly necessary since we only use one camera, - // but if we don't use this component, our UI will disappear as soon - // as we add another camera. This includes indirect ways of adding cameras like using - // [ui node outlines](https://bevyengine.org/news/bevy-0-14/#ui-node-outline-gizmos) - // for debugging. So it's good to have this here for future-proofing. - IsDefaultUiCamera, - )); -} - -#[cfg(feature = "demo")] -fn spawn_2d_camera(mut commands: Commands) { commands.spawn(( Name::new("Camera"), Camera2dBundle::default(), From 590c293dc2447b76cb09d88143cb0ccdc1d6a294 Mon Sep 17 00:00:00 2001 From: Kristofers Solo Date: Wed, 18 Sep 2024 15:41:17 +0300 Subject: [PATCH 06/20] feat(grid): generate a hex grid --- src/grid/direction.rs | 51 ++++++++++ src/grid/grid.rs | 94 ++++++++++++++++++ src/{tiles => grid}/level.rs | 10 +- src/grid/mod.rs | 8 ++ src/lib.rs | 6 +- src/screens/gameplay.rs | 2 +- src/tiles/mod.rs | 8 -- src/tiles/player.rs | 112 --------------------- src/tiles/tile.rs | 183 ----------------------------------- 9 files changed, 159 insertions(+), 315 deletions(-) create mode 100644 src/grid/direction.rs create mode 100644 src/grid/grid.rs rename src/{tiles => grid}/level.rs (57%) create mode 100644 src/grid/mod.rs delete mode 100644 src/tiles/mod.rs delete mode 100644 src/tiles/player.rs delete mode 100644 src/tiles/tile.rs diff --git a/src/grid/direction.rs b/src/grid/direction.rs new file mode 100644 index 0000000..c7438e4 --- /dev/null +++ b/src/grid/direction.rs @@ -0,0 +1,51 @@ +use bevy::prelude::*; +use hexx::EdgeDirection; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Reflect)] +pub enum HexDirection { + Top, + TopRight, + BottomRight, + Bottom, + BottomLeft, + TopLeft, +} + +impl HexDirection { + pub fn to_hexx_direction(self) -> EdgeDirection { + self.into() + } + + pub const ALL: [HexDirection; 6] = [ + Self::Top, + Self::TopRight, + Self::BottomRight, + Self::Bottom, + Self::BottomLeft, + Self::TopLeft, + ]; + + pub fn opposite(&self) -> Self { + match self { + Self::Top => Self::Bottom, + Self::TopRight => Self::BottomLeft, + Self::BottomRight => Self::TopLeft, + Self::Bottom => Self::Top, + Self::BottomLeft => Self::TopRight, + Self::TopLeft => Self::BottomRight, + } + } +} + +impl From for EdgeDirection { + fn from(value: HexDirection) -> Self { + match value { + HexDirection::Top => Self::FLAT_NORTH, + HexDirection::TopRight => Self::FLAT_NORTH_EAST, + HexDirection::BottomRight => Self::FLAT_SOUTH_EAST, + HexDirection::Bottom => Self::FLAT_SOUTH, + HexDirection::BottomLeft => Self::FLAT_SOUTH_WEST, + HexDirection::TopLeft => Self::FLAT_NORTH_WEST, + } + } +} diff --git a/src/grid/grid.rs b/src/grid/grid.rs new file mode 100644 index 0000000..1d3ea35 --- /dev/null +++ b/src/grid/grid.rs @@ -0,0 +1,94 @@ +use bevy::{ + ecs::{system::RunSystemOnce, world::Command}, + prelude::*, + render::{ + mesh::{Indices, PrimitiveTopology}, + render_asset::RenderAssetUsages, + }, + utils::hashbrown::HashMap, +}; +use hexx::{Hex, HexLayout, HexOrientation, InsetOptions, MeshInfo, PlaneMeshBuilder}; + +use super::direction::HexDirection; + +#[derive(Debug, Reflect, Component, Default)] +#[reflect(Component)] +pub struct Tile { + pub position: Hex, + pub walls: HashMap, +} + +const HEX_SIZE: Vec2 = Vec2::splat(13.0); + +#[derive(Debug)] +pub struct SpawnGrid; + +impl Command for SpawnGrid { + fn apply(self, world: &mut World) { + world.run_system_once(spawn_grid); + } +} + +pub fn spawn_grid( + mut commands: Commands, + mut meshes: ResMut>, + mut materials: ResMut>, +) { + let layout = HexLayout { + hex_size: HEX_SIZE, + orientation: HexOrientation::Pointy, + ..default() + }; + let default_material = materials.add(Color::WHITE); + + let mesh = hexagonal_plane(&layout); + let mesh_handle = meshes.add(mesh); + + for hex in Hex::ZERO.range(15) { + let pos = layout.hex_to_world_pos(hex); + commands.spawn(( + Name::new("Tile"), + ColorMesh2dBundle { + mesh: mesh_handle.clone().into(), + transform: Transform::from_xyz(pos.x, pos.y, 0.), + material: default_material.clone(), + ..default() + }, + Tile::default(), + )); + } +} + +fn hexagonal_plane(hex_layout: &HexLayout) -> Mesh { + let mesh_info = PlaneMeshBuilder::new(hex_layout) + .facing(Vec3::Z) + .with_scale(Vec3::splat(0.98)) + .center_aligned() + .build(); + construct_mesh(mesh_info) +} + +fn border_plane(hex_layout: &HexLayout) -> Mesh { + let mesh_info = PlaneMeshBuilder::new(hex_layout) + .facing(Vec3::Z) + .with_inset_options(InsetOptions { + keep_inner_face: false, + scale: 0.2, + ..default() + }) + .center_aligned() + .build(); + + construct_mesh(mesh_info) +} + +fn construct_mesh(mesh_info: MeshInfo) -> Mesh { + Mesh::new( + PrimitiveTopology::TriangleList, + RenderAssetUsages::RENDER_WORLD, + ) + .with_inserted_attribute(Mesh::ATTRIBUTE_POSITION, mesh_info.vertices) + .with_inserted_attribute(Mesh::ATTRIBUTE_NORMAL, mesh_info.normals) + .with_inserted_attribute(Mesh::ATTRIBUTE_UV_0, mesh_info.uvs) + .with_inserted_indices(Indices::U16(mesh_info.indices)) +} diff --git a/src/tiles/level.rs b/src/grid/level.rs similarity index 57% rename from src/tiles/level.rs rename to src/grid/level.rs index 2290946..b3ad1d2 100644 --- a/src/tiles/level.rs +++ b/src/grid/level.rs @@ -2,19 +2,13 @@ use bevy::{ecs::world::Command, prelude::*}; -use crate::tiles::player::SpawnPlayer; +use super::grid::SpawnGrid; -use super::tile::{self, GridSettings, SpawnGrid}; - -pub(super) fn plugin(app: &mut App) { - app.insert_resource(GridSettings::default()); - app.add_plugins(tile::plugin); -} +pub(super) fn plugin(_app: &mut App) {} /// A [`Command`] to spawn the level. /// Functions that accept only `&mut World` as their parameter implement [`Command`]. /// We use this style when a command requires no configuration. pub fn spawn_level(world: &mut World) { SpawnGrid.apply(world); - SpawnPlayer.apply(world); } diff --git a/src/grid/mod.rs b/src/grid/mod.rs new file mode 100644 index 0000000..de267df --- /dev/null +++ b/src/grid/mod.rs @@ -0,0 +1,8 @@ +use bevy::prelude::*; +pub mod direction; +pub mod grid; +pub mod level; + +pub(super) fn plugin(app: &mut App) { + app.add_plugins(level::plugin); +} diff --git a/src/lib.rs b/src/lib.rs index f673718..95b3b56 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,10 +4,10 @@ pub mod audio; mod demo; #[cfg(feature = "dev")] mod dev_tools; +#[cfg(not(feature = "demo"))] +mod grid; mod screens; mod theme; -#[cfg(not(feature = "demo"))] -mod tiles; use bevy::{ asset::AssetMetaCheck, @@ -63,7 +63,7 @@ impl Plugin for AppPlugin { #[cfg(feature = "demo")] demo::plugin, #[cfg(not(feature = "demo"))] - tiles::plugin, + grid::plugin, screens::plugin, theme::plugin, )); diff --git a/src/screens/gameplay.rs b/src/screens/gameplay.rs index da60175..b65ecc1 100644 --- a/src/screens/gameplay.rs +++ b/src/screens/gameplay.rs @@ -5,7 +5,7 @@ use bevy::{input::common_conditions::input_just_pressed, prelude::*}; #[cfg(feature = "demo")] use crate::demo::level::spawn_level as spawn_level_command; #[cfg(not(feature = "demo"))] -use crate::tiles::level::spawn_level as spawn_level_command; +use crate::grid::level::spawn_level as spawn_level_command; use crate::{asset_tracking::LoadResource, audio::Music, screens::Screen}; pub(super) fn plugin(app: &mut App) { diff --git a/src/tiles/mod.rs b/src/tiles/mod.rs deleted file mode 100644 index 841f267..0000000 --- a/src/tiles/mod.rs +++ /dev/null @@ -1,8 +0,0 @@ -use bevy::prelude::*; -pub mod level; -pub mod player; -pub mod tile; - -pub(super) fn plugin(app: &mut App) { - app.add_plugins((player::plugin, level::plugin)); -} diff --git a/src/tiles/player.rs b/src/tiles/player.rs deleted file mode 100644 index db13397..0000000 --- a/src/tiles/player.rs +++ /dev/null @@ -1,112 +0,0 @@ -use bevy::{ - color::palettes::css::BLUE, - ecs::{system::RunSystemOnce, world::Command}, - prelude::*, -}; -use hexx::{Hex, HexLayout, HexOrientation}; - -use crate::screens::Screen; - -use super::tile::{GridSettings, HexDirection, Tile}; - -pub(super) fn plugin(app: &mut App) { - app.register_type::(); - // app.add_systems(Update, move_player); -} - -#[derive(Debug)] -pub struct SpawnPlayer; - -impl Command for SpawnPlayer { - fn apply(self, world: &mut World) { - world.run_system_once(spawn_player); - } -} - -#[derive(Debug, Reflect, Component)] -#[reflect(Component)] -pub struct Player { - position: Hex, -} - -fn spawn_player(mut commands: Commands, grid_settings: Res) { - let starting_hex = Hex::ZERO; - let layout = HexLayout { - orientation: HexOrientation::Pointy, - origin: Vec2::ZERO, - hex_size: grid_settings.hex_size, - ..default() - }; - - let world_pos = layout.hex_to_world_pos(starting_hex); - - commands.spawn(( - Name::new("Player"), - SpriteBundle { - sprite: Sprite { - color: BLUE.into(), - custom_size: Some(grid_settings.hex_size * 0.8), - ..default() - }, - transform: Transform::from_translation(world_pos.extend(1.)), - ..default() - }, - Player { - position: starting_hex, - }, - StateScoped(Screen::Gameplay), - )); -} - -fn move_player( - input: Res>, - grid_settings: Res, - mut player_query: Query<&mut Player>, - tile_query: Query<&Tile>, -) { - let mut player = player_query.single_mut(); - - if let Some(direction) = get_move_direction(&input) { - let current_tile = tile_query - .iter() - .find(|tile| tile.position == player.position) - .unwrap(); - if current_tile.has_wall(&direction) { - return; - } - - let hexx_direction = direction.to_hexx_direction(); - player.position = player.position + hexx_direction; - - let layout = HexLayout { - orientation: HexOrientation::Pointy, - origin: Vec2::ZERO, - hex_size: grid_settings.hex_size, - ..default() - }; - - let world_pos = layout.hex_to_world_pos(player.position); - } -} - -fn get_move_direction(input: &Res>) -> Option { - if input.just_pressed(KeyCode::KeyW) { - return Some(HexDirection::Top); - } - if input.just_pressed(KeyCode::KeyE) { - return Some(HexDirection::TopRight); - } - if input.just_pressed(KeyCode::KeyD) { - return Some(HexDirection::BottomRight); - } - if input.just_pressed(KeyCode::KeyS) { - return Some(HexDirection::Bottom); - } - if input.just_pressed(KeyCode::KeyA) { - return Some(HexDirection::BottomLeft); - } - if input.just_pressed(KeyCode::KeyQ) { - return Some(HexDirection::TopLeft); - } - None -} diff --git a/src/tiles/tile.rs b/src/tiles/tile.rs deleted file mode 100644 index 98b067d..0000000 --- a/src/tiles/tile.rs +++ /dev/null @@ -1,183 +0,0 @@ -use bevy::{ - color::palettes::css::GRAY, - ecs::{system::RunSystemOnce, world::Command}, - prelude::*, - utils::hashbrown::{HashMap, HashSet}, -}; -use hexx::{EdgeDirection, Hex, HexLayout, HexOrientation}; -use rand::{seq::IteratorRandom, thread_rng}; - -pub(super) fn plugin(app: &mut App) { - app.add_systems(Startup, generate_maze); -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Reflect)] -pub enum HexDirection { - Top, - TopRight, - BottomRight, - Bottom, - BottomLeft, - TopLeft, -} - -#[derive(Debug)] -pub struct SpawnGrid; - -impl Command for SpawnGrid { - fn apply(self, world: &mut World) { - world.run_system_once(setup_hex_grid); - } -} - -impl HexDirection { - pub fn to_hexx_direction(self) -> EdgeDirection { - self.into() - } - - pub const ALL: [HexDirection; 6] = [ - Self::Top, - Self::TopRight, - Self::BottomRight, - Self::Bottom, - Self::BottomLeft, - Self::TopLeft, - ]; - - pub fn opposite(&self) -> Self { - match self { - Self::Top => Self::Bottom, - Self::TopRight => Self::BottomLeft, - Self::BottomRight => Self::TopLeft, - Self::Bottom => Self::Top, - Self::BottomLeft => Self::TopRight, - Self::TopLeft => Self::BottomRight, - } - } -} - -impl From for EdgeDirection { - fn from(value: HexDirection) -> Self { - match value { - HexDirection::Top => Self::FLAT_NORTH, - HexDirection::TopRight => Self::FLAT_NORTH_EAST, - HexDirection::BottomRight => Self::FLAT_SOUTH_EAST, - HexDirection::Bottom => Self::FLAT_SOUTH, - HexDirection::BottomLeft => Self::FLAT_SOUTH_WEST, - HexDirection::TopLeft => Self::FLAT_NORTH_WEST, - } - } -} - -#[derive(Debug, Reflect, Resource)] -#[reflect(Resource)] -pub struct GridSettings { - pub radius: u32, - pub hex_size: Vec2, -} - -#[derive(Debug, Clone, Reflect, Component)] -#[reflect(Component)] -pub struct Tile { - pub position: Hex, - pub walls: HashMap, -} - -impl Tile { - pub fn new(position: Hex) -> Self { - let mut walls = HashMap::new(); - for direction in HexDirection::ALL { - walls.insert(direction, true); - } - Self { position, walls } - } - - pub fn has_wall(&self, direction: &HexDirection) -> bool { - *self.walls.get(direction).unwrap_or(&false) - } - - pub fn remove_wall(&mut self, direction: HexDirection) { - self.walls.insert(direction, false); - } -} - -impl Default for GridSettings { - fn default() -> Self { - Self { - radius: 5, - hex_size: Vec2::splat(32.), - } - } -} - -pub fn setup_hex_grid(mut commands: Commands, grid_settings: Res) { - let GridSettings { radius, hex_size } = *grid_settings; - let layout = HexLayout { - orientation: HexOrientation::Pointy, - origin: Vec2::ZERO, - hex_size, - ..default() - }; - - let hexes = Hex::ZERO.range(radius); - - for hex in hexes { - let world_pos = layout.hex_to_world_pos(hex); - commands.spawn(( - SpriteBundle { - sprite: Sprite { - color: GRAY.into(), - custom_size: Some(hex_size), - ..default() - }, - transform: Transform::from_translation(world_pos.extend(0.)), - ..default() - }, - Tile::new(hex), - )); - } -} - -pub fn generate_maze(mut tile_query: Query<&mut Tile>, grid_settings: Res) { - let radius = grid_settings.radius; - let mut tiles = tile_query - .iter_mut() - .map(|tile| (tile.position, tile.clone())) - .collect::>(); - - let mut rng = thread_rng(); - let mut visited = HashSet::new(); - let mut stack = Vec::new(); - - let start_hex = Hex::ZERO; - visited.insert(start_hex); - stack.push(start_hex); - - while let Some(current_hex) = stack.pop() { - let mut unvisited_neighbors = Vec::new(); - for direction in HexDirection::ALL { - let neighbor_hex = current_hex + direction.to_hexx_direction(); - if neighbor_hex.distance_to(Hex::ZERO) > radius as i32 { - continue; - } - if !visited.contains(&neighbor_hex) { - unvisited_neighbors.push((neighbor_hex, direction)); - } - } - if !unvisited_neighbors.is_empty() { - stack.push(current_hex); - let &(neighbor_hex, direction) = unvisited_neighbors.iter().choose(&mut rng).unwrap(); - - if let Some(current_tile) = tiles.get_mut(¤t_hex) { - current_tile.remove_wall(direction); - } - - if let Some(neighbor_tile) = tiles.get_mut(&neighbor_hex) { - neighbor_tile.remove_wall(direction.opposite()); - } - - visited.insert(neighbor_hex); - stack.push(neighbor_hex); - } - } -} From 5929f255a817b2c0ee3733920eeb73c9490b9591 Mon Sep 17 00:00:00 2001 From: Kristofers Solo Date: Wed, 18 Sep 2024 21:34:12 +0300 Subject: [PATCH 07/20] refactor(grid): remove dead code --- src/grid/direction.rs | 2 + src/grid/grid.rs | 122 ++++++++++++++++------------------------ src/grid/level.rs | 14 ----- src/grid/mod.rs | 4 +- src/grid/tile.rs | 69 +++++++++++++++++++++++ src/screens/gameplay.rs | 2 +- src/screens/mod.rs | 3 +- 7 files changed, 123 insertions(+), 93 deletions(-) delete mode 100644 src/grid/level.rs create mode 100644 src/grid/tile.rs diff --git a/src/grid/direction.rs b/src/grid/direction.rs index c7438e4..cc0551a 100644 --- a/src/grid/direction.rs +++ b/src/grid/direction.rs @@ -1,6 +1,8 @@ use bevy::prelude::*; use hexx::EdgeDirection; +pub(super) fn plugin(_app: &mut App) {} + #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Reflect)] pub enum HexDirection { Top, diff --git a/src/grid/grid.rs b/src/grid/grid.rs index 1d3ea35..69c4563 100644 --- a/src/grid/grid.rs +++ b/src/grid/grid.rs @@ -1,94 +1,66 @@ +use super::tile::spawn_tiles; use bevy::{ ecs::{system::RunSystemOnce, world::Command}, prelude::*, - render::{ - mesh::{Indices, PrimitiveTopology}, - render_asset::RenderAssetUsages, - }, - utils::hashbrown::HashMap, }; -use hexx::{Hex, HexLayout, HexOrientation, InsetOptions, MeshInfo, PlaneMeshBuilder}; +use hexx::{HexLayout, HexOrientation}; +use std::time::Duration; -use super::direction::HexDirection; +pub(super) fn plugin(_app: &mut App) {} -#[derive(Debug, Reflect, Component, Default)] -#[reflect(Component)] -pub struct Tile { - pub position: Hex, - pub walls: HashMap, +pub fn spawn_grid(world: &mut World) { + world.init_resource::(); + world.init_resource::(); + GridSettings::default().apply(world); } -const HEX_SIZE: Vec2 = Vec2::splat(13.0); +#[derive(Debug, Reflect, Resource)] +#[reflect(Resource)] +pub struct Grid { + pub layout: HexLayout, +} -#[derive(Debug)] -pub struct SpawnGrid; +#[derive(Debug, Reflect, Resource, Deref, DerefMut)] +#[reflect(Resource)] +struct RotationTimer(Timer); -impl Command for SpawnGrid { - fn apply(self, world: &mut World) { - world.run_system_once(spawn_grid); +impl Default for RotationTimer { + fn default() -> Self { + Self(Timer::new(Duration::from_secs_f32(0.5), TimerMode::Once)) } } -pub fn spawn_grid( - mut commands: Commands, - mut meshes: ResMut>, - mut materials: ResMut>, -) { - let layout = HexLayout { - hex_size: HEX_SIZE, - orientation: HexOrientation::Pointy, - ..default() - }; - let default_material = materials.add(Color::WHITE); +#[derive(Debug, Reflect)] +pub struct GridSettings { + pub radius: u32, +} - let mesh = hexagonal_plane(&layout); - let mesh_handle = meshes.add(mesh); +impl Default for GridSettings { + fn default() -> Self { + Self { radius: 10 } + } +} - for hex in Hex::ZERO.range(15) { - let pos = layout.hex_to_world_pos(hex); - commands.spawn(( - Name::new("Tile"), - ColorMesh2dBundle { - mesh: mesh_handle.clone().into(), - transform: Transform::from_xyz(pos.x, pos.y, 0.), - material: default_material.clone(), +impl Command for GridSettings { + fn apply(self, world: &mut World) { + world.run_system_once_with(self, spawn_tiles) + } +} + +impl Default for Grid { + fn default() -> Self { + Self::new(20., HexOrientation::Flat) + } +} + +impl Grid { + pub fn new(hex_size: f32, orientation: HexOrientation) -> Self { + Self { + layout: HexLayout { + hex_size: Vec2::splat(hex_size), + orientation, ..default() }, - Tile::default(), - )); + } } } - -fn hexagonal_plane(hex_layout: &HexLayout) -> Mesh { - let mesh_info = PlaneMeshBuilder::new(hex_layout) - .facing(Vec3::Z) - .with_scale(Vec3::splat(0.98)) - .center_aligned() - .build(); - construct_mesh(mesh_info) -} - -fn border_plane(hex_layout: &HexLayout) -> Mesh { - let mesh_info = PlaneMeshBuilder::new(hex_layout) - .facing(Vec3::Z) - .with_inset_options(InsetOptions { - keep_inner_face: false, - scale: 0.2, - ..default() - }) - .center_aligned() - .build(); - - construct_mesh(mesh_info) -} - -fn construct_mesh(mesh_info: MeshInfo) -> Mesh { - Mesh::new( - PrimitiveTopology::TriangleList, - RenderAssetUsages::RENDER_WORLD, - ) - .with_inserted_attribute(Mesh::ATTRIBUTE_POSITION, mesh_info.vertices) - .with_inserted_attribute(Mesh::ATTRIBUTE_NORMAL, mesh_info.normals) - .with_inserted_attribute(Mesh::ATTRIBUTE_UV_0, mesh_info.uvs) - .with_inserted_indices(Indices::U16(mesh_info.indices)) -} diff --git a/src/grid/level.rs b/src/grid/level.rs deleted file mode 100644 index b3ad1d2..0000000 --- a/src/grid/level.rs +++ /dev/null @@ -1,14 +0,0 @@ -//! Spawn the main level. - -use bevy::{ecs::world::Command, prelude::*}; - -use super::grid::SpawnGrid; - -pub(super) fn plugin(_app: &mut App) {} - -/// A [`Command`] to spawn the level. -/// Functions that accept only `&mut World` as their parameter implement [`Command`]. -/// We use this style when a command requires no configuration. -pub fn spawn_level(world: &mut World) { - SpawnGrid.apply(world); -} diff --git a/src/grid/mod.rs b/src/grid/mod.rs index de267df..2f7c051 100644 --- a/src/grid/mod.rs +++ b/src/grid/mod.rs @@ -1,8 +1,8 @@ use bevy::prelude::*; pub mod direction; pub mod grid; -pub mod level; +pub mod tile; pub(super) fn plugin(app: &mut App) { - app.add_plugins(level::plugin); + app.add_plugins((direction::plugin, tile::plugin, grid::plugin)); } diff --git a/src/grid/tile.rs b/src/grid/tile.rs new file mode 100644 index 0000000..7699604 --- /dev/null +++ b/src/grid/tile.rs @@ -0,0 +1,69 @@ +use super::{ + direction::HexDirection, + grid::{Grid, GridSettings}, +}; +use bevy::{ + prelude::*, + render::{ + mesh::{Indices, PrimitiveTopology}, + render_asset::RenderAssetUsages, + }, + utils::hashbrown::HashMap, +}; +use hexx::{Hex, HexLayout, PlaneMeshBuilder}; + +pub(super) fn plugin(_app: &mut App) {} + +#[derive(Debug, Reflect, Component, Default)] +#[reflect(Component)] +pub struct Tile { + pub position: Hex, + pub walls: HashMap, +} + +pub fn spawn_tiles( + config: In, + mut commands: Commands, + mut meshes: ResMut>, + mut materials: ResMut>, + grid: Res, +) { + let default_material = materials.add(Color::WHITE); + + let mesh = hexagonal_plane(&grid.layout); + let mesh_handle = meshes.add(mesh); + + for hex_pos in Hex::ZERO.range(config.radius) { + let world_pos = grid.layout.hex_to_world_pos(hex_pos); + commands.spawn(( + Name::new(format!("Tile: ({}, {})", world_pos.x, world_pos.y)), + ColorMesh2dBundle { + mesh: mesh_handle.clone().into(), + transform: Transform::from_xyz(world_pos.x, world_pos.y, 0.), + material: default_material.clone(), + ..default() + }, + Tile { + position: hex_pos, + ..default() + }, + )); + } +} + +fn hexagonal_plane(hex_layout: &HexLayout) -> Mesh { + let mesh_info = PlaneMeshBuilder::new(hex_layout) + .facing(Vec3::Z) + .with_scale(Vec3::splat(0.9)) // border + .center_aligned() + .build(); + + Mesh::new( + PrimitiveTopology::TriangleList, + RenderAssetUsages::RENDER_WORLD, + ) + .with_inserted_attribute(Mesh::ATTRIBUTE_POSITION, mesh_info.vertices) + .with_inserted_attribute(Mesh::ATTRIBUTE_NORMAL, mesh_info.normals) + .with_inserted_attribute(Mesh::ATTRIBUTE_UV_0, mesh_info.uvs) + .with_inserted_indices(Indices::U16(mesh_info.indices)) +} diff --git a/src/screens/gameplay.rs b/src/screens/gameplay.rs index b65ecc1..de212a4 100644 --- a/src/screens/gameplay.rs +++ b/src/screens/gameplay.rs @@ -5,7 +5,7 @@ use bevy::{input::common_conditions::input_just_pressed, prelude::*}; #[cfg(feature = "demo")] use crate::demo::level::spawn_level as spawn_level_command; #[cfg(not(feature = "demo"))] -use crate::grid::level::spawn_level as spawn_level_command; +use crate::grid::grid::spawn_grid as spawn_level_command; use crate::{asset_tracking::LoadResource, audio::Music, screens::Screen}; pub(super) fn plugin(app: &mut App) { diff --git a/src/screens/mod.rs b/src/screens/mod.rs index 49bdc53..13606fd 100644 --- a/src/screens/mod.rs +++ b/src/screens/mod.rs @@ -24,8 +24,9 @@ pub(super) fn plugin(app: &mut App) { /// The game's main screen states. #[derive(States, Debug, Hash, PartialEq, Eq, Clone, Default)] pub enum Screen { - #[default] + #[cfg_attr(not(feature = "dev"), default)] Splash, + #[cfg_attr(feature = "dev", default)] Loading, Title, Credits, From 869d11e8105f3992ce667f8d273bd40e40ab9285 Mon Sep 17 00:00:00 2001 From: Kristofers Solo Date: Fri, 20 Sep 2024 16:59:24 +0300 Subject: [PATCH 08/20] feat: add bevy_protoype_lyon dependency --- Cargo.lock | 93 ++++++++++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 1 + src/grid/grid.rs | 17 ++++----- src/grid/tile.rs | 64 +++++++++++++++++++++++++++++++-- 4 files changed, 165 insertions(+), 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index aa2a063..9013d1e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -818,6 +818,18 @@ dependencies = [ "static_assertions", ] +[[package]] +name = "bevy_prototype_lyon" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66a59b46da5bccc6d86c6047cfc81b8e9027f5b98e24b8721e8e1453c1d05371" +dependencies = [ + "bevy", + "lyon_algorithms", + "lyon_tessellation", + "svgtypes", +] + [[package]] name = "bevy_ptr" version = "0.14.1" @@ -1801,6 +1813,12 @@ dependencies = [ "miniz_oxide", ] +[[package]] +name = "float_next_after" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8bf7cc16383c4b8d58b9905a8509f02926ce3058053c056376248d958c9df1e8" + [[package]] name = "fnv" version = "1.0.7" @@ -2327,6 +2345,15 @@ dependencies = [ "bitflags 1.3.2", ] +[[package]] +name = "kurbo" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd85a5776cd9500c2e2059c8c76c3b01528566b7fcbaf8098b55a33fc298849b" +dependencies = [ + "arrayvec", +] + [[package]] name = "lazy_static" version = "1.5.0" @@ -2376,6 +2403,12 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "libm" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" + [[package]] name = "libredox" version = "0.0.2" @@ -2425,6 +2458,48 @@ version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" +[[package]] +name = "lyon_algorithms" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3bca95f9a4955b3e4a821fbbcd5edfbd9be2a9a50bb5758173e5358bfb4c623" +dependencies = [ + "lyon_path", + "num-traits", +] + +[[package]] +name = "lyon_geom" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edecfb8d234a2b0be031ab02ebcdd9f3b9ee418fb35e265f7a540a48d197bff9" +dependencies = [ + "arrayvec", + "euclid", + "num-traits", +] + +[[package]] +name = "lyon_path" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c08a606c7a59638d6c6aa18ac91a06aa9fb5f765a7efb27e6a4da58700740d7" +dependencies = [ + "lyon_geom", + "num-traits", +] + +[[package]] +name = "lyon_tessellation" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "579d42360a4b09846eff2feef28f538696c7d6c7439bfa65874ff3cbe0951b2c" +dependencies = [ + "float_next_after", + "lyon_path", + "num-traits", +] + [[package]] name = "mach2" version = "0.4.2" @@ -2703,6 +2778,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", + "libm", ] [[package]] @@ -3463,6 +3539,12 @@ version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" +[[package]] +name = "siphasher" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" + [[package]] name = "slab" version = "0.4.9" @@ -3548,6 +3630,16 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "20e16a0f46cf5fd675563ef54f26e83e20f2366bcf027bcb3cc3ed2b98aaf2ca" +[[package]] +name = "svgtypes" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71499ff2d42f59d26edb21369a308ede691421f79ebc0f001e2b1fd3a7c9e52" +dependencies = [ + "kurbo", + "siphasher", +] + [[package]] name = "syn" version = "1.0.109" @@ -3611,6 +3703,7 @@ name = "the-labyrinth-of-echoes" version = "0.0.3" dependencies = [ "bevy", + "bevy_prototype_lyon", "hexx", "log", "rand", diff --git a/Cargo.toml b/Cargo.toml index 322c41b..939ba28 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,6 +18,7 @@ tracing = { version = "0.1", features = [ "release_max_level_warn", ] } hexx = { version = "0.18", features = ["bevy_reflect"] } +bevy_prototype_lyon = "0.12" [features] default = [ diff --git a/src/grid/grid.rs b/src/grid/grid.rs index 69c4563..8cf920b 100644 --- a/src/grid/grid.rs +++ b/src/grid/grid.rs @@ -1,4 +1,4 @@ -use super::tile::spawn_tiles; +use super::tile::{draw_walls, spawn_tiles}; use bevy::{ ecs::{system::RunSystemOnce, world::Command}, prelude::*, @@ -14,12 +14,6 @@ pub fn spawn_grid(world: &mut World) { GridSettings::default().apply(world); } -#[derive(Debug, Reflect, Resource)] -#[reflect(Resource)] -pub struct Grid { - pub layout: HexLayout, -} - #[derive(Debug, Reflect, Resource, Deref, DerefMut)] #[reflect(Resource)] struct RotationTimer(Timer); @@ -43,10 +37,17 @@ impl Default for GridSettings { impl Command for GridSettings { fn apply(self, world: &mut World) { - world.run_system_once_with(self, spawn_tiles) + world.run_system_once_with(self, spawn_tiles); + world.run_system_once(draw_walls); } } +#[derive(Debug, Reflect, Resource)] +#[reflect(Resource)] +pub struct Grid { + pub layout: HexLayout, +} + impl Default for Grid { fn default() -> Self { Self::new(20., HexOrientation::Flat) diff --git a/src/grid/tile.rs b/src/grid/tile.rs index 7699604..af7def6 100644 --- a/src/grid/tile.rs +++ b/src/grid/tile.rs @@ -10,7 +10,9 @@ use bevy::{ }, utils::hashbrown::HashMap, }; +use bevy_prototype_lyon::{entity::ShapeBundle, geometry::GeometryBuilder, shapes::Line}; use hexx::{Hex, HexLayout, PlaneMeshBuilder}; +use rand::{thread_rng, Rng}; pub(super) fn plugin(_app: &mut App) {} @@ -33,8 +35,16 @@ pub fn spawn_tiles( let mesh = hexagonal_plane(&grid.layout); let mesh_handle = meshes.add(mesh); + let mut rng = thread_rng(); + for hex_pos in Hex::ZERO.range(config.radius) { let world_pos = grid.layout.hex_to_world_pos(hex_pos); + let mut walls = HashMap::new(); + + for dir in HexDirection::ALL { + walls.insert(dir, rng.gen_bool(0.5)); + } + commands.spawn(( Name::new(format!("Tile: ({}, {})", world_pos.x, world_pos.y)), ColorMesh2dBundle { @@ -45,7 +55,7 @@ pub fn spawn_tiles( }, Tile { position: hex_pos, - ..default() + walls, }, )); } @@ -54,7 +64,7 @@ pub fn spawn_tiles( fn hexagonal_plane(hex_layout: &HexLayout) -> Mesh { let mesh_info = PlaneMeshBuilder::new(hex_layout) .facing(Vec3::Z) - .with_scale(Vec3::splat(0.9)) // border + // .with_scale(Vec3::splat(0.9)) // border .center_aligned() .build(); @@ -67,3 +77,53 @@ fn hexagonal_plane(hex_layout: &HexLayout) -> Mesh { .with_inserted_attribute(Mesh::ATTRIBUTE_UV_0, mesh_info.uvs) .with_inserted_indices(Indices::U16(mesh_info.indices)) } + +fn hex_corner_positions(layout: &HexLayout, hex: Hex) -> [Vec2; 6] { + let center = layout.hex_to_world_pos(hex); + let mut corners = [Vec2::ZERO; 6]; + for (idx, corner) in corners.iter_mut().enumerate() { + let andgle_deg = 60. * idx as f32; // FIX: + let andgle_rad = andgle_deg.to_radians(); + let size = layout.hex_size; + *corner = center + Vec2::new(size.x * andgle_rad.cos(), size.y * andgle_rad.sin()); + } + corners +} + +pub fn draw_walls( + mut commands: Commands, + tile_query: Query<(Entity, &Tile)>, + + mut materials: ResMut>, + grid: Res, +) { + let default_material = materials.add(Color::BLACK); + + for (entity, tile) in tile_query.iter() { + let corners = hex_corner_positions(&grid.layout, tile.position); + + for (dir, has_wall) in &tile.walls { + if *has_wall { + let direction_idx = *dir as usize; + let cornder1 = direction_idx; + let cornder2 = (direction_idx + 1) % 6; + + let start_pos = corners[cornder1]; + let end_pos = corners[cornder2]; + + let line = Line(start_pos, end_pos); + let wall_entity = commands + .spawn(( + Name::new("Wall"), + ShapeBundle { + path: GeometryBuilder::build_as(&line), + material: default_material.clone(), + ..default() + }, + )) + .id(); + commands.entity(entity).add_child(wall_entity); + } + } + } +} From f11b701ec35331d8e3c7ceb0ee29d2a26d4e3bf9 Mon Sep 17 00:00:00 2001 From: Kristofers Solo Date: Sun, 22 Sep 2024 14:25:08 +0300 Subject: [PATCH 09/20] feat(grid): generate grid with random walls --- src/grid/grid.rs | 37 +++++++++++++++-- src/grid/tile.rs | 1 - src/hex.rs | 106 +++++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 4 +- 4 files changed, 143 insertions(+), 5 deletions(-) create mode 100644 src/hex.rs diff --git a/src/grid/grid.rs b/src/grid/grid.rs index 8cf920b..6ad231e 100644 --- a/src/grid/grid.rs +++ b/src/grid/grid.rs @@ -1,12 +1,24 @@ use super::tile::{draw_walls, spawn_tiles}; use bevy::{ + color::palettes::css::{BLACK, DARK_CYAN}, ecs::{system::RunSystemOnce, world::Command}, prelude::*, }; +use bevy_prototype_lyon::{ + draw::{Fill, Stroke}, + entity::ShapeBundle, + geometry::GeometryBuilder, + plugin::ShapePlugin, + prelude::RegularPolygon, + shapes::RegularPolygonFeature, +}; use hexx::{HexLayout, HexOrientation}; use std::time::Duration; -pub(super) fn plugin(_app: &mut App) {} +pub(super) fn plugin(app: &mut App) { + app.insert_resource(Msaa::Sample4); + app.add_plugins(ShapePlugin); +} pub fn spawn_grid(world: &mut World) { world.init_resource::(); @@ -37,11 +49,30 @@ impl Default for GridSettings { impl Command for GridSettings { fn apply(self, world: &mut World) { - world.run_system_once_with(self, spawn_tiles); - world.run_system_once(draw_walls); + // world.run_system_once_with(self, spawn_tiles); + // world.run_system_once(draw_walls); + world.run_system_once(draw); } } +fn draw(mut commands: Commands) { + let shape = RegularPolygon { + sides: 6, + feature: RegularPolygonFeature::Radius(200.), + ..default() + }; + + commands.spawn(( + Name::new("Hexagon"), + ShapeBundle { + path: GeometryBuilder::build_as(&shape), + ..default() + }, + Fill::color(DARK_CYAN), + Stroke::new(BLACK, 10.), + )); +} + #[derive(Debug, Reflect, Resource)] #[reflect(Resource)] pub struct Grid { diff --git a/src/grid/tile.rs b/src/grid/tile.rs index af7def6..8d537d5 100644 --- a/src/grid/tile.rs +++ b/src/grid/tile.rs @@ -64,7 +64,6 @@ pub fn spawn_tiles( fn hexagonal_plane(hex_layout: &HexLayout) -> Mesh { let mesh_info = PlaneMeshBuilder::new(hex_layout) .facing(Vec3::Z) - // .with_scale(Vec3::splat(0.9)) // border .center_aligned() .build(); diff --git a/src/hex.rs b/src/hex.rs new file mode 100644 index 0000000..e6a4c75 --- /dev/null +++ b/src/hex.rs @@ -0,0 +1,106 @@ +use bevy::{color::palettes::css::BLACK, prelude::*}; + +use bevy_prototype_lyon::{ + draw::{Fill, Stroke}, + entity::ShapeBundle, + path::PathBuilder, + plugin::ShapePlugin, +}; +use rand::{thread_rng, Rng}; + +pub(super) fn plugin(app: &mut App) { + app.add_plugins(ShapePlugin); + app.add_systems(Startup, setup_system); +} + +fn setup_system(mut commands: Commands) { + let radius = 5; + let hex_positions = generate_hex_grix(radius); + + let hex_size = 30.; + let hex_height = hex_size * 2.; + let hex_width = (3.0_f32).sqrt() * hex_size; + + for (q, r) in hex_positions { + let x = hex_width * (q as f32 + r as f32 / 2.); + let y = hex_height * (r as f32 * 3. / 4.); + let mut rng = thread_rng(); + let walls: [bool; 6] = [ + rng.gen(), + rng.gen(), + rng.gen(), + rng.gen(), + rng.gen(), + rng.gen(), + ]; + + add_hex_tile(&mut commands, Vec2::new(x, y), hex_size, walls); + } +} + +fn generate_hex_grix(radius: i32) -> Vec<(i32, i32)> { + let mut positions = Vec::new(); + + for q in -radius..=radius { + let r1 = (-radius).max(-q - radius); + let r2 = radius.min(-q + radius); + + for r in r1..=r2 { + positions.push((q, r)); + } + } + positions +} + +fn add_hex_tile(commands: &mut Commands, position: Vec2, size: f32, walls: [bool; 6]) { + let hex_points = (0..6) + .map(|i| { + let angle_deg = 60. * i as f32 - 30.; + let angle_rad = angle_deg.to_radians(); + Vec2::new(size * angle_rad.cos(), size * angle_rad.sin()) + }) + .collect::>(); + + let mut path_builder = PathBuilder::new(); + path_builder.move_to(hex_points[0]); + for point in &hex_points[1..] { + path_builder.line_to(*point); + } + path_builder.close(); + let hexagon = path_builder.build(); + + commands.spawn(( + ShapeBundle { + path: hexagon, + spatial: SpatialBundle { + transform: Transform::from_xyz(position.x, position.y, 0.), + ..default() + }, + ..default() + }, + Fill::color(Color::srgb(0.8, 0.8, 0.8)), + )); + + for i in 0..6 { + if walls[i] { + let start = hex_points[i]; + let end = hex_points[(i + 1) % 6]; + let mut line_builder = PathBuilder::new(); + line_builder.move_to(start); + line_builder.line_to(end); + let line = line_builder.build(); + + commands.spawn(( + ShapeBundle { + path: line, + spatial: SpatialBundle { + transform: Transform::from_xyz(position.x, position.y, 1.), + ..default() + }, + ..default() + }, + Stroke::new(BLACK, 2.), + )); + } + } +} diff --git a/src/lib.rs b/src/lib.rs index 95b3b56..6e3dc65 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,6 +6,7 @@ mod demo; mod dev_tools; #[cfg(not(feature = "demo"))] mod grid; +mod hex; mod screens; mod theme; @@ -63,7 +64,8 @@ impl Plugin for AppPlugin { #[cfg(feature = "demo")] demo::plugin, #[cfg(not(feature = "demo"))] - grid::plugin, + // grid::plugin, + hex::plugin, screens::plugin, theme::plugin, )); From 0ee94c826a037183e22ac2cb5fbc5daf9dd5efdd Mon Sep 17 00:00:00 2001 From: Kristofers Solo Date: Sun, 22 Sep 2024 14:32:32 +0300 Subject: [PATCH 10/20] refactor(grid): make it a Plugin --- src/grid/grid.rs | 98 ---------------------- src/grid/mod.rs | 8 -- src/grid/tile.rs | 128 ----------------------------- src/{grid => hexgrid}/direction.rs | 0 src/{hex.rs => hexgrid/grid.rs} | 12 ++- src/hexgrid/mod.rs | 25 ++++++ src/lib.rs | 6 +- src/screens/gameplay.rs | 2 +- 8 files changed, 36 insertions(+), 243 deletions(-) delete mode 100644 src/grid/grid.rs delete mode 100644 src/grid/mod.rs delete mode 100644 src/grid/tile.rs rename src/{grid => hexgrid}/direction.rs (100%) rename src/{hex.rs => hexgrid/grid.rs} (92%) create mode 100644 src/hexgrid/mod.rs diff --git a/src/grid/grid.rs b/src/grid/grid.rs deleted file mode 100644 index 6ad231e..0000000 --- a/src/grid/grid.rs +++ /dev/null @@ -1,98 +0,0 @@ -use super::tile::{draw_walls, spawn_tiles}; -use bevy::{ - color::palettes::css::{BLACK, DARK_CYAN}, - ecs::{system::RunSystemOnce, world::Command}, - prelude::*, -}; -use bevy_prototype_lyon::{ - draw::{Fill, Stroke}, - entity::ShapeBundle, - geometry::GeometryBuilder, - plugin::ShapePlugin, - prelude::RegularPolygon, - shapes::RegularPolygonFeature, -}; -use hexx::{HexLayout, HexOrientation}; -use std::time::Duration; - -pub(super) fn plugin(app: &mut App) { - app.insert_resource(Msaa::Sample4); - app.add_plugins(ShapePlugin); -} - -pub fn spawn_grid(world: &mut World) { - world.init_resource::(); - world.init_resource::(); - GridSettings::default().apply(world); -} - -#[derive(Debug, Reflect, Resource, Deref, DerefMut)] -#[reflect(Resource)] -struct RotationTimer(Timer); - -impl Default for RotationTimer { - fn default() -> Self { - Self(Timer::new(Duration::from_secs_f32(0.5), TimerMode::Once)) - } -} - -#[derive(Debug, Reflect)] -pub struct GridSettings { - pub radius: u32, -} - -impl Default for GridSettings { - fn default() -> Self { - Self { radius: 10 } - } -} - -impl Command for GridSettings { - fn apply(self, world: &mut World) { - // world.run_system_once_with(self, spawn_tiles); - // world.run_system_once(draw_walls); - world.run_system_once(draw); - } -} - -fn draw(mut commands: Commands) { - let shape = RegularPolygon { - sides: 6, - feature: RegularPolygonFeature::Radius(200.), - ..default() - }; - - commands.spawn(( - Name::new("Hexagon"), - ShapeBundle { - path: GeometryBuilder::build_as(&shape), - ..default() - }, - Fill::color(DARK_CYAN), - Stroke::new(BLACK, 10.), - )); -} - -#[derive(Debug, Reflect, Resource)] -#[reflect(Resource)] -pub struct Grid { - pub layout: HexLayout, -} - -impl Default for Grid { - fn default() -> Self { - Self::new(20., HexOrientation::Flat) - } -} - -impl Grid { - pub fn new(hex_size: f32, orientation: HexOrientation) -> Self { - Self { - layout: HexLayout { - hex_size: Vec2::splat(hex_size), - orientation, - ..default() - }, - } - } -} diff --git a/src/grid/mod.rs b/src/grid/mod.rs deleted file mode 100644 index 2f7c051..0000000 --- a/src/grid/mod.rs +++ /dev/null @@ -1,8 +0,0 @@ -use bevy::prelude::*; -pub mod direction; -pub mod grid; -pub mod tile; - -pub(super) fn plugin(app: &mut App) { - app.add_plugins((direction::plugin, tile::plugin, grid::plugin)); -} diff --git a/src/grid/tile.rs b/src/grid/tile.rs deleted file mode 100644 index 8d537d5..0000000 --- a/src/grid/tile.rs +++ /dev/null @@ -1,128 +0,0 @@ -use super::{ - direction::HexDirection, - grid::{Grid, GridSettings}, -}; -use bevy::{ - prelude::*, - render::{ - mesh::{Indices, PrimitiveTopology}, - render_asset::RenderAssetUsages, - }, - utils::hashbrown::HashMap, -}; -use bevy_prototype_lyon::{entity::ShapeBundle, geometry::GeometryBuilder, shapes::Line}; -use hexx::{Hex, HexLayout, PlaneMeshBuilder}; -use rand::{thread_rng, Rng}; - -pub(super) fn plugin(_app: &mut App) {} - -#[derive(Debug, Reflect, Component, Default)] -#[reflect(Component)] -pub struct Tile { - pub position: Hex, - pub walls: HashMap, -} - -pub fn spawn_tiles( - config: In, - mut commands: Commands, - mut meshes: ResMut>, - mut materials: ResMut>, - grid: Res, -) { - let default_material = materials.add(Color::WHITE); - - let mesh = hexagonal_plane(&grid.layout); - let mesh_handle = meshes.add(mesh); - - let mut rng = thread_rng(); - - for hex_pos in Hex::ZERO.range(config.radius) { - let world_pos = grid.layout.hex_to_world_pos(hex_pos); - let mut walls = HashMap::new(); - - for dir in HexDirection::ALL { - walls.insert(dir, rng.gen_bool(0.5)); - } - - commands.spawn(( - Name::new(format!("Tile: ({}, {})", world_pos.x, world_pos.y)), - ColorMesh2dBundle { - mesh: mesh_handle.clone().into(), - transform: Transform::from_xyz(world_pos.x, world_pos.y, 0.), - material: default_material.clone(), - ..default() - }, - Tile { - position: hex_pos, - walls, - }, - )); - } -} - -fn hexagonal_plane(hex_layout: &HexLayout) -> Mesh { - let mesh_info = PlaneMeshBuilder::new(hex_layout) - .facing(Vec3::Z) - .center_aligned() - .build(); - - Mesh::new( - PrimitiveTopology::TriangleList, - RenderAssetUsages::RENDER_WORLD, - ) - .with_inserted_attribute(Mesh::ATTRIBUTE_POSITION, mesh_info.vertices) - .with_inserted_attribute(Mesh::ATTRIBUTE_NORMAL, mesh_info.normals) - .with_inserted_attribute(Mesh::ATTRIBUTE_UV_0, mesh_info.uvs) - .with_inserted_indices(Indices::U16(mesh_info.indices)) -} - -fn hex_corner_positions(layout: &HexLayout, hex: Hex) -> [Vec2; 6] { - let center = layout.hex_to_world_pos(hex); - let mut corners = [Vec2::ZERO; 6]; - for (idx, corner) in corners.iter_mut().enumerate() { - let andgle_deg = 60. * idx as f32; // FIX: - let andgle_rad = andgle_deg.to_radians(); - let size = layout.hex_size; - *corner = center + Vec2::new(size.x * andgle_rad.cos(), size.y * andgle_rad.sin()); - } - corners -} - -pub fn draw_walls( - mut commands: Commands, - tile_query: Query<(Entity, &Tile)>, - - mut materials: ResMut>, - grid: Res, -) { - let default_material = materials.add(Color::BLACK); - - for (entity, tile) in tile_query.iter() { - let corners = hex_corner_positions(&grid.layout, tile.position); - - for (dir, has_wall) in &tile.walls { - if *has_wall { - let direction_idx = *dir as usize; - let cornder1 = direction_idx; - let cornder2 = (direction_idx + 1) % 6; - - let start_pos = corners[cornder1]; - let end_pos = corners[cornder2]; - - let line = Line(start_pos, end_pos); - let wall_entity = commands - .spawn(( - Name::new("Wall"), - ShapeBundle { - path: GeometryBuilder::build_as(&line), - material: default_material.clone(), - ..default() - }, - )) - .id(); - commands.entity(entity).add_child(wall_entity); - } - } - } -} diff --git a/src/grid/direction.rs b/src/hexgrid/direction.rs similarity index 100% rename from src/grid/direction.rs rename to src/hexgrid/direction.rs diff --git a/src/hex.rs b/src/hexgrid/grid.rs similarity index 92% rename from src/hex.rs rename to src/hexgrid/grid.rs index e6a4c75..287444d 100644 --- a/src/hex.rs +++ b/src/hexgrid/grid.rs @@ -8,12 +8,16 @@ use bevy_prototype_lyon::{ }; use rand::{thread_rng, Rng}; -pub(super) fn plugin(app: &mut App) { - app.add_plugins(ShapePlugin); - app.add_systems(Startup, setup_system); +pub struct HexGrid; + +impl Plugin for HexGrid { + fn build(&self, app: &mut App) { + app.add_plugins(ShapePlugin); + app.add_systems(Startup, setup_system); + } } -fn setup_system(mut commands: Commands) { +pub(super) fn setup_system(mut commands: Commands) { let radius = 5; let hex_positions = generate_hex_grix(radius); diff --git a/src/hexgrid/mod.rs b/src/hexgrid/mod.rs new file mode 100644 index 0000000..a18b576 --- /dev/null +++ b/src/hexgrid/mod.rs @@ -0,0 +1,25 @@ +use bevy::{ + ecs::{system::RunSystemOnce, world::Command}, + prelude::*, +}; +use bevy_prototype_lyon::plugin::ShapePlugin; +use grid::setup_system; +pub mod grid; + +pub struct HexGrid; + +impl Plugin for HexGrid { + fn build(&self, app: &mut App) { + app.add_plugins(ShapePlugin); + } +} + +impl Command for HexGrid { + fn apply(self, world: &mut World) { + world.run_system_once(setup_system); + } +} + +pub fn spawn_grid(world: &mut World) { + HexGrid.apply(world); +} diff --git a/src/lib.rs b/src/lib.rs index 6e3dc65..2edc68d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,8 +5,7 @@ mod demo; #[cfg(feature = "dev")] mod dev_tools; #[cfg(not(feature = "demo"))] -mod grid; -mod hex; +mod hexgrid; mod screens; mod theme; @@ -64,8 +63,7 @@ impl Plugin for AppPlugin { #[cfg(feature = "demo")] demo::plugin, #[cfg(not(feature = "demo"))] - // grid::plugin, - hex::plugin, + hexgrid::HexGrid, screens::plugin, theme::plugin, )); diff --git a/src/screens/gameplay.rs b/src/screens/gameplay.rs index de212a4..638ec9d 100644 --- a/src/screens/gameplay.rs +++ b/src/screens/gameplay.rs @@ -5,7 +5,7 @@ use bevy::{input::common_conditions::input_just_pressed, prelude::*}; #[cfg(feature = "demo")] use crate::demo::level::spawn_level as spawn_level_command; #[cfg(not(feature = "demo"))] -use crate::grid::grid::spawn_grid as spawn_level_command; +use crate::hexgrid::spawn_grid as spawn_level_command; use crate::{asset_tracking::LoadResource, audio::Music, screens::Screen}; pub(super) fn plugin(app: &mut App) { From f16fd51090d89e9ac78a12d2ea7f7fd413809c05 Mon Sep 17 00:00:00 2001 From: Kristofers Solo Date: Sun, 22 Sep 2024 15:28:07 +0300 Subject: [PATCH 11/20] feat(grid): generate maze --- src/hex.rs | 14 ++++ src/hexgrid/direction.rs | 23 +------ src/hexgrid/grid.rs | 138 +++++++++++++++++++++++++++++++-------- src/hexgrid/mod.rs | 2 + src/hexgrid/tile.rs | 24 +++++++ 5 files changed, 154 insertions(+), 47 deletions(-) create mode 100644 src/hex.rs create mode 100644 src/hexgrid/tile.rs diff --git a/src/hex.rs b/src/hex.rs new file mode 100644 index 0000000..2f48253 --- /dev/null +++ b/src/hex.rs @@ -0,0 +1,14 @@ +use bevy::{color::palettes::css::BLACK, prelude::*}; + +use bevy_prototype_lyon::{ + draw::{Fill, Stroke}, + entity::ShapeBundle, + path::PathBuilder, + plugin::ShapePlugin, +}; +use rand::{thread_rng, Rng}; + +pub(super) fn plugin(app: &mut App) { + app.add_plugins(ShapePlugin); + app.add_systems(Startup, setup_system); +} diff --git a/src/hexgrid/direction.rs b/src/hexgrid/direction.rs index cc0551a..7522a5f 100644 --- a/src/hexgrid/direction.rs +++ b/src/hexgrid/direction.rs @@ -4,7 +4,7 @@ use hexx::EdgeDirection; pub(super) fn plugin(_app: &mut App) {} #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Reflect)] -pub enum HexDirection { +pub enum Direction { Top, TopRight, BottomRight, @@ -13,12 +13,8 @@ pub enum HexDirection { TopLeft, } -impl HexDirection { - pub fn to_hexx_direction(self) -> EdgeDirection { - self.into() - } - - pub const ALL: [HexDirection; 6] = [ +impl Direction { + pub const ALL: [Direction; 6] = [ Self::Top, Self::TopRight, Self::BottomRight, @@ -38,16 +34,3 @@ impl HexDirection { } } } - -impl From for EdgeDirection { - fn from(value: HexDirection) -> Self { - match value { - HexDirection::Top => Self::FLAT_NORTH, - HexDirection::TopRight => Self::FLAT_NORTH_EAST, - HexDirection::BottomRight => Self::FLAT_SOUTH_EAST, - HexDirection::Bottom => Self::FLAT_SOUTH, - HexDirection::BottomLeft => Self::FLAT_SOUTH_WEST, - HexDirection::TopLeft => Self::FLAT_NORTH_WEST, - } - } -} diff --git a/src/hexgrid/grid.rs b/src/hexgrid/grid.rs index 287444d..757e829 100644 --- a/src/hexgrid/grid.rs +++ b/src/hexgrid/grid.rs @@ -1,4 +1,8 @@ -use bevy::{color::palettes::css::BLACK, prelude::*}; +use bevy::{ + color::palettes::css::{BLACK, GREEN, RED}, + prelude::*, + utils::hashbrown::HashMap, +}; use bevy_prototype_lyon::{ draw::{Fill, Stroke}, @@ -6,7 +10,18 @@ use bevy_prototype_lyon::{ path::PathBuilder, plugin::ShapePlugin, }; -use rand::{thread_rng, Rng}; +use rand::{prelude::SliceRandom, rngs::ThreadRng, thread_rng}; + +use super::tile::{AxialCoord, Tile}; + +const DIRECTIONS: [AxialCoord; 6] = [ + AxialCoord { q: 1, r: 0 }, // Right + AxialCoord { q: 1, r: -1 }, // Top-right + AxialCoord { q: 0, r: -1 }, // Top-left + AxialCoord { q: -1, r: 0 }, // Left + AxialCoord { q: -1, r: 1 }, // Bottom-left + AxialCoord { q: 0, r: 1 }, // Bottom-right +]; pub struct HexGrid; @@ -18,45 +33,45 @@ impl Plugin for HexGrid { } pub(super) fn setup_system(mut commands: Commands) { - let radius = 5; - let hex_positions = generate_hex_grix(radius); + let radius = 7; + let mut grid = generate_hex_grix(radius); - let hex_size = 30.; - let hex_height = hex_size * 2.; - let hex_width = (3.0_f32).sqrt() * hex_size; + let start_coord = AxialCoord::new(-radius, 0); + let end_coord = AxialCoord::new(radius, 0); - for (q, r) in hex_positions { - let x = hex_width * (q as f32 + r as f32 / 2.); - let y = hex_height * (r as f32 * 3. / 4.); - let mut rng = thread_rng(); - let walls: [bool; 6] = [ - rng.gen(), - rng.gen(), - rng.gen(), - rng.gen(), - rng.gen(), - rng.gen(), - ]; + let mut rng = thread_rng(); + generate_maze(&mut grid, start_coord, &mut rng); - add_hex_tile(&mut commands, Vec2::new(x, y), hex_size, walls); - } + render_maze(&mut commands, &mut grid, radius, start_coord, end_coord); } -fn generate_hex_grix(radius: i32) -> Vec<(i32, i32)> { - let mut positions = Vec::new(); +fn generate_hex_grix(radius: i32) -> HashMap { + let mut grid = HashMap::new(); for q in -radius..=radius { let r1 = (-radius).max(-q - radius); let r2 = radius.min(-q + radius); for r in r1..=r2 { - positions.push((q, r)); + let coord = AxialCoord::new(q, r); + let tile = Tile { + position: coord, + walls: [true; 6], + visited: false, + }; + grid.insert(coord, tile); } } - positions + grid } -fn add_hex_tile(commands: &mut Commands, position: Vec2, size: f32, walls: [bool; 6]) { +fn add_hex_tile( + commands: &mut Commands, + position: Vec2, + size: f32, + walls: [bool; 6], + fill_color: Color, +) { let hex_points = (0..6) .map(|i| { let angle_deg = 60. * i as f32 - 30.; @@ -73,6 +88,7 @@ fn add_hex_tile(commands: &mut Commands, position: Vec2, size: f32, walls: [bool path_builder.close(); let hexagon = path_builder.build(); + // Create the hexagon fill commands.spawn(( ShapeBundle { path: hexagon, @@ -82,9 +98,10 @@ fn add_hex_tile(commands: &mut Commands, position: Vec2, size: f32, walls: [bool }, ..default() }, - Fill::color(Color::srgb(0.8, 0.8, 0.8)), + Fill::color(fill_color), )); + // Draw walls for i in 0..6 { if walls[i] { let start = hex_points[i]; @@ -108,3 +125,70 @@ fn add_hex_tile(commands: &mut Commands, position: Vec2, size: f32, walls: [bool } } } + +fn generate_maze( + grid: &mut HashMap, + current_coord: AxialCoord, + rng: &mut ThreadRng, +) { + { + let current_tile = grid.get_mut(¤t_coord).unwrap(); + current_tile.visit(); + } + + let mut directions = DIRECTIONS.clone(); + directions.shuffle(rng); + + for (i, direction) in directions.iter().enumerate() { + let neightbor_coord = AxialCoord { + q: current_coord.q + direction.q, + r: current_coord.r + direction.r, + }; + + if let Some(neightbor_tile) = grid.get(&neightbor_coord) { + if !neightbor_tile.visited { + // Remove the wall between current_tile and neighbor_tile + { + let current_tile = grid.get_mut(¤t_coord).unwrap(); + current_tile.walls[i] = false; + } + { + let neightbor_tile = grid.get_mut(&neightbor_coord).unwrap(); + neightbor_tile.walls[opposite_wall(i)] = false; + } + // Recurse with the neighbor tile + generate_maze(grid, neightbor_coord, rng); + } + } + } +} + +fn render_maze( + commands: &mut Commands, + grid: &mut HashMap, + radius: i32, + start_coord: AxialCoord, + end_coord: AxialCoord, +) { + let hex_size = 30.; + let hex_height = hex_size * 2.; + let hex_width = (3.0_f32).sqrt() * hex_size; + + for tile in grid.values() { + let (q, r) = (tile.position.q, tile.position.r); + let x = hex_width * (q as f32 + r as f32 / 2.); + let y = hex_height * (r as f32 * 3. / 4.); + let mut fill_color = Color::srgb(0.8, 0.8, 0.8); + if tile.position == start_coord { + fill_color = GREEN.into(); + } else if tile.position == end_coord { + fill_color = RED.into(); + } + + add_hex_tile(commands, Vec2::new(x, y), hex_size, tile.walls, fill_color); + } +} + +fn opposite_wall(index: usize) -> usize { + (index + 3) % 6 +} diff --git a/src/hexgrid/mod.rs b/src/hexgrid/mod.rs index a18b576..0dd34ee 100644 --- a/src/hexgrid/mod.rs +++ b/src/hexgrid/mod.rs @@ -4,7 +4,9 @@ use bevy::{ }; use bevy_prototype_lyon::plugin::ShapePlugin; use grid::setup_system; +pub mod direction; pub mod grid; +pub mod tile; pub struct HexGrid; diff --git a/src/hexgrid/tile.rs b/src/hexgrid/tile.rs new file mode 100644 index 0000000..ad13baf --- /dev/null +++ b/src/hexgrid/tile.rs @@ -0,0 +1,24 @@ +#[derive(Debug, Clone)] +pub struct Tile { + pub position: AxialCoord, + pub walls: [bool; 6], + pub visited: bool, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct AxialCoord { + pub q: i32, + pub r: i32, +} + +impl Tile { + pub fn visit(&mut self) { + self.visited = true + } +} + +impl AxialCoord { + pub fn new(q: i32, r: i32) -> Self { + Self { q, r } + } +} From c5f8dede6df966dbcedf90fd94058be0af8af9a2 Mon Sep 17 00:00:00 2001 From: Kristofers Solo Date: Mon, 23 Sep 2024 20:42:07 +0300 Subject: [PATCH 12/20] feat(grid): add precidualy generated maze grid --- Cargo.toml | 2 +- src/hexgrid/direction.rs | 36 ------- src/hexgrid/grid.rs | 194 ---------------------------------- src/hexgrid/mod.rs | 27 ----- src/hexgrid/tile.rs | 24 ----- src/lib.rs | 4 +- src/maze/grid.rs | 218 +++++++++++++++++++++++++++++++++++++++ src/maze/mod.rs | 28 +++++ src/maze/resource.rs | 53 ++++++++++ src/maze/tile.rs | 46 +++++++++ src/screens/gameplay.rs | 2 +- 11 files changed, 349 insertions(+), 285 deletions(-) delete mode 100644 src/hexgrid/direction.rs delete mode 100644 src/hexgrid/grid.rs delete mode 100644 src/hexgrid/mod.rs delete mode 100644 src/hexgrid/tile.rs create mode 100644 src/maze/grid.rs create mode 100644 src/maze/mod.rs create mode 100644 src/maze/resource.rs create mode 100644 src/maze/tile.rs diff --git a/Cargo.toml b/Cargo.toml index 939ba28..914f76e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,7 +17,7 @@ tracing = { version = "0.1", features = [ "max_level_debug", "release_max_level_warn", ] } -hexx = { version = "0.18", features = ["bevy_reflect"] } +hexx = { version = "0.18", features = ["bevy_reflect", "grid"] } bevy_prototype_lyon = "0.12" [features] diff --git a/src/hexgrid/direction.rs b/src/hexgrid/direction.rs deleted file mode 100644 index 7522a5f..0000000 --- a/src/hexgrid/direction.rs +++ /dev/null @@ -1,36 +0,0 @@ -use bevy::prelude::*; -use hexx::EdgeDirection; - -pub(super) fn plugin(_app: &mut App) {} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Reflect)] -pub enum Direction { - Top, - TopRight, - BottomRight, - Bottom, - BottomLeft, - TopLeft, -} - -impl Direction { - pub const ALL: [Direction; 6] = [ - Self::Top, - Self::TopRight, - Self::BottomRight, - Self::Bottom, - Self::BottomLeft, - Self::TopLeft, - ]; - - pub fn opposite(&self) -> Self { - match self { - Self::Top => Self::Bottom, - Self::TopRight => Self::BottomLeft, - Self::BottomRight => Self::TopLeft, - Self::Bottom => Self::Top, - Self::BottomLeft => Self::TopRight, - Self::TopLeft => Self::BottomRight, - } - } -} diff --git a/src/hexgrid/grid.rs b/src/hexgrid/grid.rs deleted file mode 100644 index 757e829..0000000 --- a/src/hexgrid/grid.rs +++ /dev/null @@ -1,194 +0,0 @@ -use bevy::{ - color::palettes::css::{BLACK, GREEN, RED}, - prelude::*, - utils::hashbrown::HashMap, -}; - -use bevy_prototype_lyon::{ - draw::{Fill, Stroke}, - entity::ShapeBundle, - path::PathBuilder, - plugin::ShapePlugin, -}; -use rand::{prelude::SliceRandom, rngs::ThreadRng, thread_rng}; - -use super::tile::{AxialCoord, Tile}; - -const DIRECTIONS: [AxialCoord; 6] = [ - AxialCoord { q: 1, r: 0 }, // Right - AxialCoord { q: 1, r: -1 }, // Top-right - AxialCoord { q: 0, r: -1 }, // Top-left - AxialCoord { q: -1, r: 0 }, // Left - AxialCoord { q: -1, r: 1 }, // Bottom-left - AxialCoord { q: 0, r: 1 }, // Bottom-right -]; - -pub struct HexGrid; - -impl Plugin for HexGrid { - fn build(&self, app: &mut App) { - app.add_plugins(ShapePlugin); - app.add_systems(Startup, setup_system); - } -} - -pub(super) fn setup_system(mut commands: Commands) { - let radius = 7; - let mut grid = generate_hex_grix(radius); - - let start_coord = AxialCoord::new(-radius, 0); - let end_coord = AxialCoord::new(radius, 0); - - let mut rng = thread_rng(); - generate_maze(&mut grid, start_coord, &mut rng); - - render_maze(&mut commands, &mut grid, radius, start_coord, end_coord); -} - -fn generate_hex_grix(radius: i32) -> HashMap { - let mut grid = HashMap::new(); - - for q in -radius..=radius { - let r1 = (-radius).max(-q - radius); - let r2 = radius.min(-q + radius); - - for r in r1..=r2 { - let coord = AxialCoord::new(q, r); - let tile = Tile { - position: coord, - walls: [true; 6], - visited: false, - }; - grid.insert(coord, tile); - } - } - grid -} - -fn add_hex_tile( - commands: &mut Commands, - position: Vec2, - size: f32, - walls: [bool; 6], - fill_color: Color, -) { - let hex_points = (0..6) - .map(|i| { - let angle_deg = 60. * i as f32 - 30.; - let angle_rad = angle_deg.to_radians(); - Vec2::new(size * angle_rad.cos(), size * angle_rad.sin()) - }) - .collect::>(); - - let mut path_builder = PathBuilder::new(); - path_builder.move_to(hex_points[0]); - for point in &hex_points[1..] { - path_builder.line_to(*point); - } - path_builder.close(); - let hexagon = path_builder.build(); - - // Create the hexagon fill - commands.spawn(( - ShapeBundle { - path: hexagon, - spatial: SpatialBundle { - transform: Transform::from_xyz(position.x, position.y, 0.), - ..default() - }, - ..default() - }, - Fill::color(fill_color), - )); - - // Draw walls - for i in 0..6 { - if walls[i] { - let start = hex_points[i]; - let end = hex_points[(i + 1) % 6]; - let mut line_builder = PathBuilder::new(); - line_builder.move_to(start); - line_builder.line_to(end); - let line = line_builder.build(); - - commands.spawn(( - ShapeBundle { - path: line, - spatial: SpatialBundle { - transform: Transform::from_xyz(position.x, position.y, 1.), - ..default() - }, - ..default() - }, - Stroke::new(BLACK, 2.), - )); - } - } -} - -fn generate_maze( - grid: &mut HashMap, - current_coord: AxialCoord, - rng: &mut ThreadRng, -) { - { - let current_tile = grid.get_mut(¤t_coord).unwrap(); - current_tile.visit(); - } - - let mut directions = DIRECTIONS.clone(); - directions.shuffle(rng); - - for (i, direction) in directions.iter().enumerate() { - let neightbor_coord = AxialCoord { - q: current_coord.q + direction.q, - r: current_coord.r + direction.r, - }; - - if let Some(neightbor_tile) = grid.get(&neightbor_coord) { - if !neightbor_tile.visited { - // Remove the wall between current_tile and neighbor_tile - { - let current_tile = grid.get_mut(¤t_coord).unwrap(); - current_tile.walls[i] = false; - } - { - let neightbor_tile = grid.get_mut(&neightbor_coord).unwrap(); - neightbor_tile.walls[opposite_wall(i)] = false; - } - // Recurse with the neighbor tile - generate_maze(grid, neightbor_coord, rng); - } - } - } -} - -fn render_maze( - commands: &mut Commands, - grid: &mut HashMap, - radius: i32, - start_coord: AxialCoord, - end_coord: AxialCoord, -) { - let hex_size = 30.; - let hex_height = hex_size * 2.; - let hex_width = (3.0_f32).sqrt() * hex_size; - - for tile in grid.values() { - let (q, r) = (tile.position.q, tile.position.r); - let x = hex_width * (q as f32 + r as f32 / 2.); - let y = hex_height * (r as f32 * 3. / 4.); - let mut fill_color = Color::srgb(0.8, 0.8, 0.8); - if tile.position == start_coord { - fill_color = GREEN.into(); - } else if tile.position == end_coord { - fill_color = RED.into(); - } - - add_hex_tile(commands, Vec2::new(x, y), hex_size, tile.walls, fill_color); - } -} - -fn opposite_wall(index: usize) -> usize { - (index + 3) % 6 -} diff --git a/src/hexgrid/mod.rs b/src/hexgrid/mod.rs deleted file mode 100644 index 0dd34ee..0000000 --- a/src/hexgrid/mod.rs +++ /dev/null @@ -1,27 +0,0 @@ -use bevy::{ - ecs::{system::RunSystemOnce, world::Command}, - prelude::*, -}; -use bevy_prototype_lyon::plugin::ShapePlugin; -use grid::setup_system; -pub mod direction; -pub mod grid; -pub mod tile; - -pub struct HexGrid; - -impl Plugin for HexGrid { - fn build(&self, app: &mut App) { - app.add_plugins(ShapePlugin); - } -} - -impl Command for HexGrid { - fn apply(self, world: &mut World) { - world.run_system_once(setup_system); - } -} - -pub fn spawn_grid(world: &mut World) { - HexGrid.apply(world); -} diff --git a/src/hexgrid/tile.rs b/src/hexgrid/tile.rs deleted file mode 100644 index ad13baf..0000000 --- a/src/hexgrid/tile.rs +++ /dev/null @@ -1,24 +0,0 @@ -#[derive(Debug, Clone)] -pub struct Tile { - pub position: AxialCoord, - pub walls: [bool; 6], - pub visited: bool, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct AxialCoord { - pub q: i32, - pub r: i32, -} - -impl Tile { - pub fn visit(&mut self) { - self.visited = true - } -} - -impl AxialCoord { - pub fn new(q: i32, r: i32) -> Self { - Self { q, r } - } -} diff --git a/src/lib.rs b/src/lib.rs index 2edc68d..c0ad671 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,7 +5,7 @@ mod demo; #[cfg(feature = "dev")] mod dev_tools; #[cfg(not(feature = "demo"))] -mod hexgrid; +mod maze; mod screens; mod theme; @@ -63,7 +63,7 @@ impl Plugin for AppPlugin { #[cfg(feature = "demo")] demo::plugin, #[cfg(not(feature = "demo"))] - hexgrid::HexGrid, + maze::MazePlugin, screens::plugin, theme::plugin, )); diff --git a/src/maze/grid.rs b/src/maze/grid.rs new file mode 100644 index 0000000..9247675 --- /dev/null +++ b/src/maze/grid.rs @@ -0,0 +1,218 @@ +use std::usize; + +use bevy::{ + color::palettes::css::{BLACK, GREEN, RED}, + prelude::*, + utils::hashbrown::HashMap, +}; + +use bevy_prototype_lyon::{ + draw::{Fill, Stroke}, + entity::ShapeBundle, + path::PathBuilder, + plugin::ShapePlugin, +}; +use hexx::{EdgeDirection, Hex}; +use log::info; +use rand::{prelude::SliceRandom, rngs::ThreadRng, thread_rng}; + +use super::{ + resource::{Layout, MazeConfig}, + tile::{Tile, TileBundle, Walls}, +}; + +pub(super) fn plugin(app: &mut App) { + app.add_plugins(ShapePlugin); + app.init_resource::(); + app.init_resource::(); +} + +pub(super) fn spawn_hex_grid(mut commands: Commands, config: Res) { + let radius = config.radius as i32; + + for q in -radius..=radius { + let r1 = (-radius).max(-q - radius); + let r2 = radius.min(-q + radius); + for r in r1..=r2 { + let tile = Tile::new(q, r); + commands.spawn(( + Name::new(format!("Tile {}", &tile.to_string())), + TileBundle { + hex: tile, + ..default() + }, + )); + } + } +} + +pub(super) fn generate_maze( + mut commands: Commands, + query: Query<(Entity, &Tile, &Walls)>, + config: Res, +) { + let mut tiles = query + .into_iter() + .map(|(entity, tile, walls)| (tile.hex, (entity, tile.clone(), walls.clone()))) + .collect(); + + let mut rng = thread_rng(); + recursive_maze(&mut tiles, config.start_pos, &mut rng); + + for (entity, tile, walls) in tiles.values() { + commands + .entity(*entity) + .insert(tile.clone()) + .insert(walls.clone()); + } +} + +fn recursive_maze( + tiles: &mut HashMap, + current_hex: Hex, + rng: &mut ThreadRng, +) { + { + let (_, tile, _) = tiles.get_mut(¤t_hex).unwrap(); + tile.visit(); + } + + let mut directions = EdgeDirection::ALL_DIRECTIONS; + directions.shuffle(rng); + + for direction in directions.into_iter() { + let neighbor_hex = current_hex + direction; + if let Some((_, neighbor_tile, _)) = tiles.get(&neighbor_hex) { + if !neighbor_tile.visited { + remove_wall_between(tiles, current_hex, neighbor_hex, direction); + recursive_maze(tiles, neighbor_hex, rng); + } + } + } +} + +fn remove_wall_between( + tiles: &mut HashMap, + current_hex: Hex, + neighbor_hex: Hex, + direction: EdgeDirection, +) { + { + let (_, _, walls) = tiles.get_mut(¤t_hex).unwrap(); + walls.0[direction.index() as usize] = false; + } + { + let (_, _, walls) = tiles.get_mut(&neighbor_hex).unwrap(); + walls.0[direction.const_neg().index() as usize] = false; + } +} + +fn add_hex_tile( + commands: &mut Commands, + position: Vec2, + size: f32, + tile: &Tile, + walls: &Walls, + fill_color: Color, + layout: &Layout, +) { + let hex_points = tile + .hex + .all_vertices() + .into_iter() + .map(|v| { + let mut layout = layout.clone(); + layout.origin = position; + layout.hex_size = Vec2::splat(size); + layout.hex_to_world_pos(v.origin + v.direction) + }) + .collect::>(); + + let mut path_builder = PathBuilder::new(); + path_builder.move_to(hex_points[0]); + for point in &hex_points[1..] { + path_builder.line_to(*point); + } + path_builder.close(); + let hexagon = path_builder.build(); + + // Create the hexagon fill + commands.spawn(( + ShapeBundle { + path: hexagon, + spatial: SpatialBundle { + transform: Transform::from_xyz(position.x, position.y, 0.), + ..default() + }, + ..default() + }, + Fill::color(fill_color), + )); + // .with_children(|p| { + // p.spawn(Text2dBundle { + // text: Text { + // sections: vec![TextSection { + // value: tile.to_string(), + // style: TextStyle { + // font_size: 16., + // color: Color::BLACK, + // ..default() + // }, + // }], + // ..default() + // }, + // transform: Transform::from_xyz(position.x * 2., position.y * 2., 1.), + // ..default() + // }); + // }); + + // Draw walls + for direction in EdgeDirection::iter() { + let idx = direction.index() as usize; + if walls[idx] { + let start = hex_points[idx]; + let end = hex_points[(idx + 1) % 6]; + let mut line_builder = PathBuilder::new(); + line_builder.move_to(start); + line_builder.line_to(end); + let line = line_builder.build(); + + commands.spawn(( + ShapeBundle { + path: line, + spatial: SpatialBundle { + transform: Transform::from_xyz(position.x, position.y, 1.), + ..default() + }, + ..default() + }, + Stroke::new(BLACK, 2.), + )); + } + } +} + +pub(super) fn render_maze( + mut commands: Commands, + query: Query<(&Tile, &mut Walls)>, + layout: Res, + config: Res, +) { + for (tile, walls) in query.iter() { + let world_pos = layout.hex_to_world_pos(tile.hex); + let fill_color = match tile.hex { + pos if pos == config.start_pos => GREEN.into(), + pos if pos == config.end_pos => RED.into(), + _ => Color::srgb(0.8, 0.8, 0.8), + }; + add_hex_tile( + &mut commands, + world_pos, + config.size, + tile, + walls, + fill_color, + &layout, + ); + } +} diff --git a/src/maze/mod.rs b/src/maze/mod.rs new file mode 100644 index 0000000..8a347d3 --- /dev/null +++ b/src/maze/mod.rs @@ -0,0 +1,28 @@ +use bevy::{ + ecs::{system::RunSystemOnce, world::Command}, + prelude::*, +}; +use grid::{generate_maze, plugin, render_maze, spawn_hex_grid}; +pub mod grid; +pub mod resource; +pub mod tile; + +pub struct MazePlugin; + +impl Plugin for MazePlugin { + fn build(&self, app: &mut App) { + app.add_plugins(plugin); + } +} + +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); + } +} + +pub fn spawn_grid(world: &mut World) { + MazePlugin.apply(world); +} diff --git a/src/maze/resource.rs b/src/maze/resource.rs new file mode 100644 index 0000000..7ecb034 --- /dev/null +++ b/src/maze/resource.rs @@ -0,0 +1,53 @@ +use bevy::prelude::*; +use hexx::{Hex, HexLayout, HexOrientation}; +use rand::{thread_rng, Rng}; + +#[derive(Debug, Reflect, Resource)] +#[reflect(Resource)] +pub struct MazeConfig { + pub radius: u32, + pub size: f32, + pub start_pos: Hex, + pub end_pos: Hex, +} + +impl Default for MazeConfig { + fn default() -> Self { + let mut rng = thread_rng(); + let radius = 5; + let start_pos = Hex::new( + rng.gen_range(-radius..radius), + rng.gen_range(-radius..radius), + ); + let end_pos = Hex::new( + rng.gen_range(-radius..radius), + rng.gen_range(-radius..radius), + ); + debug!("Start pos: ({},{})", start_pos.x, start_pos.y); + debug!("End pos: ({},{})", end_pos.x, end_pos.y); + Self { + radius: radius as u32, + size: 10., + start_pos, + end_pos, + } + } +} + +#[derive(Debug, Reflect, Resource, Deref, DerefMut, Clone)] +#[reflect(Resource)] +pub struct Layout(pub HexLayout); + +impl FromWorld for Layout { + fn from_world(world: &mut World) -> Self { + let size = world + .get_resource::() + .unwrap_or(&MazeConfig::default()) + .size; + Self(HexLayout { + orientation: HexOrientation::Pointy, + hex_size: Vec2::splat(size), + ..default() + }) + } +} diff --git a/src/maze/tile.rs b/src/maze/tile.rs new file mode 100644 index 0000000..bda8302 --- /dev/null +++ b/src/maze/tile.rs @@ -0,0 +1,46 @@ +use std::fmt::Display; + +use bevy::prelude::*; +use hexx::Hex; + +#[derive(Debug, Reflect, Component, Default, PartialEq, Eq, Hash, Clone)] +#[reflect(Component)] +pub struct Tile { + pub hex: Hex, + pub visited: bool, +} + +#[derive(Debug, Reflect, Component, Deref, DerefMut, Clone)] +#[reflect(Component)] +pub struct Walls(pub [bool; 6]); + +#[derive(Debug, Reflect, Bundle, Default)] +pub struct TileBundle { + pub hex: Tile, + pub walls: Walls, +} + +impl Tile { + pub fn new(q: i32, r: i32) -> Self { + Self { + hex: Hex::new(q, r), + visited: false, + } + } + + pub fn visit(&mut self) { + self.visited = true; + } +} + +impl Display for Tile { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "({},{})", self.hex.x, self.hex.y) + } +} + +impl Default for Walls { + fn default() -> Self { + Self([true; 6]) + } +} diff --git a/src/screens/gameplay.rs b/src/screens/gameplay.rs index 638ec9d..f932d17 100644 --- a/src/screens/gameplay.rs +++ b/src/screens/gameplay.rs @@ -5,7 +5,7 @@ use bevy::{input::common_conditions::input_just_pressed, prelude::*}; #[cfg(feature = "demo")] use crate::demo::level::spawn_level as spawn_level_command; #[cfg(not(feature = "demo"))] -use crate::hexgrid::spawn_grid as spawn_level_command; +use crate::maze::spawn_grid as spawn_level_command; use crate::{asset_tracking::LoadResource, audio::Music, screens::Screen}; pub(super) fn plugin(app: &mut App) { From ec9ac21b8ffe70c2e8c295695c28e8ae670d1d88 Mon Sep 17 00:00:00 2001 From: Kristofers Solo Date: Wed, 25 Sep 2024 20:29:58 +0300 Subject: [PATCH 13/20] feat(hex): draw hex prisms --- Cargo.lock | 319 ++++++++++++++++++++++++++++++++++++++++++++-- Cargo.toml | 3 + src/hex.rs | 14 -- src/lib.rs | 8 +- src/maze/grid.rs | 88 ++++++++----- src/maze/mod.rs | 11 +- src/maze/prism.rs | 64 ++++++++++ 7 files changed, 446 insertions(+), 61 deletions(-) delete mode 100644 src/hex.rs create mode 100644 src/maze/prism.rs diff --git a/Cargo.lock b/Cargo.lock index 9013d1e..a0188ca 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -180,6 +180,24 @@ dependencies = [ "num-traits", ] +[[package]] +name = "arboard" +version = "3.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df099ccb16cd014ff054ac1bf392c67feeef57164b05c42f037cd40f5d4357f4" +dependencies = [ + "clipboard-win", + "core-graphics", + "image 0.25.2", + "log", + "objc2", + "objc2-app-kit", + "objc2-foundation", + "parking_lot", + "windows-sys 0.48.0", + "x11rb", +] + [[package]] name = "arrayref" version = "0.3.8" @@ -304,6 +322,50 @@ dependencies = [ "bevy_internal", ] +[[package]] +name = "bevy-inspector-egui" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d46ba955761969dbc9a79d3583a175609b4e370303bc0f9a5846397dcb7f05fd" +dependencies = [ + "bevy-inspector-egui-derive", + "bevy_app", + "bevy_asset", + "bevy_color", + "bevy_core", + "bevy_core_pipeline", + "bevy_ecs", + "bevy_egui", + "bevy_hierarchy", + "bevy_log", + "bevy_math", + "bevy_pbr", + "bevy_reflect", + "bevy_render", + "bevy_state", + "bevy_time", + "bevy_utils", + "bevy_window", + "bytemuck", + "egui", + "fuzzy-matcher", + "image 0.24.9", + "once_cell", + "pretty-type-name", + "smallvec", +] + +[[package]] +name = "bevy-inspector-egui-derive" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06683f27065a27065ef8cebe77d7b347c9d0511a091deafd6dd77c5535434934" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.72", +] + [[package]] name = "bevy_a11y" version = "0.14.1" @@ -579,6 +641,29 @@ dependencies = [ "syn 2.0.72", ] +[[package]] +name = "bevy_egui" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "128438a8163e49528207aabf20d3ff0890fd6be0f0054626915995efac87922b" +dependencies = [ + "arboard", + "bevy", + "bytemuck", + "console_log", + "crossbeam-channel", + "egui", + "js-sys", + "log", + "thread_local", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "webbrowser", + "wgpu-types", + "winit", +] + [[package]] name = "bevy_encase_derive" version = "0.14.1" @@ -901,7 +986,7 @@ dependencies = [ "encase", "futures-lite", "hexasphere", - "image", + "image 0.25.2", "js-sys", "ktx2", "naga", @@ -1380,6 +1465,15 @@ dependencies = [ "libloading 0.8.5", ] +[[package]] +name = "clipboard-win" +version = "5.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15efe7a882b08f34e38556b14f2fb3daa98769d06c7f0c1b076dfd0d983bc892" +dependencies = [ + "error-code", +] + [[package]] name = "codespan-reporting" version = "0.11.1" @@ -1390,6 +1484,12 @@ dependencies = [ "unicode-width", ] +[[package]] +name = "color_quant" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" + [[package]] name = "com" version = "0.6.0" @@ -1450,6 +1550,16 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "console_log" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be8aed40e4edbf4d3b4431ab260b63fdc40f5780a4766824329ea0f1eefe3c0f" +dependencies = [ + "log", + "web-sys", +] + [[package]] name = "const-fnv1a-hash" version = "1.1.0" @@ -1494,10 +1604,20 @@ dependencies = [ ] [[package]] -name = "core-foundation-sys" -version = "0.8.6" +name = "core-foundation" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" +checksum = "b55271e5c8c478ad3f38ad24ef34923091e0548492a266d19b3c0b4d82574c63" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "core-graphics" @@ -1506,7 +1626,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c07782be35f9e1140080c6b96f0d44b739e2278479f64e02fdab4e32dfd8b081" dependencies = [ "bitflags 1.3.2", - "core-foundation", + "core-foundation 0.9.4", "core-graphics-types", "foreign-types", "libc", @@ -1519,7 +1639,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "45390e6114f68f718cc7a830514a96f903cccd70d02a8f6d9f643ac4ba45afaf" dependencies = [ "bitflags 1.3.2", - "core-foundation", + "core-foundation 0.9.4", "libc", ] @@ -1655,12 +1775,43 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f25c0e292a7ca6d6498557ff1df68f32c99850012b6ea401cf8daf771f22ff53" +[[package]] +name = "ecolor" +version = "0.28.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e6b451ff1143f6de0f33fc7f1b68fecfd2c7de06e104de96c4514de3f5396f8" +dependencies = [ + "bytemuck", + "emath", +] + +[[package]] +name = "egui" +version = "0.28.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20c97e70a2768de630f161bb5392cbd3874fcf72868f14df0e002e82e06cb798" +dependencies = [ + "ahash", + "emath", + "epaint", + "nohash-hasher", +] + [[package]] name = "either" version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" +[[package]] +name = "emath" +version = "0.28.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a6a21708405ea88f63d8309650b4d77431f4bc28fb9d8e6f77d3963b51249e6" +dependencies = [ + "bytemuck", +] + [[package]] name = "encase" version = "0.8.0" @@ -1693,6 +1844,21 @@ dependencies = [ "syn 2.0.72", ] +[[package]] +name = "epaint" +version = "0.28.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f0dcc0a0771e7500e94cd1cb797bd13c9f23b9409bdc3c824e2cbc562b7fa01" +dependencies = [ + "ab_glyph", + "ahash", + "bytemuck", + "ecolor", + "emath", + "nohash-hasher", + "parking_lot", +] + [[package]] name = "equivalent" version = "1.0.1" @@ -1719,6 +1885,12 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "error-code" +version = "3.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5d9305ccc6942a704f4335694ecd3de2ea531b114ac2d51f5f843750787a92f" + [[package]] name = "euclid" version = "0.22.10" @@ -1852,6 +2024,15 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b" +[[package]] +name = "form_urlencoded" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +dependencies = [ + "percent-encoding", +] + [[package]] name = "fsevent-sys" version = "4.1.0" @@ -1886,6 +2067,15 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "fuzzy-matcher" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54614a3312934d066701a80f20f15fa3b56d67ac7722b39eea5b4c9dd1d66c94" +dependencies = [ + "thread_local", +] + [[package]] name = "gethostname" version = "0.4.3" @@ -1928,7 +2118,7 @@ version = "0.5.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbb5e8d912059b33b463831c16b838d15c4772d584ce332e4a80f6dffdae2bc1" dependencies = [ - "core-foundation", + "core-foundation 0.9.4", "inotify 0.10.2", "io-kit-sys", "js-sys", @@ -2166,6 +2356,37 @@ dependencies = [ "serde", ] +[[package]] +name = "home" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "idna" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "image" +version = "0.24.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5690139d2f55868e080017335e4b94cb7414274c74f1669c84fb5feba2c9f69d" +dependencies = [ + "bytemuck", + "byteorder", + "color_quant", + "num-traits", +] + [[package]] name = "image" version = "0.25.2" @@ -2176,6 +2397,7 @@ dependencies = [ "byteorder-lite", "num-traits", "png", + "tiff", ] [[package]] @@ -2290,6 +2512,12 @@ dependencies = [ "libc", ] +[[package]] +name = "jpeg-decoder" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5d4a7da358eff58addd2877a45865158f0d78c911d43a5784ceb7bbf52833b0" + [[package]] name = "js-sys" version = "0.3.69" @@ -2692,6 +2920,12 @@ dependencies = [ "libc", ] +[[package]] +name = "nohash-hasher" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bf50223579dc7cdcfb3bfcacf7069ff68243f8c363f62ffa99cf000a6b9c451" + [[package]] name = "nom" version = "7.1.3" @@ -3224,6 +3458,12 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8cf8e6a8aa66ce33f63993ffc4ea4271eb5b0530a9002db8455ea6050c77bfa" +[[package]] +name = "pretty-type-name" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f73cdaf19b52e6143685c3606206e114a4dfa969d6b14ec3894c88eb38bd4b" + [[package]] name = "proc-macro-crate" version = "3.1.0" @@ -3703,6 +3943,7 @@ name = "the-labyrinth-of-echoes" version = "0.0.3" dependencies = [ "bevy", + "bevy-inspector-egui", "bevy_prototype_lyon", "hexx", "log", @@ -3740,6 +3981,17 @@ dependencies = [ "once_cell", ] +[[package]] +name = "tiff" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba1310fcea54c6a9a4fd1aad794ecc02c31682f6bfbecdf460bf19533eed1e3e" +dependencies = [ + "flate2", + "jpeg-decoder", + "weezl", +] + [[package]] name = "tiny-skia" version = "0.11.4" @@ -3902,12 +4154,27 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "059d83cc991e7a42fc37bd50941885db0888e34209f8cfd9aab07ddec03bc9cf" +[[package]] +name = "unicode-bidi" +version = "0.3.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" + [[package]] name = "unicode-ident" version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +[[package]] +name = "unicode-normalization" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956" +dependencies = [ + "tinyvec", +] + [[package]] name = "unicode-segmentation" version = "1.11.0" @@ -3926,6 +4193,17 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" +[[package]] +name = "url" +version = "2.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] + [[package]] name = "uuid" version = "1.10.0" @@ -4141,6 +4419,7 @@ checksum = "43676fe2daf68754ecf1d72026e4e6c15483198b5d24e888b74d3f22f887a148" dependencies = [ "dlib", "log", + "once_cell", "pkg-config", ] @@ -4164,6 +4443,30 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "webbrowser" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e5f07fb9bc8de2ddfe6b24a71a75430673fd679e568c48b52716cef1cfae923" +dependencies = [ + "block2", + "core-foundation 0.10.0", + "home", + "jni", + "log", + "ndk-context", + "objc2", + "objc2-foundation", + "url", + "web-sys", +] + +[[package]] +name = "weezl" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53a85b86a771b1c87058196170769dd264f66c0782acf1ae6cc51bfd64b39082" + [[package]] name = "wgpu" version = "0.20.1" @@ -4675,7 +4978,7 @@ dependencies = [ "calloop", "cfg_aliases 0.2.1", "concurrent-queue", - "core-foundation", + "core-foundation 0.9.4", "core-graphics", "cursor-icon", "dpi", diff --git a/Cargo.toml b/Cargo.toml index 914f76e..2cb5457 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,6 +20,9 @@ tracing = { version = "0.1", features = [ hexx = { version = "0.18", features = ["bevy_reflect", "grid"] } bevy_prototype_lyon = "0.12" +[dev-dependencies] +bevy-inspector-egui = "0.26" + [features] default = [ # Default to a native dev build. diff --git a/src/hex.rs b/src/hex.rs deleted file mode 100644 index 2f48253..0000000 --- a/src/hex.rs +++ /dev/null @@ -1,14 +0,0 @@ -use bevy::{color::palettes::css::BLACK, prelude::*}; - -use bevy_prototype_lyon::{ - draw::{Fill, Stroke}, - entity::ShapeBundle, - path::PathBuilder, - plugin::ShapePlugin, -}; -use rand::{thread_rng, Rng}; - -pub(super) fn plugin(app: &mut App) { - app.add_plugins(ShapePlugin); - app.add_systems(Startup, setup_system); -} diff --git a/src/lib.rs b/src/lib.rs index c0ad671..06307ab 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -9,6 +9,8 @@ mod maze; mod screens; mod theme; +use std::f32::consts::FRAC_PI_4; + use bevy::{ asset::AssetMetaCheck, audio::{AudioPlugin, Volume}, @@ -90,7 +92,11 @@ enum AppSet { fn spawn_camera(mut commands: Commands) { commands.spawn(( Name::new("Camera"), - Camera2dBundle::default(), + Camera3dBundle { + transform: Transform::from_xyz(0., 5., 10.).looking_at(Vec3::ZERO, Vec3::Y), + ..default() + }, + // Camera2dBundle::default(), // Render all UI to this camera. // Not strictly necessary since we only use one camera, // but if we don't use this component, our UI will disappear as soon diff --git a/src/maze/grid.rs b/src/maze/grid.rs index 9247675..24bab0c 100644 --- a/src/maze/grid.rs +++ b/src/maze/grid.rs @@ -1,11 +1,12 @@ -use std::usize; +use std::{f32::consts::PI, usize}; use bevy::{ - color::palettes::css::{BLACK, GREEN, RED}, + color::palettes::css::{BLACK, GREEN, RED, SILVER}, + pbr::wireframe::{Wireframe, WireframeConfig, WireframePlugin}, prelude::*, + render::{mesh::PrimitiveTopology, render_asset::RenderAssetUsages}, utils::hashbrown::HashMap, }; - use bevy_prototype_lyon::{ draw::{Fill, Stroke}, entity::ShapeBundle, @@ -13,7 +14,6 @@ use bevy_prototype_lyon::{ plugin::ShapePlugin, }; use hexx::{EdgeDirection, Hex}; -use log::info; use rand::{prelude::SliceRandom, rngs::ThreadRng, thread_rng}; use super::{ @@ -22,9 +22,28 @@ use super::{ }; pub(super) fn plugin(app: &mut App) { - app.add_plugins(ShapePlugin); + app.add_plugins((ShapePlugin, WireframePlugin)); app.init_resource::(); app.init_resource::(); + app.insert_resource(WireframeConfig { + global: false, + ..default() + }); +} + +pub(super) fn spawn_light(mut commands: Commands) { + commands.spawn(( + Name::new("Light Source"), + PointLightBundle { + point_light: PointLight { + intensity: 5000., + shadows_enabled: true, + ..default() + }, + transform: Transform::from_xyz(5., 10., 5.), + ..default() + }, + )); } pub(super) fn spawn_hex_grid(mut commands: Commands, config: Res) { @@ -109,7 +128,7 @@ fn remove_wall_between( fn add_hex_tile( commands: &mut Commands, - position: Vec2, + position: Vec3, size: f32, tile: &Tile, walls: &Walls, @@ -122,7 +141,7 @@ fn add_hex_tile( .into_iter() .map(|v| { let mut layout = layout.clone(); - layout.origin = position; + layout.origin = position.xy(); layout.hex_size = Vec2::splat(size); layout.hex_to_world_pos(v.origin + v.direction) }) @@ -137,34 +156,35 @@ fn add_hex_tile( let hexagon = path_builder.build(); // Create the hexagon fill - commands.spawn(( - ShapeBundle { - path: hexagon, - spatial: SpatialBundle { - transform: Transform::from_xyz(position.x, position.y, 0.), + commands + .spawn(( + ShapeBundle { + path: hexagon, + spatial: SpatialBundle { + transform: Transform::from_xyz(position.x, position.y, 0.), + ..default() + }, ..default() }, - ..default() - }, - Fill::color(fill_color), - )); - // .with_children(|p| { - // p.spawn(Text2dBundle { - // text: Text { - // sections: vec![TextSection { - // value: tile.to_string(), - // style: TextStyle { - // font_size: 16., - // color: Color::BLACK, - // ..default() - // }, - // }], - // ..default() - // }, - // transform: Transform::from_xyz(position.x * 2., position.y * 2., 1.), - // ..default() - // }); - // }); + Fill::color(fill_color), + )) + .with_children(|p| { + p.spawn(Text2dBundle { + text: Text { + sections: vec![TextSection { + value: tile.to_string(), + style: TextStyle { + font_size: 16., + color: Color::BLACK, + ..default() + }, + }], + ..default() + }, + transform: Transform::from_xyz(position.x * 2., position.y * 2., 1.), + ..default() + }); + }); // Draw walls for direction in EdgeDirection::iter() { @@ -199,7 +219,7 @@ pub(super) fn render_maze( config: Res, ) { for (tile, walls) in query.iter() { - let world_pos = layout.hex_to_world_pos(tile.hex); + let world_pos = layout.hex_to_world_pos(tile.hex).extend(0.); let fill_color = match tile.hex { pos if pos == config.start_pos => GREEN.into(), pos if pos == config.end_pos => RED.into(), diff --git a/src/maze/mod.rs b/src/maze/mod.rs index 8a347d3..7f31591 100644 --- a/src/maze/mod.rs +++ b/src/maze/mod.rs @@ -2,8 +2,9 @@ use bevy::{ ecs::{system::RunSystemOnce, world::Command}, prelude::*, }; -use grid::{generate_maze, plugin, render_maze, spawn_hex_grid}; +use grid::{generate_maze, plugin, render_maze, spawn_hex_grid, spawn_light}; pub mod grid; +pub mod prism; pub mod resource; pub mod tile; @@ -17,9 +18,11 @@ impl Plugin for MazePlugin { 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(spawn_hex_grid); + // world.run_system_once(generate_maze); + // world.run_system_once(render_maze); + world.run_system_once(spawn_light); + world.run_system_once(prism::setup); } } diff --git a/src/maze/prism.rs b/src/maze/prism.rs new file mode 100644 index 0000000..46d5cb4 --- /dev/null +++ b/src/maze/prism.rs @@ -0,0 +1,64 @@ +use bevy::prelude::*; +use std::f32::consts::FRAC_PI_2; + +#[derive(Debug, Reflect, Component)] +#[reflect(Component)] +struct Prism { + radius: f32, + height: f32, +} + +struct PrismParams { + positions: Vec3, + radius: f32, + height: f32, +} + +pub(super) fn setup( + mut commands: Commands, + mut meshes: ResMut>, + mut materials: ResMut>, +) { + let prism_material = materials.add(Color::WHITE); + + let prisms = vec![ + PrismParams { + positions: Vec3::new(-3., 0., 0.), + radius: 1., + height: 2., + }, + PrismParams { + positions: Vec3::new(0., 0., 0.), + radius: 1.5, + height: 2.5, + }, + PrismParams { + positions: Vec3::new(3., 0., 0.), + radius: 0.8, + height: 1.5, + }, + ]; + + for params in prisms { + let hexagon = RegularPolygon { + sides: 6, + circumcircle: Circle::new(params.radius), + }; + let prism_shape = Extrusion::new(hexagon, params.height); + let prism_mesh = meshes.add(Mesh::from(prism_shape)); + + commands.spawn(( + PbrBundle { + mesh: prism_mesh, + material: prism_material.clone(), + transform: Transform::from_translation(params.positions) + .with_rotation(Quat::from_rotation_x(FRAC_PI_2)), + ..default() + }, + Prism { + radius: params.radius, + height: params.height, + }, + )); + } +} From 623b53c34f8a070dd32445a1d6135acf2a7fc7bd Mon Sep 17 00:00:00 2001 From: Kristofers Solo Date: Thu, 26 Sep 2024 12:25:40 +0300 Subject: [PATCH 14/20] feat(dev): add bevy inspector egui --- Cargo.toml | 4 ++-- src/dev_tools.rs | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 2cb5457..a8d8225 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,9 +19,8 @@ tracing = { version = "0.1", features = [ ] } hexx = { version = "0.18", features = ["bevy_reflect", "grid"] } bevy_prototype_lyon = "0.12" +bevy-inspector-egui = { version = "0.26", optional = true } -[dev-dependencies] -bevy-inspector-egui = "0.26" [features] default = [ @@ -32,6 +31,7 @@ dev = [ # Improve compile times for dev builds by linking Bevy as a dynamic library. "bevy/dynamic_linking", "bevy/bevy_dev_tools", + "bevy-inspector-egui", ] dev_native = [ "dev", diff --git a/src/dev_tools.rs b/src/dev_tools.rs index 7f387db..1b78f7e 100644 --- a/src/dev_tools.rs +++ b/src/dev_tools.rs @@ -9,6 +9,8 @@ use bevy::{ prelude::*, }; +use bevy_inspector_egui::quick::WorldInspectorPlugin; + use crate::screens::Screen; pub(super) fn plugin(app: &mut App) { @@ -17,6 +19,7 @@ pub(super) fn plugin(app: &mut App) { // Toggle the debug overlay for UI. app.add_plugins(DebugUiPlugin); + app.add_plugins(WorldInspectorPlugin::default()); app.add_systems( Update, toggle_debug_ui.run_if(input_just_pressed(TOGGLE_KEY)), From 1a8eeb97b5a9816c109a1051c9ca15a29cc91b24 Mon Sep 17 00:00:00 2001 From: Kristofers Solo Date: Sun, 29 Sep 2024 20:01:18 +0300 Subject: [PATCH 15/20] feat(prism): impl Default --- src/lib.rs | 5 +---- src/maze/grid.rs | 17 +------------- src/maze/mod.rs | 4 ++-- src/maze/prism.rs | 56 +++++++++++++++++++++++++++++++---------------- 4 files changed, 41 insertions(+), 41 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 06307ab..d58e021 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -9,8 +9,6 @@ mod maze; mod screens; mod theme; -use std::f32::consts::FRAC_PI_4; - use bevy::{ asset::AssetMetaCheck, audio::{AudioPlugin, Volume}, @@ -93,10 +91,9 @@ fn spawn_camera(mut commands: Commands) { commands.spawn(( Name::new("Camera"), Camera3dBundle { - transform: Transform::from_xyz(0., 5., 10.).looking_at(Vec3::ZERO, Vec3::Y), + transform: Transform::from_xyz(0., 15., 10.).looking_at(Vec3::ZERO, Vec3::Y), ..default() }, - // Camera2dBundle::default(), // Render all UI to this camera. // Not strictly necessary since we only use one camera, // but if we don't use this component, our UI will disappear as soon diff --git a/src/maze/grid.rs b/src/maze/grid.rs index 24bab0c..98b41a1 100644 --- a/src/maze/grid.rs +++ b/src/maze/grid.rs @@ -1,4 +1,4 @@ -use std::{f32::consts::PI, usize}; +use std::usize; use bevy::{ color::palettes::css::{BLACK, GREEN, RED, SILVER}, @@ -31,21 +31,6 @@ pub(super) fn plugin(app: &mut App) { }); } -pub(super) fn spawn_light(mut commands: Commands) { - commands.spawn(( - Name::new("Light Source"), - PointLightBundle { - point_light: PointLight { - intensity: 5000., - shadows_enabled: true, - ..default() - }, - transform: Transform::from_xyz(5., 10., 5.), - ..default() - }, - )); -} - pub(super) fn spawn_hex_grid(mut commands: Commands, config: Res) { let radius = config.radius as i32; diff --git a/src/maze/mod.rs b/src/maze/mod.rs index 7f31591..6392dd4 100644 --- a/src/maze/mod.rs +++ b/src/maze/mod.rs @@ -2,7 +2,7 @@ use bevy::{ ecs::{system::RunSystemOnce, world::Command}, prelude::*, }; -use grid::{generate_maze, plugin, render_maze, spawn_hex_grid, spawn_light}; +use grid::{generate_maze, plugin, render_maze, spawn_hex_grid}; pub mod grid; pub mod prism; pub mod resource; @@ -12,6 +12,7 @@ pub struct MazePlugin; impl Plugin for MazePlugin { fn build(&self, app: &mut App) { + app.add_plugins(prism::plugin); app.add_plugins(plugin); } } @@ -21,7 +22,6 @@ impl Command for MazePlugin { // world.run_system_once(spawn_hex_grid); // world.run_system_once(generate_maze); // world.run_system_once(render_maze); - world.run_system_once(spawn_light); world.run_system_once(prism::setup); } } diff --git a/src/maze/prism.rs b/src/maze/prism.rs index 46d5cb4..9833d5d 100644 --- a/src/maze/prism.rs +++ b/src/maze/prism.rs @@ -1,6 +1,10 @@ use bevy::prelude::*; use std::f32::consts::FRAC_PI_2; +pub(super) fn plugin(app: &mut App) { + app.add_systems(Update, spawn_light); +} + #[derive(Debug, Reflect, Component)] #[reflect(Component)] struct Prism { @@ -9,11 +13,41 @@ struct Prism { } struct PrismParams { - positions: Vec3, + position: Vec3, radius: f32, height: f32, } +impl From for PrismParams { + fn from(value: Vec3) -> Self { + Self { + position: value, + ..default() + } + } +} + +impl Default for PrismParams { + fn default() -> Self { + Self { + position: Vec3::ZERO, + radius: 2., + height: 4., + } + } +} + +pub(super) fn spawn_light(mut commands: Commands) { + commands.spawn(( + Name::new("Light Source"), + PointLightBundle { + point_light: PointLight { ..default() }, + transform: Transform::from_xyz(5., 10., 5.), + ..default() + }, + )); +} + pub(super) fn setup( mut commands: Commands, mut meshes: ResMut>, @@ -21,23 +55,7 @@ pub(super) fn setup( ) { let prism_material = materials.add(Color::WHITE); - let prisms = vec![ - PrismParams { - positions: Vec3::new(-3., 0., 0.), - radius: 1., - height: 2., - }, - PrismParams { - positions: Vec3::new(0., 0., 0.), - radius: 1.5, - height: 2.5, - }, - PrismParams { - positions: Vec3::new(3., 0., 0.), - radius: 0.8, - height: 1.5, - }, - ]; + let prisms: Vec = vec![Vec3::ZERO.into()]; for params in prisms { let hexagon = RegularPolygon { @@ -51,7 +69,7 @@ pub(super) fn setup( PbrBundle { mesh: prism_mesh, material: prism_material.clone(), - transform: Transform::from_translation(params.positions) + transform: Transform::from_translation(params.position) .with_rotation(Quat::from_rotation_x(FRAC_PI_2)), ..default() }, From c471382f6fd3293442fac66f90ee0df3c6b82880 Mon Sep 17 00:00:00 2001 From: Kristofers Solo Date: Sat, 12 Oct 2024 15:59:17 +0300 Subject: [PATCH 16/20] feat(grid): draw 3d hex grid --- src/lib.rs | 4 +- src/maze/mod.rs | 28 ++---------- src/maze/plugin.rs | 25 ++++++++++ src/maze/prism.rs | 106 ++++++++++++++++++++----------------------- src/maze/resource.rs | 4 +- src/maze/tile.rs | 11 ++++- 6 files changed, 93 insertions(+), 85 deletions(-) create mode 100644 src/maze/plugin.rs diff --git a/src/lib.rs b/src/lib.rs index d58e021..83b126f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -63,7 +63,7 @@ impl Plugin for AppPlugin { #[cfg(feature = "demo")] demo::plugin, #[cfg(not(feature = "demo"))] - maze::MazePlugin, + maze::plugin::MazePlugin::default(), screens::plugin, theme::plugin, )); @@ -91,7 +91,7 @@ fn spawn_camera(mut commands: Commands) { commands.spawn(( Name::new("Camera"), Camera3dBundle { - transform: Transform::from_xyz(0., 15., 10.).looking_at(Vec3::ZERO, Vec3::Y), + transform: Transform::from_xyz(0., 100., 0.).looking_at(Vec3::ZERO, Vec3::Y), ..default() }, // Render all UI to this camera. diff --git a/src/maze/mod.rs b/src/maze/mod.rs index 6392dd4..31264df 100644 --- a/src/maze/mod.rs +++ b/src/maze/mod.rs @@ -1,31 +1,11 @@ -use bevy::{ - ecs::{system::RunSystemOnce, world::Command}, - prelude::*, -}; -use grid::{generate_maze, plugin, render_maze, spawn_hex_grid}; +use bevy::{ecs::world::Command, prelude::*}; +use plugin::MazePlugin; pub mod grid; +pub mod plugin; pub mod prism; pub mod resource; pub mod tile; -pub struct MazePlugin; - -impl Plugin for MazePlugin { - fn build(&self, app: &mut App) { - app.add_plugins(prism::plugin); - app.add_plugins(plugin); - } -} - -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); - } -} - pub fn spawn_grid(world: &mut World) { - MazePlugin.apply(world); + MazePlugin::default().apply(world); } diff --git a/src/maze/plugin.rs b/src/maze/plugin.rs new file mode 100644 index 0000000..11584e0 --- /dev/null +++ b/src/maze/plugin.rs @@ -0,0 +1,25 @@ +use bevy::{ + ecs::{system::RunSystemOnce, world::Command}, + prelude::*, +}; + +use super::{grid, prism}; + +#[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); + } +} + +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); + } +} diff --git a/src/maze/prism.rs b/src/maze/prism.rs index 9833d5d..8fd4119 100644 --- a/src/maze/prism.rs +++ b/src/maze/prism.rs @@ -1,48 +1,20 @@ use bevy::prelude::*; use std::f32::consts::FRAC_PI_2; +use super::{ + resource::{Layout, MazeConfig}, + tile::Tile, +}; + pub(super) fn plugin(app: &mut App) { - app.add_systems(Update, spawn_light); -} - -#[derive(Debug, Reflect, Component)] -#[reflect(Component)] -struct Prism { - radius: f32, - height: f32, -} - -struct PrismParams { - position: Vec3, - radius: f32, - height: f32, -} - -impl From for PrismParams { - fn from(value: Vec3) -> Self { - Self { - position: value, - ..default() - } - } -} - -impl Default for PrismParams { - fn default() -> Self { - Self { - position: Vec3::ZERO, - radius: 2., - height: 4., - } - } + app.add_systems(Startup, spawn_light); } pub(super) fn spawn_light(mut commands: Commands) { commands.spawn(( Name::new("Light Source"), PointLightBundle { - point_light: PointLight { ..default() }, - transform: Transform::from_xyz(5., 10., 5.), + transform: Transform::from_xyz(0., 50., 0.), ..default() }, )); @@ -52,31 +24,51 @@ pub(super) fn setup( mut commands: Commands, mut meshes: ResMut>, mut materials: ResMut>, + config: Res, + layout: Res, ) { - let prism_material = materials.add(Color::WHITE); + let radius = config.radius as i32; - let prisms: Vec = vec![Vec3::ZERO.into()]; + let rotation = Quat::from_rotation_x(-FRAC_PI_2); + let material = materials.add(Color::WHITE); + let prism_mesh = generate_hex_prism_mesh(layout.hex_size.x, config.height); + let mesh = meshes.add(prism_mesh); - for params in prisms { - let hexagon = RegularPolygon { - sides: 6, - circumcircle: Circle::new(params.radius), - }; - let prism_shape = Extrusion::new(hexagon, params.height); - let prism_mesh = meshes.add(Mesh::from(prism_shape)); - - commands.spawn(( - PbrBundle { - mesh: prism_mesh, - material: prism_material.clone(), - transform: Transform::from_translation(params.position) - .with_rotation(Quat::from_rotation_x(FRAC_PI_2)), + commands + .spawn(( + Name::new("Floor"), + SpatialBundle { + transform: Transform::from_translation(Vec3::ZERO), ..default() }, - Prism { - radius: params.radius, - height: params.height, - }, - )); - } + )) + .with_children(|p| { + for q in -radius..=radius { + let r1 = (-radius).max(-q - radius); + let r2 = radius.min(-q + radius); + for r in r1..=r2 { + let tile = Tile::new(q, r); + let pos = tile.to_vec3(&layout); + p.spawn(( + Name::new(format!("Hex {}", &tile.to_string())), + PbrBundle { + mesh: mesh.clone(), + material: material.clone(), + transform: Transform::from_translation(pos).with_rotation(rotation), + ..default() + }, + )); + } + } + }); +} + +fn generate_hex_prism_mesh(radius: f32, depth: f32) -> Mesh { + let hexagon = RegularPolygon { + sides: 6, + circumcircle: Circle::new(radius), + }; + let prism_shape = Extrusion::new(hexagon, depth); + + Mesh::from(prism_shape) } diff --git a/src/maze/resource.rs b/src/maze/resource.rs index 7ecb034..e6485d2 100644 --- a/src/maze/resource.rs +++ b/src/maze/resource.rs @@ -7,6 +7,7 @@ use rand::{thread_rng, Rng}; pub struct MazeConfig { pub radius: u32, pub size: f32, + pub height: f32, pub start_pos: Hex, pub end_pos: Hex, } @@ -27,7 +28,8 @@ impl Default for MazeConfig { debug!("End pos: ({},{})", end_pos.x, end_pos.y); Self { radius: radius as u32, - size: 10., + size: 5., + height: 5., start_pos, end_pos, } diff --git a/src/maze/tile.rs b/src/maze/tile.rs index bda8302..0548edc 100644 --- a/src/maze/tile.rs +++ b/src/maze/tile.rs @@ -1,7 +1,7 @@ use std::fmt::Display; use bevy::prelude::*; -use hexx::Hex; +use hexx::{Hex, HexLayout}; #[derive(Debug, Reflect, Component, Default, PartialEq, Eq, Hash, Clone)] #[reflect(Component)] @@ -31,6 +31,15 @@ impl Tile { pub fn visit(&mut self) { self.visited = true; } + + pub fn to_vec2(&self, layout: &HexLayout) -> Vec2 { + layout.hex_to_world_pos(self.hex) + } + + pub fn to_vec3(&self, layout: &HexLayout) -> Vec3 { + let pos = self.to_vec2(layout); + Vec3::new(pos.x, 0., pos.y) + } } impl Display for Tile { From 07794aa993adce26e89e8a430eb8c19b98ff72b8 Mon Sep 17 00:00:00 2001 From: Kristofers Solo Date: Fri, 25 Oct 2024 17:22:37 +0300 Subject: [PATCH 17/20] feat(lighting): add ambient light --- Cargo.lock | 72 +++++++++++++++----------------------------- Cargo.toml | 2 +- src/lib.rs | 4 +-- src/maze/plugin.rs | 5 +++ src/maze/prism.rs | 16 ++-------- src/maze/resource.rs | 6 ++-- 6 files changed, 38 insertions(+), 67 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a0188ca..5c39b4e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -188,7 +188,7 @@ checksum = "df099ccb16cd014ff054ac1bf392c67feeef57164b05c42f037cd40f5d4357f4" dependencies = [ "clipboard-win", "core-graphics", - "image 0.25.2", + "image", "log", "objc2", "objc2-app-kit", @@ -324,9 +324,9 @@ dependencies = [ [[package]] name = "bevy-inspector-egui" -version = "0.26.0" +version = "0.27.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d46ba955761969dbc9a79d3583a175609b4e370303bc0f9a5846397dcb7f05fd" +checksum = "cac12a22e5de801323bc5bc344949de086b9b8db02c34e109f128ffd41514e5d" dependencies = [ "bevy-inspector-egui-derive", "bevy_app", @@ -349,17 +349,17 @@ dependencies = [ "bytemuck", "egui", "fuzzy-matcher", - "image 0.24.9", - "once_cell", + "image", "pretty-type-name", "smallvec", + "winit", ] [[package]] name = "bevy-inspector-egui-derive" -version = "0.26.0" +version = "0.27.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06683f27065a27065ef8cebe77d7b347c9d0511a091deafd6dd77c5535434934" +checksum = "89f3be3ba88a25445c0c10684709b1ccd07e37f5f6b5d1b8dcf11d34548f1d61" dependencies = [ "proc-macro2", "quote", @@ -643,14 +643,13 @@ dependencies = [ [[package]] name = "bevy_egui" -version = "0.29.0" +version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "128438a8163e49528207aabf20d3ff0890fd6be0f0054626915995efac87922b" +checksum = "d0b8c164da1303ac3e6dc8d1a649be3e4399f12fd132f7665f3d018884236f9c" dependencies = [ "arboard", "bevy", "bytemuck", - "console_log", "crossbeam-channel", "egui", "js-sys", @@ -986,7 +985,7 @@ dependencies = [ "encase", "futures-lite", "hexasphere", - "image 0.25.2", + "image", "js-sys", "ktx2", "naga", @@ -1484,12 +1483,6 @@ dependencies = [ "unicode-width", ] -[[package]] -name = "color_quant" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" - [[package]] name = "com" version = "0.6.0" @@ -1550,16 +1543,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "console_log" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be8aed40e4edbf4d3b4431ab260b63fdc40f5780a4766824329ea0f1eefe3c0f" -dependencies = [ - "log", - "web-sys", -] - [[package]] name = "const-fnv1a-hash" version = "1.1.0" @@ -1777,9 +1760,9 @@ checksum = "f25c0e292a7ca6d6498557ff1df68f32c99850012b6ea401cf8daf771f22ff53" [[package]] name = "ecolor" -version = "0.28.1" +version = "0.29.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e6b451ff1143f6de0f33fc7f1b68fecfd2c7de06e104de96c4514de3f5396f8" +checksum = "775cfde491852059e386c4e1deb4aef381c617dc364184c6f6afee99b87c402b" dependencies = [ "bytemuck", "emath", @@ -1787,9 +1770,9 @@ dependencies = [ [[package]] name = "egui" -version = "0.28.1" +version = "0.29.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20c97e70a2768de630f161bb5392cbd3874fcf72868f14df0e002e82e06cb798" +checksum = "53eafabcce0cb2325a59a98736efe0bf060585b437763f8c476957fb274bb974" dependencies = [ "ahash", "emath", @@ -1805,9 +1788,9 @@ checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" [[package]] name = "emath" -version = "0.28.1" +version = "0.29.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a6a21708405ea88f63d8309650b4d77431f4bc28fb9d8e6f77d3963b51249e6" +checksum = "b1fe0049ce51d0fb414d029e668dd72eb30bc2b739bf34296ed97bd33df544f3" dependencies = [ "bytemuck", ] @@ -1846,19 +1829,26 @@ dependencies = [ [[package]] name = "epaint" -version = "0.28.1" +version = "0.29.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f0dcc0a0771e7500e94cd1cb797bd13c9f23b9409bdc3c824e2cbc562b7fa01" +checksum = "a32af8da821bd4f43f2c137e295459ee2e1661d87ca8779dfa0eaf45d870e20f" dependencies = [ "ab_glyph", "ahash", "bytemuck", "ecolor", "emath", + "epaint_default_fonts", "nohash-hasher", "parking_lot", ] +[[package]] +name = "epaint_default_fonts" +version = "0.29.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "483440db0b7993cf77a20314f08311dbe95675092405518c0677aa08c151a3ea" + [[package]] name = "equivalent" version = "1.0.1" @@ -2375,18 +2365,6 @@ dependencies = [ "unicode-normalization", ] -[[package]] -name = "image" -version = "0.24.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5690139d2f55868e080017335e4b94cb7414274c74f1669c84fb5feba2c9f69d" -dependencies = [ - "bytemuck", - "byteorder", - "color_quant", - "num-traits", -] - [[package]] name = "image" version = "0.25.2" diff --git a/Cargo.toml b/Cargo.toml index a8d8225..4d6e8ff 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,7 +19,7 @@ tracing = { version = "0.1", features = [ ] } hexx = { version = "0.18", features = ["bevy_reflect", "grid"] } bevy_prototype_lyon = "0.12" -bevy-inspector-egui = { version = "0.26", optional = true } +bevy-inspector-egui = { version = "0.27", optional = true } [features] diff --git a/src/lib.rs b/src/lib.rs index 83b126f..843efe6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -51,7 +51,7 @@ impl Plugin for AppPlugin { }) .set(AudioPlugin { global_volume: GlobalVolume { - volume: Volume::new(0.3), + volume: Volume::new(0.), }, ..default() }), @@ -91,7 +91,7 @@ fn spawn_camera(mut commands: Commands) { commands.spawn(( Name::new("Camera"), Camera3dBundle { - transform: Transform::from_xyz(0., 100., 0.).looking_at(Vec3::ZERO, Vec3::Y), + transform: Transform::from_xyz(0., 100., 100.).looking_at(Vec3::ZERO, Vec3::Y), ..default() }, // Render all UI to this camera. diff --git a/src/maze/plugin.rs b/src/maze/plugin.rs index 11584e0..8ff67cf 100644 --- a/src/maze/plugin.rs +++ b/src/maze/plugin.rs @@ -1,5 +1,6 @@ use bevy::{ ecs::{system::RunSystemOnce, world::Command}, + pbr::wireframe::WireframePlugin, prelude::*, }; @@ -12,6 +13,10 @@ 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, + }); } } diff --git a/src/maze/prism.rs b/src/maze/prism.rs index 8fd4119..d5b27f9 100644 --- a/src/maze/prism.rs +++ b/src/maze/prism.rs @@ -1,4 +1,4 @@ -use bevy::prelude::*; +use bevy::{pbr::wireframe::Wireframe, prelude::*}; use std::f32::consts::FRAC_PI_2; use super::{ @@ -6,19 +6,7 @@ use super::{ tile::Tile, }; -pub(super) fn plugin(app: &mut App) { - app.add_systems(Startup, spawn_light); -} - -pub(super) fn spawn_light(mut commands: Commands) { - commands.spawn(( - Name::new("Light Source"), - PointLightBundle { - transform: Transform::from_xyz(0., 50., 0.), - ..default() - }, - )); -} +pub(super) fn plugin(_app: &mut App) {} pub(super) fn setup( mut commands: Commands, diff --git a/src/maze/resource.rs b/src/maze/resource.rs index e6485d2..b12ad2b 100644 --- a/src/maze/resource.rs +++ b/src/maze/resource.rs @@ -15,7 +15,7 @@ pub struct MazeConfig { impl Default for MazeConfig { fn default() -> Self { let mut rng = thread_rng(); - let radius = 5; + let radius = 11; let start_pos = Hex::new( rng.gen_range(-radius..radius), rng.gen_range(-radius..radius), @@ -28,8 +28,8 @@ impl Default for MazeConfig { debug!("End pos: ({},{})", end_pos.x, end_pos.y); Self { radius: radius as u32, - size: 5., - height: 5., + size: 1., + height: 15., start_pos, end_pos, } From 00c90916e58f891e948f7a7fa73d6b19575c3041 Mon Sep 17 00:00:00 2001 From: Kristofers Solo Date: Mon, 4 Nov 2024 20:18:04 +0200 Subject: [PATCH 18/20] feat(walls): draw tile walls --- src/lib.rs | 2 +- src/maze/grid.rs | 4 +- src/maze/plugin.rs | 9 ++- src/maze/prism.rs | 127 ++++++++++++++++++++++++++++++++++++------- src/maze/resource.rs | 14 ++--- 5 files changed, 118 insertions(+), 38 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 843efe6..f1e343c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -91,7 +91,7 @@ fn spawn_camera(mut commands: Commands) { commands.spawn(( Name::new("Camera"), Camera3dBundle { - transform: Transform::from_xyz(0., 100., 100.).looking_at(Vec3::ZERO, Vec3::Y), + transform: Transform::from_xyz(0., 300., 300.).looking_at(Vec3::ZERO, Vec3::Y), ..default() }, // Render all UI to this camera. diff --git a/src/maze/grid.rs b/src/maze/grid.rs index 98b41a1..bc4bc78 100644 --- a/src/maze/grid.rs +++ b/src/maze/grid.rs @@ -17,7 +17,7 @@ use hexx::{EdgeDirection, Hex}; use rand::{prelude::SliceRandom, rngs::ThreadRng, thread_rng}; use super::{ - resource::{Layout, MazeConfig}, + resource::{Layout, MazeConfig, HEX_SIZE}, tile::{Tile, TileBundle, Walls}, }; @@ -213,7 +213,7 @@ pub(super) fn render_maze( add_hex_tile( &mut commands, world_pos, - config.size, + HEX_SIZE, tile, walls, fill_color, diff --git a/src/maze/plugin.rs b/src/maze/plugin.rs index 8ff67cf..d59f509 100644 --- a/src/maze/plugin.rs +++ b/src/maze/plugin.rs @@ -1,6 +1,5 @@ use bevy::{ ecs::{system::RunSystemOnce, world::Command}, - pbr::wireframe::WireframePlugin, prelude::*, }; @@ -13,10 +12,10 @@ 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.insert_resource(AmbientLight { + // brightness: f32::MAX, + // color: Color::WHITE, + // }); } } diff --git a/src/maze/prism.rs b/src/maze/prism.rs index d5b27f9..c6d649c 100644 --- a/src/maze/prism.rs +++ b/src/maze/prism.rs @@ -1,12 +1,15 @@ -use bevy::{pbr::wireframe::Wireframe, prelude::*}; -use std::f32::consts::FRAC_PI_2; +use bevy::{pbr::UvChannel, prelude::*}; +use core::f32; +use hexx::{EdgeDirection, GridEdge, Hex}; +use std::f32::consts::{FRAC_PI_2, FRAC_PI_3, FRAC_PI_6}; use super::{ - resource::{Layout, MazeConfig}, + resource::{Layout, MazeConfig, HEX_SIZE}, tile::Tile, }; pub(super) fn plugin(_app: &mut App) {} +const WALL_SIZE: f32 = 1.0; pub(super) fn setup( mut commands: Commands, @@ -17,11 +20,8 @@ pub(super) fn setup( ) { let radius = config.radius as i32; - let rotation = Quat::from_rotation_x(-FRAC_PI_2); - let material = materials.add(Color::WHITE); - let prism_mesh = generate_hex_prism_mesh(layout.hex_size.x, config.height); - let mesh = meshes.add(prism_mesh); - + let assets = create_base_assets(&mut meshes, &mut materials, &config); + // spawn_single_hex_tile(&mut commands, &assets, &config); commands .spawn(( Name::new("Floor"), @@ -30,33 +30,118 @@ pub(super) fn setup( ..default() }, )) - .with_children(|p| { + .with_children(|mut parent| { for q in -radius..=radius { let r1 = (-radius).max(-q - radius); let r2 = radius.min(-q + radius); for r in r1..=r2 { let tile = Tile::new(q, r); - let pos = tile.to_vec3(&layout); - p.spawn(( - Name::new(format!("Hex {}", &tile.to_string())), - PbrBundle { - mesh: mesh.clone(), - material: material.clone(), - transform: Transform::from_translation(pos).with_rotation(rotation), - ..default() - }, - )); + spawn_single_hex_tile(&mut parent, &tile, &layout, &assets, &config); } } }); } -fn generate_hex_prism_mesh(radius: f32, depth: f32) -> Mesh { +fn spawn_single_hex_tile( + parent: &mut ChildBuilder, + tile: &Tile, + layout: &Res, + assets: &MazeAssets, + config: &Res, +) { + let pos = tile.to_vec3(&layout); + parent + .spawn(( + Name::new(format!("Hex {}", &tile.to_string())), + PbrBundle { + mesh: assets.hex_mesh.clone(), + material: assets.hex_material.clone(), + transform: Transform::from_translation(pos), + ..default() + }, + )) + .with_children(|parent| spawn_walls(parent, assets, config)); +} + +fn spawn_walls(parent: &mut ChildBuilder, asstets: &MazeAssets, config: &Res) { + let y_offset = config.height / 2.; + let z_rotation = Quat::from_rotation_z(-FRAC_PI_2); + + for i in 0..6 { + 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, asstets, 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) + 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/resource.rs index b12ad2b..a3c5326 100644 --- a/src/maze/resource.rs +++ b/src/maze/resource.rs @@ -2,11 +2,12 @@ use bevy::prelude::*; use hexx::{Hex, HexLayout, HexOrientation}; use rand::{thread_rng, Rng}; +pub(crate) const HEX_SIZE: f32 = 6.; + #[derive(Debug, Reflect, Resource)] #[reflect(Resource)] pub struct MazeConfig { pub radius: u32, - pub size: f32, pub height: f32, pub start_pos: Hex, pub end_pos: Hex, @@ -28,8 +29,7 @@ impl Default for MazeConfig { debug!("End pos: ({},{})", end_pos.x, end_pos.y); Self { radius: radius as u32, - size: 1., - height: 15., + height: 20., start_pos, end_pos, } @@ -41,14 +41,10 @@ impl Default for MazeConfig { pub struct Layout(pub HexLayout); impl FromWorld for Layout { - fn from_world(world: &mut World) -> Self { - let size = world - .get_resource::() - .unwrap_or(&MazeConfig::default()) - .size; + fn from_world(_world: &mut World) -> Self { Self(HexLayout { orientation: HexOrientation::Pointy, - hex_size: Vec2::splat(size), + hex_size: Vec2::splat(HEX_SIZE), ..default() }) } From 1aa1bd1c41e45df6a1eac12b56575f45460155d6 Mon Sep 17 00:00:00 2001 From: Kristofers Solo Date: Mon, 4 Nov 2024 20:29:26 +0200 Subject: [PATCH 19/20] chore: bump version to 0.0.4 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 4d6e8ff..6d70049 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "the-labyrinth-of-echoes" authors = ["Kristofers Solo "] -version = "0.0.3" +version = "0.0.4" edition = "2021" [dependencies] From 8f454cb2c6284a0700b95014594a0e582bf631f3 Mon Sep 17 00:00:00 2001 From: Kristofers Solo Date: Mon, 4 Nov 2024 20:37:25 +0200 Subject: [PATCH 20/20] fix: warnings --- Cargo.lock | 2 +- src/lib.rs | 2 +- src/maze/grid.rs | 29 +++++++++++++---------------- src/maze/mod.rs | 2 +- src/maze/prism.rs | 11 +++++------ src/maze/tile.rs | 2 +- 6 files changed, 22 insertions(+), 26 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5c39b4e..b5c5dcc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3918,7 +3918,7 @@ dependencies = [ [[package]] name = "the-labyrinth-of-echoes" -version = "0.0.3" +version = "0.0.4" dependencies = [ "bevy", "bevy-inspector-egui", diff --git a/src/lib.rs b/src/lib.rs index f1e343c..be714f8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -63,7 +63,7 @@ impl Plugin for AppPlugin { #[cfg(feature = "demo")] demo::plugin, #[cfg(not(feature = "demo"))] - maze::plugin::MazePlugin::default(), + maze::plugin::MazePlugin, screens::plugin, theme::plugin, )); diff --git a/src/maze/grid.rs b/src/maze/grid.rs index bc4bc78..babf67b 100644 --- a/src/maze/grid.rs +++ b/src/maze/grid.rs @@ -1,10 +1,7 @@ -use std::usize; - use bevy::{ - color::palettes::css::{BLACK, GREEN, RED, SILVER}, - pbr::wireframe::{Wireframe, WireframeConfig, WireframePlugin}, + color::palettes::css::{BLACK, GREEN, RED}, + pbr::wireframe::{WireframeConfig, WireframePlugin}, prelude::*, - render::{mesh::PrimitiveTopology, render_asset::RenderAssetUsages}, utils::hashbrown::HashMap, }; use bevy_prototype_lyon::{ @@ -31,7 +28,7 @@ pub(super) fn plugin(app: &mut App) { }); } -pub(super) fn spawn_hex_grid(mut commands: Commands, config: Res) { +pub(super) fn _spawn_hex_grid(mut commands: Commands, config: Res) { let radius = config.radius as i32; for q in -radius..=radius { @@ -50,7 +47,7 @@ pub(super) fn spawn_hex_grid(mut commands: Commands, config: Res) { } } -pub(super) fn generate_maze( +pub(super) fn _generate_maze( mut commands: Commands, query: Query<(Entity, &Tile, &Walls)>, config: Res, @@ -61,7 +58,7 @@ pub(super) fn generate_maze( .collect(); let mut rng = thread_rng(); - recursive_maze(&mut tiles, config.start_pos, &mut rng); + _recursive_maze(&mut tiles, config.start_pos, &mut rng); for (entity, tile, walls) in tiles.values() { commands @@ -71,14 +68,14 @@ pub(super) fn generate_maze( } } -fn recursive_maze( +fn _recursive_maze( tiles: &mut HashMap, current_hex: Hex, rng: &mut ThreadRng, ) { { let (_, tile, _) = tiles.get_mut(¤t_hex).unwrap(); - tile.visit(); + tile._visit(); } let mut directions = EdgeDirection::ALL_DIRECTIONS; @@ -88,14 +85,14 @@ fn recursive_maze( let neighbor_hex = current_hex + direction; if let Some((_, neighbor_tile, _)) = tiles.get(&neighbor_hex) { if !neighbor_tile.visited { - remove_wall_between(tiles, current_hex, neighbor_hex, direction); - recursive_maze(tiles, neighbor_hex, rng); + _remove_wall_between(tiles, current_hex, neighbor_hex, direction); + _recursive_maze(tiles, neighbor_hex, rng); } } } } -fn remove_wall_between( +fn _remove_wall_between( tiles: &mut HashMap, current_hex: Hex, neighbor_hex: Hex, @@ -111,7 +108,7 @@ fn remove_wall_between( } } -fn add_hex_tile( +fn _add_hex_tile( commands: &mut Commands, position: Vec3, size: f32, @@ -197,7 +194,7 @@ fn add_hex_tile( } } -pub(super) fn render_maze( +pub(super) fn _render_maze( mut commands: Commands, query: Query<(&Tile, &mut Walls)>, layout: Res, @@ -210,7 +207,7 @@ pub(super) fn render_maze( pos if pos == config.end_pos => RED.into(), _ => Color::srgb(0.8, 0.8, 0.8), }; - add_hex_tile( + _add_hex_tile( &mut commands, world_pos, HEX_SIZE, diff --git a/src/maze/mod.rs b/src/maze/mod.rs index 31264df..c3266d1 100644 --- a/src/maze/mod.rs +++ b/src/maze/mod.rs @@ -7,5 +7,5 @@ pub mod resource; pub mod tile; pub fn spawn_grid(world: &mut World) { - MazePlugin::default().apply(world); + MazePlugin.apply(world); } diff --git a/src/maze/prism.rs b/src/maze/prism.rs index c6d649c..0310a0a 100644 --- a/src/maze/prism.rs +++ b/src/maze/prism.rs @@ -1,7 +1,6 @@ -use bevy::{pbr::UvChannel, prelude::*}; +use bevy::prelude::*; use core::f32; -use hexx::{EdgeDirection, GridEdge, Hex}; -use std::f32::consts::{FRAC_PI_2, FRAC_PI_3, FRAC_PI_6}; +use std::f32::consts::{FRAC_PI_2, FRAC_PI_3}; use super::{ resource::{Layout, MazeConfig, HEX_SIZE}, @@ -30,13 +29,13 @@ pub(super) fn setup( ..default() }, )) - .with_children(|mut parent| { + .with_children(|parent| { for q in -radius..=radius { let r1 = (-radius).max(-q - radius); let r2 = radius.min(-q + radius); for r in r1..=r2 { let tile = Tile::new(q, r); - spawn_single_hex_tile(&mut parent, &tile, &layout, &assets, &config); + spawn_single_hex_tile(parent, &tile, &layout, &assets, &config); } } }); @@ -49,7 +48,7 @@ fn spawn_single_hex_tile( assets: &MazeAssets, config: &Res, ) { - let pos = tile.to_vec3(&layout); + let pos = tile.to_vec3(layout); parent .spawn(( Name::new(format!("Hex {}", &tile.to_string())), diff --git a/src/maze/tile.rs b/src/maze/tile.rs index 0548edc..7c75af7 100644 --- a/src/maze/tile.rs +++ b/src/maze/tile.rs @@ -28,7 +28,7 @@ impl Tile { } } - pub fn visit(&mut self) { + pub fn _visit(&mut self) { self.visited = true; }