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,