From 191b8e2852cfe04808d90351f5ea009b3b65ecaa Mon Sep 17 00:00:00 2001 From: "Earthmark (Daniel Miller)" Date: Sun, 3 Apr 2022 16:06:53 -0700 Subject: [PATCH 1/6] Got some of the labels working. --- src/level/input.rs | 42 ++++-- src/level/loader.rs | 22 +++- src/level/maze_level.rs | 6 +- src/level/maze_ui_renderer.rs | 237 +++++++++++++++------------------- src/level/plugin.rs | 2 +- 5 files changed, 159 insertions(+), 150 deletions(-) diff --git a/src/level/input.rs b/src/level/input.rs index af7961d..03720fd 100644 --- a/src/level/input.rs +++ b/src/level/input.rs @@ -1,40 +1,66 @@ -use bevy::prelude::{Input, KeyCode, Query, Res}; +use bevy::prelude::*; use super::maze_level::*; use super::maze_level::{Axis, Direction}; pub fn level_navigation( - mut query: Query<&mut MazeLevel>, + mut query: Query<(Entity, &mut MazeLevel)>, keys: Res>, + mut position_event: EventWriter>, + mut axis_event: EventWriter, ) { if keys.just_pressed(KeyCode::Q) { - for mut level in query.iter_mut() { + for (entity, mut level) in query.iter_mut() { level.shift_axis(Axis::X, Direction::Negative); + axis_event.send(AxisChanged { + level: entity, + axis: level.axis, + }); } } if keys.just_pressed(KeyCode::E) { - for mut level in query.iter_mut() { + for (entity, mut level) in query.iter_mut() { level.shift_axis(Axis::X, Direction::Positive); + axis_event.send(AxisChanged { + level: entity, + axis: level.axis, + }); } } if keys.just_pressed(KeyCode::W) { - for mut level in query.iter_mut() { + for (entity, mut level) in query.iter_mut() { level.move_pos(Axis::X, Direction::Positive); + position_event.send(PositionChanged:: { + level: entity, + position: level.position, + }); } } if keys.just_pressed(KeyCode::S) { - for mut level in query.iter_mut() { + for (entity, mut level) in query.iter_mut() { level.move_pos(Axis::X, Direction::Negative); + position_event.send(PositionChanged:: { + level: entity, + position: level.position, + }); } } if keys.just_pressed(KeyCode::D) { - for mut level in query.iter_mut() { + for (entity, mut level) in query.iter_mut() { level.move_pos(Axis::Y, Direction::Positive); + position_event.send(PositionChanged:: { + level: entity, + position: level.position, + }); } } if keys.just_pressed(KeyCode::A) { - for mut level in query.iter_mut() { + for (entity, mut level) in query.iter_mut() { level.move_pos(Axis::Y, Direction::Negative); + position_event.send(PositionChanged:: { + level: entity, + position: level.position, + }); } } } diff --git a/src/level/loader.rs b/src/level/loader.rs index 1b4d8c1..4c8e427 100644 --- a/src/level/loader.rs +++ b/src/level/loader.rs @@ -1,7 +1,10 @@ use bevy::prelude::*; use rand::prelude::*; -use super::MazeLevel; +use super::{ + maze_level::{AxisChanged, PositionChanged}, + MazeLevel, +}; #[derive(Clone, Debug)] pub struct LoadLevel { @@ -58,3 +61,20 @@ pub fn level_load_system(mut commands: Commands, mut events: EventReader( + query: Query<(Entity, &MazeLevel), Added>>, + mut position_changed: EventWriter>, + mut axis_changed: EventWriter, +) { + for (level, maze) in query.iter() { + position_changed.send(PositionChanged:: { + level, + position: maze.position, + }); + axis_changed.send(AxisChanged { + level, + axis: maze.axis, + }); + } +} diff --git a/src/level/maze_level.rs b/src/level/maze_level.rs index 51295bc..f9936e5 100644 --- a/src/level/maze_level.rs +++ b/src/level/maze_level.rs @@ -4,21 +4,19 @@ use bevy::prelude::*; #[derive(Component)] pub struct MazeLevel { maze: maze::Maze, - position: [u8; DIMS], - axis: [u8; 2], + pub position: [u8; DIMS], + pub axis: [u8; 2], } #[derive(Clone, Debug)] pub struct AxisChanged { pub level: Entity, - pub old_axis: [u8; 2], pub axis: [u8; 2], } #[derive(Clone, Debug)] pub struct PositionChanged { pub level: Entity, - pub old_position: [u8; DIMS], pub position: [u8; DIMS], } diff --git a/src/level/maze_ui_renderer.rs b/src/level/maze_ui_renderer.rs index ff2b81b..dbb1db4 100644 --- a/src/level/maze_ui_renderer.rs +++ b/src/level/maze_ui_renderer.rs @@ -32,10 +32,10 @@ use bevy::prelude::*; pub fn spawn_ui( mut c: Commands, - query: Query<&MazeLevel, Added>>, + query: Query<(Entity, &MazeLevel), Added>>, assets: Res, ) { - for _maze in query.iter() { + for (level, maze) in query.iter() { info!("Added maze"); let style = TextStyle { font: assets.load("fonts\\UnicaOne-Regular.ttf"), @@ -43,23 +43,27 @@ pub fn spawn_ui( ..Default::default() }; - let label = |s: &'static str| TextBundle { - text: Text::with_section(s, style.clone(), Default::default()), + let label = |s: &str| TextBundle { + text: Text::with_section( + s, + style.clone(), + TextAlignment { + vertical: VerticalAlign::Center, + horizontal: HorizontalAlign::Center, + }, + ), style: Style { - flex_grow: 1.0, + size: Size::new(Val::Auto, Val::Px(50.0)), ..Default::default() }, ..Default::default() }; - fn row() -> NodeBundle { + fn column() -> NodeBundle { NodeBundle { style: Style { - flex_direction: FlexDirection::Row, - justify_content: JustifyContent::SpaceBetween, - align_content: AlignContent::Stretch, - position: Rect::all(Val::Auto), - margin: Rect::all(Val::Auto), + flex_direction: FlexDirection::Column, + justify_content: JustifyContent::SpaceEvenly, ..Default::default() }, color: Color::NONE.into(), @@ -67,124 +71,109 @@ pub fn spawn_ui( } } - fn column() -> NodeBundle { - NodeBundle { - style: Style { - flex_direction: FlexDirection::ColumnReverse, - align_content: AlignContent::Stretch, - position: Rect::all(Val::Auto), - margin: Rect::all(Val::Auto), - ..Default::default() - }, - color: Color::NONE.into(), - ..Default::default() + let dimension_col = |dimension: usize| { + move |c: &mut ChildBuilder| { + c.spawn_bundle(label("S")).insert(MazeAxisLabel:: { + level, + axis: Axis::X, + dim: dimension as u8, + }); + c.spawn_bundle(label("A")).insert(MazeAxisLabel:: { + level, + axis: Axis::Y, + dim: dimension as u8, + }); + c.spawn_bundle(label("#")) + .insert(MazePositionLabel:: { level, dimension }); + c.spawn_bundle(label("W")).insert(MazeAxisLabel:: { + level, + axis: Axis::X, + dim: dimension as u8, + }); + c.spawn_bundle(label("D")).insert(MazeAxisLabel:: { + level, + axis: Axis::Y, + dim: dimension as u8, + }); } - } + }; c.spawn_bundle(NodeBundle { style: Style { - flex_direction: FlexDirection::ColumnReverse, + flex_direction: FlexDirection::Column, ..Default::default() }, color: Color::NONE.into(), ..Default::default() }) .with_children(|c| { - c.spawn_bundle(column()).with_children(|c| { - // upper - c.spawn_bundle(row()).with_children(|c| { - c.spawn_bundle(label("-")); - c.spawn_bundle(label("w")); - c.spawn_bundle(label("a")); - c.spawn_bundle(label("s")); - c.spawn_bundle(label("-")); - }); - - // middle - c.spawn_bundle(row()).with_children(|c| { - c.spawn_bundle(label("[")); - c.spawn_bundle(label("1,")); - c.spawn_bundle(label("2,")); - c.spawn_bundle(label("3,")); - c.spawn_bundle(label("]")); - }); - - // lower - c.spawn_bundle(row()).with_children(|c| { - c.spawn_bundle(label("-")); - c.spawn_bundle(label("z")); - c.spawn_bundle(label("x")); - c.spawn_bundle(label("c")); - c.spawn_bundle(label("-")); - }); - }); - - // Axis Shift Controls - c.spawn_bundle(row()).with_children(|commands| { - commands.spawn_bundle(TextBundle { + c.spawn_bundle(NodeBundle { + style: Style { + justify_content: JustifyContent::SpaceEvenly, + flex_direction: FlexDirection::Row, + align_items: AlignItems::Center, + ..Default::default() + }, + color: Color::NONE.into(), + ..Default::default() + }) + .with_children(|c| { + // Axis Shift Controls + c.spawn_bundle(TextBundle { + text: Text::with_section( + "ZX", + style.clone(), + TextAlignment { + vertical: VerticalAlign::Center, + horizontal: HorizontalAlign::Center, + }, + ), style: Style { - ..Default::default() - }, - text: Text { - sections: vec![ - TextSection { - value: "Z".into(), - style: style.clone(), - }, - TextSection { - value: "<".into(), - style: style.clone(), - }, - TextSection { - value: "W/S".into(), - style: style.clone(), - }, - TextSection { - value: ">".into(), - style: style.clone(), - }, - TextSection { - value: "X".into(), - style: style.clone(), - }, - ], + margin: Rect { + right: Val::Px(5.0), + ..Default::default() + }, ..Default::default() }, ..Default::default() }); - - commands.spawn_bundle(TextBundle { + c.spawn_bundle(TextBundle { + text: Text::with_section( + "QE", + style.clone(), + TextAlignment { + vertical: VerticalAlign::Center, + horizontal: HorizontalAlign::Center, + }, + ), style: Style { - ..Default::default() - }, - text: Text { - sections: vec![ - TextSection { - value: "Q".into(), - style: style.clone(), - }, - TextSection { - value: "<".into(), - style: style.clone(), - }, - TextSection { - value: "D/A".into(), - style: style.clone(), - }, - TextSection { - value: ">".into(), - style: style.clone(), - }, - TextSection { - value: "E".into(), - style: style.clone(), - }, - ], + margin: Rect { + left: Val::Px(5.0), + ..Default::default() + }, ..Default::default() }, ..Default::default() }); }); + + c.spawn_bundle(NodeBundle { + style: Style { + flex_direction: FlexDirection::Row, + align_items: AlignItems::Center, + justify_content: JustifyContent::FlexStart, + ..Default::default() + }, + color: Color::NONE.into(), + ..Default::default() + }) + .with_children(|c| { + c.spawn_bundle(label("[")); + for i in 0..DIMS { + c.spawn_bundle(column()).with_children(dimension_col(i)); + } + c.spawn_bundle(label("]")); + }); }); } } @@ -192,30 +181,6 @@ pub fn spawn_ui( #[derive(Component)] struct MazeUiRoot; -// A component used to mark something to be visible only if the specific dimension is selected. -#[derive(Component)] -pub struct MazeSelectedAxisVisibilityHider { - // The maze level this is bound to. - level: Entity, - // The dimension that this listener is watching for. - dim: u8, - // If true, the object will be visible while the axis is selected. If false, the effect is negated. - visible_if_selected: bool, -} - -pub fn maze_selected_axis_visibility_hider_updater( - mut query: Query<(&MazeSelectedAxisVisibilityHider, &mut Visibility)>, - mut axis_changed: EventReader, -) { - for changed in axis_changed.iter() { - for (label, mut vis) in query.iter_mut() { - if label.level == changed.level { - vis.is_visible = changed.axis.contains(&label.dim) == label.visible_if_selected; - } - } - } -} - #[derive(Component)] pub struct MazeAxisLabel { level: Entity, @@ -243,7 +208,7 @@ pub fn maze_axis_label_update_listener( #[derive(Component)] pub struct MazePositionLabel { level: Entity, - text_section_to_dim: [usize; DIMS], + dimension: usize, } pub fn maze_position_label_update_listener( @@ -253,9 +218,9 @@ pub fn maze_position_label_update_listener( for changed in position_changed.iter() { for (label, mut text) in query.iter_mut() { if label.level == changed.level { - for (section_index, dimension) in label.text_section_to_dim.iter().enumerate() { - if let Some(section) = text.sections.get_mut(section_index) { - section.value = format!("{}", changed.position[*dimension]); + if let Some(section) = text.sections.first_mut() { + if let Some(target) = changed.position.get(label.dimension) { + section.value = format!("{}", target); } } } diff --git a/src/level/plugin.rs b/src/level/plugin.rs index 124a69f..7f00378 100644 --- a/src/level/plugin.rs +++ b/src/level/plugin.rs @@ -24,9 +24,9 @@ impl Plugin for SingleDimMazePlugin { .add_event::>() .add_system(maze_renderer::spawn_ui::) .add_system(maze_ui_renderer::spawn_ui::) - .add_system(maze_ui_renderer::maze_selected_axis_visibility_hider_updater) .add_system(maze_ui_renderer::maze_axis_label_update_listener::) .add_system(maze_ui_renderer::maze_position_label_update_listener::) + .add_system(loader::initial_events_on_load::) .add_system(maze_renderer::update_maze_offset::) .add_system(input::level_navigation::); } From 2050b0fd932aa38255e691c58de83c7b9ab00d34 Mon Sep 17 00:00:00 2001 From: "Earthmark (Daniel Miller)" Date: Mon, 11 Apr 2022 22:55:20 -0700 Subject: [PATCH 2/6] Swapped to resource based mazes, this may take a performance hit. --- src/level/input.rs | 68 ++++----- src/level/loader.rs | 52 +++---- src/level/maze_level.rs | 124 +++++++++------ src/level/maze_renderer.rs | 60 ++++---- src/level/maze_ui_renderer.rs | 273 ++++++++++++++++------------------ src/level/plugin.rs | 37 ++--- src/main.rs | 8 + 7 files changed, 317 insertions(+), 305 deletions(-) diff --git a/src/level/input.rs b/src/level/input.rs index 03720fd..885c375 100644 --- a/src/level/input.rs +++ b/src/level/input.rs @@ -3,63 +3,51 @@ use bevy::prelude::*; use super::maze_level::*; use super::maze_level::{Axis, Direction}; -pub fn level_navigation( - mut query: Query<(Entity, &mut MazeLevel)>, +pub fn level_navigation( + level: Option>, keys: Res>, - mut position_event: EventWriter>, + mut position_event: EventWriter, mut axis_event: EventWriter, ) { - if keys.just_pressed(KeyCode::Q) { - for (entity, mut level) in query.iter_mut() { + if let Some(mut level) = level { + if keys.just_pressed(KeyCode::Q) { level.shift_axis(Axis::X, Direction::Negative); - axis_event.send(AxisChanged { - level: entity, - axis: level.axis, - }); + axis_event.send(AxisChanged { axis: level.axis() }); } - } - if keys.just_pressed(KeyCode::E) { - for (entity, mut level) in query.iter_mut() { + if keys.just_pressed(KeyCode::E) { level.shift_axis(Axis::X, Direction::Positive); - axis_event.send(AxisChanged { - level: entity, - axis: level.axis, - }); + axis_event.send(AxisChanged { axis: level.axis() }); } - } - if keys.just_pressed(KeyCode::W) { - for (entity, mut level) in query.iter_mut() { + if keys.just_pressed(KeyCode::Z) { + level.shift_axis(Axis::Y, Direction::Negative); + axis_event.send(AxisChanged { axis: level.axis() }); + } + if keys.just_pressed(KeyCode::X) { + level.shift_axis(Axis::Y, Direction::Positive); + axis_event.send(AxisChanged { axis: level.axis() }); + } + if keys.just_pressed(KeyCode::W) { level.move_pos(Axis::X, Direction::Positive); - position_event.send(PositionChanged:: { - level: entity, - position: level.position, + position_event.send(PositionChanged { + position: level.pos(), }); } - } - if keys.just_pressed(KeyCode::S) { - for (entity, mut level) in query.iter_mut() { + if keys.just_pressed(KeyCode::S) { level.move_pos(Axis::X, Direction::Negative); - position_event.send(PositionChanged:: { - level: entity, - position: level.position, + position_event.send(PositionChanged { + position: level.pos(), }); } - } - if keys.just_pressed(KeyCode::D) { - for (entity, mut level) in query.iter_mut() { + if keys.just_pressed(KeyCode::D) { level.move_pos(Axis::Y, Direction::Positive); - position_event.send(PositionChanged:: { - level: entity, - position: level.position, + position_event.send(PositionChanged { + position: level.pos(), }); } - } - if keys.just_pressed(KeyCode::A) { - for (entity, mut level) in query.iter_mut() { + if keys.just_pressed(KeyCode::A) { level.move_pos(Axis::Y, Direction::Negative); - position_event.send(PositionChanged:: { - level: entity, - position: level.position, + position_event.send(PositionChanged { + position: level.pos(), }); } } diff --git a/src/level/loader.rs b/src/level/loader.rs index 4c8e427..b71d949 100644 --- a/src/level/loader.rs +++ b/src/level/loader.rs @@ -1,3 +1,4 @@ +use crate::AppState; use bevy::prelude::*; use rand::prelude::*; @@ -37,44 +38,33 @@ impl Default for LoadLevel { } } -pub fn level_load_system(mut commands: Commands, mut events: EventReader) { +pub fn level_load_system( + mut c: Commands, + mut events: EventReader, + mut app_state: ResMut>, +) { for level_loader in events.iter() { let mut rng = match level_loader.rng_source { RngSource::Seeded(seed) => StdRng::seed_from_u64(seed), }; - match level_loader.dimensions { - DimensionLength::Two(lengths) => { - commands.spawn().insert(MazeLevel::new(&lengths, &mut rng)) - } - DimensionLength::Three(lengths) => { - commands.spawn().insert(MazeLevel::new(&lengths, &mut rng)) - } - DimensionLength::Four(lengths) => { - commands.spawn().insert(MazeLevel::new(&lengths, &mut rng)) - } - DimensionLength::Five(lengths) => { - commands.spawn().insert(MazeLevel::new(&lengths, &mut rng)) - } - DimensionLength::Six(lengths) => { - commands.spawn().insert(MazeLevel::new(&lengths, &mut rng)) - } - }; + c.insert_resource(match level_loader.dimensions { + DimensionLength::Two(lengths) => MazeLevel::new(&lengths, &mut rng), + DimensionLength::Three(lengths) => MazeLevel::new(&lengths, &mut rng), + DimensionLength::Four(lengths) => MazeLevel::new(&lengths, &mut rng), + DimensionLength::Five(lengths) => MazeLevel::new(&lengths, &mut rng), + DimensionLength::Six(lengths) => MazeLevel::new(&lengths, &mut rng), + }); + app_state.push(AppState::InMaze).unwrap(); } } -pub fn initial_events_on_load( - query: Query<(Entity, &MazeLevel), Added>>, - mut position_changed: EventWriter>, +pub fn initial_events_on_load( + maze: Res, + mut position_changed: EventWriter, mut axis_changed: EventWriter, ) { - for (level, maze) in query.iter() { - position_changed.send(PositionChanged:: { - level, - position: maze.position, - }); - axis_changed.send(AxisChanged { - level, - axis: maze.axis, - }); - } + position_changed.send(PositionChanged { + position: maze.pos().into(), + }); + axis_changed.send(AxisChanged { axis: maze.axis() }); } diff --git a/src/level/maze_level.rs b/src/level/maze_level.rs index f9936e5..75c5594 100644 --- a/src/level/maze_level.rs +++ b/src/level/maze_level.rs @@ -1,23 +1,23 @@ +use std::ops::{Deref, DerefMut}; + +use bevy::{ecs::system::Resource, prelude::*}; + use crate::maze; -use bevy::prelude::*; -#[derive(Component)] -pub struct MazeLevel { +struct MazeImpl { maze: maze::Maze, - pub position: [u8; DIMS], - pub axis: [u8; 2], + position: [u8; DIMS], + axis: [u8; 2], } #[derive(Clone, Debug)] pub struct AxisChanged { - pub level: Entity, pub axis: [u8; 2], } #[derive(Clone, Debug)] -pub struct PositionChanged { - pub level: Entity, - pub position: [u8; DIMS], +pub struct PositionChanged { + pub position: [u8; 2], } #[derive(PartialEq, Eq, Clone, Copy)] @@ -63,7 +63,7 @@ impl Direction { } } -impl Default for MazeLevel { +impl Default for MazeImpl { fn default() -> Self { Self { maze: Default::default(), @@ -73,20 +73,17 @@ impl Default for MazeLevel { } } -impl MazeLevel { +impl MazeImpl { pub fn new(lengths: &[u8; DIMS], rng: &mut impl rand::Rng) -> Self { Self { maze: crate::maze::Maze::new(lengths, rng), - ..Default::default() + axis: [0, 1], + position: [0; DIMS], } } } -impl MazeView for MazeLevel { - fn dims(&self) -> &[u8] { - self.maze.lengths() - } - +impl MazeView for MazeImpl { fn axis(&self) -> [u8; 2] { self.axis } @@ -111,8 +108,15 @@ impl MazeView for MazeLevel { *axis.get_mut(&mut self.axis) = dest; } + fn dims_limit(&self) -> &[u8] { + self.maze.lengths() + } + + fn dims(&self) -> &[u8] { + &self.position + } + // assume dim_x and dim_y are both together. - #[inline] fn pos_limit(&self) -> [u8; 2] { [ self.maze.lengths()[self.axis[0] as usize], @@ -160,12 +164,12 @@ impl MazeView for MazeLevel { } } -pub trait MazeView { - fn dims(&self) -> &[u8]; - +pub trait MazeView: Resource { fn axis(&self) -> [u8; 2]; fn shift_axis(&mut self, axis: Axis, dir: Direction); + fn dims_limit(&self) -> &[u8]; + fn dims(&self) -> &[u8]; fn pos_limit(&self) -> [u8; 2]; fn pos(&self) -> [u8; 2]; fn move_pos(&mut self, axis: Axis, dir: Direction); @@ -173,26 +177,60 @@ pub trait MazeView { fn should_make_wall(&self, position: [u8; 2], axis: Axis) -> bool; } -pub fn iter_walls( - maze: &impl MazeView, -) -> impl std::iter::Iterator + '_ { - let [length_x, length_y] = maze.pos_limit(); - - (0..length_x) - .flat_map(move |x| (0..length_y).map(move |y| [x, y])) - .flat_map(move |cursor| { - [ - if maze.should_make_wall(cursor, Axis::X) { - Some((cursor, [cursor[0] + 1, cursor[1]])) - } else { - None - }, - if maze.should_make_wall(cursor, Axis::Y) { - Some((cursor, [cursor[0], cursor[1] + 1])) - } else { - None - }, - ] - }) - .flatten() +pub struct MazeLevel { + inner: Box, +} + +impl Default for MazeLevel { + fn default() -> Self { + Self { + inner: Box::new(MazeImpl::<2>::default()), + } + } +} + +impl MazeLevel { + pub fn new(lengths: &[u8; DIMS], rng: &mut impl rand::Rng) -> Self { + Self { + inner: Box::new(MazeImpl::new(lengths, rng)), + } + } +} + +impl Deref for MazeLevel { + type Target = dyn MazeView; + + fn deref(&self) -> &Self::Target { + self.inner.as_ref() + } +} + +impl DerefMut for MazeLevel { + fn deref_mut(&mut self) -> &mut Self::Target { + self.inner.as_mut() + } +} + +impl MazeLevel { + pub fn iter_walls(&self) -> impl std::iter::Iterator + '_ { + let [length_x, length_y] = self.pos_limit(); + + (0..length_x) + .flat_map(move |x| (0..length_y).map(move |y| [x, y])) + .flat_map(move |cursor| { + [ + if self.should_make_wall(cursor, Axis::X) { + Some((cursor, [cursor[0] + 1, cursor[1]])) + } else { + None + }, + if self.should_make_wall(cursor, Axis::Y) { + Some((cursor, [cursor[0], cursor[1] + 1])) + } else { + None + }, + ] + }) + .flatten() + } } diff --git a/src/level/maze_renderer.rs b/src/level/maze_renderer.rs index 795c8bd..a365c00 100644 --- a/src/level/maze_renderer.rs +++ b/src/level/maze_renderer.rs @@ -3,25 +3,21 @@ use std::f32::consts::PI; use super::maze_level::*; use bevy::prelude::*; -pub fn spawn_ui( +pub fn spawn_maze_root( mut commands: Commands, - query: Query<(Entity, &MazeLevel), Added>>, mut meshes: ResMut>, mut materials: ResMut>, ) { - for (entity, _maze) in query.iter() { - commands.spawn_bundle(MazeRendererBundle { - renderer: MazeRenderer { - level: entity, - last_dims: [0, 0], - joint: meshes.add(Mesh::from(shape::Box::new(0.2, 1.0, 0.2))), - wall: meshes.add(Mesh::from(shape::Box::new(0.1, 0.6, 1.0))), - material: materials.add(Color::rgb(0.8, 0.7, 0.6).into()), - }, - transform: Default::default(), - global_transform: Default::default(), - }); - } + commands.spawn_bundle(MazeRendererBundle { + renderer: MazeRenderer { + last_axis: [0, 0], + joint: meshes.add(Mesh::from(shape::Box::new(0.2, 1.0, 0.2))), + wall: meshes.add(Mesh::from(shape::Box::new(0.1, 0.6, 1.0))), + material: materials.add(Color::rgb(0.8, 0.7, 0.6).into()), + }, + transform: Default::default(), + global_transform: Default::default(), + }); } #[derive(Bundle)] @@ -33,8 +29,7 @@ pub struct MazeRendererBundle { #[derive(Component)] pub struct MazeRenderer { - level: Entity, - last_dims: [u8; 2], + last_axis: [u8; 2], joint: Handle, wall: Handle, material: Handle, @@ -60,29 +55,38 @@ impl MazeRenderer { } } -pub fn update_maze_offset( +pub fn update_maze_offset( + level: Res, mut maze_query: Query<(&MazeRenderer, &mut Transform)>, - level_query: Query<&MazeLevel, Changed>>, + mut position_changed: EventReader, + mut axis_changed: EventReader, ) { - for (maze, mut trs) in maze_query.iter_mut() { - if let Ok(level) = level_query.get(maze.level) { + for _ in position_changed.iter() { + for (_, mut trs) in maze_query.iter_mut() { + let p = level.pos(); + trs.translation = Vec3::new(-(p[0] as f32), 0.0, -(p[1] as f32)) + } + } + for _ in axis_changed.iter() { + for (_, mut trs) in maze_query.iter_mut() { let p = level.pos(); trs.translation = Vec3::new(-(p[0] as f32), 0.0, -(p[1] as f32)) } } } -pub fn maze_level_renderer( +pub fn maze_level_renderer( + level: Res, mut commands: Commands, mut render_query: Query<(Entity, &mut MazeRenderer)>, - level_query: Query<&MazeLevel, Changed>>, + mut axis_changed: EventReader, ) { - for (entity, mut assets) in render_query.iter_mut() { - if let Ok(level) = level_query.get(assets.level) { - if assets.last_dims == level.pos() { + for _ in axis_changed.iter() { + for (entity, mut assets) in render_query.iter_mut() { + if assets.last_axis == level.axis() { continue; } - assets.last_dims = level.pos(); + assets.last_axis = level.axis(); let mut entity = commands.entity(entity); entity.despawn_descendants(); @@ -131,7 +135,7 @@ pub fn maze_level_renderer( } // walls - for (v1, v2) in iter_walls(level) { + for (v1, v2) in level.iter_walls() { let p1 = Vec3::new(v1[0] as f32, 0.0, v1[1] as f32); let p2 = Vec3::new(v2[0] as f32, 0.0, v2[1] as f32); let rotation = if v1[0] != v2[0] { diff --git a/src/level/maze_ui_renderer.rs b/src/level/maze_ui_renderer.rs index dbb1db4..6789830 100644 --- a/src/level/maze_ui_renderer.rs +++ b/src/level/maze_ui_renderer.rs @@ -1,4 +1,4 @@ -use super::maze_level::{Axis, *}; +use super::maze_level::*; use bevy::prelude::*; // Current dimension status text layout: @@ -30,198 +30,187 @@ use bevy::prelude::*; // (false, None) -> Greyed out circle, // } -pub fn spawn_ui( - mut c: Commands, - query: Query<(Entity, &MazeLevel), Added>>, - assets: Res, -) { - for (level, maze) in query.iter() { - info!("Added maze"); - let style = TextStyle { - font: assets.load("fonts\\UnicaOne-Regular.ttf"), - font_size: 50.0, +pub fn spawn_ui(mut c: Commands, maze: Res, assets: Res) { + let style = TextStyle { + font: assets.load("fonts\\UnicaOne-Regular.ttf"), + font_size: 50.0, + ..Default::default() + }; + + let label = |s: &str| TextBundle { + text: Text::with_section( + s, + style.clone(), + TextAlignment { + vertical: VerticalAlign::Center, + horizontal: HorizontalAlign::Center, + }, + ), + style: Style { + size: Size::new(Val::Auto, Val::Px(50.0)), ..Default::default() - }; - - let label = |s: &str| TextBundle { - text: Text::with_section( - s, - style.clone(), - TextAlignment { - vertical: VerticalAlign::Center, - horizontal: HorizontalAlign::Center, - }, - ), + }, + ..Default::default() + }; + + fn column() -> NodeBundle { + NodeBundle { style: Style { - size: Size::new(Val::Auto, Val::Px(50.0)), + flex_direction: FlexDirection::Column, + justify_content: JustifyContent::SpaceEvenly, ..Default::default() }, + color: Color::NONE.into(), ..Default::default() - }; - - fn column() -> NodeBundle { - NodeBundle { - style: Style { - flex_direction: FlexDirection::Column, - justify_content: JustifyContent::SpaceEvenly, - ..Default::default() - }, - color: Color::NONE.into(), - ..Default::default() - } } + } - let dimension_col = |dimension: usize| { - move |c: &mut ChildBuilder| { - c.spawn_bundle(label("S")).insert(MazeAxisLabel:: { - level, - axis: Axis::X, - dim: dimension as u8, - }); - c.spawn_bundle(label("A")).insert(MazeAxisLabel:: { - level, - axis: Axis::Y, - dim: dimension as u8, - }); - c.spawn_bundle(label("#")) - .insert(MazePositionLabel:: { level, dimension }); - c.spawn_bundle(label("W")).insert(MazeAxisLabel:: { - level, - axis: Axis::X, - dim: dimension as u8, - }); - c.spawn_bundle(label("D")).insert(MazeAxisLabel:: { - level, - axis: Axis::Y, - dim: dimension as u8, - }); - } - }; + let dimension_col = |dimension: usize| { + move |c: &mut ChildBuilder| { + c.spawn_bundle(label("-")).insert(MazeAxisLabel { + dim: dimension as u8, + dir: AxisDirection::Positive, + }); + c.spawn_bundle(label("#")) + .insert(MazePositionLabel { dimension }); + c.spawn_bundle(label("-")).insert(MazeAxisLabel { + dim: dimension as u8, + dir: AxisDirection::Negative, + }); + } + }; + c.spawn_bundle(NodeBundle { + style: Style { + flex_direction: FlexDirection::Column, + ..Default::default() + }, + color: Color::NONE.into(), + ..Default::default() + }) + .with_children(|c| { c.spawn_bundle(NodeBundle { style: Style { - flex_direction: FlexDirection::Column, + justify_content: JustifyContent::SpaceEvenly, + flex_direction: FlexDirection::Row, + align_items: AlignItems::Center, ..Default::default() }, color: Color::NONE.into(), ..Default::default() }) .with_children(|c| { - c.spawn_bundle(NodeBundle { + // Axis Shift Controls + c.spawn_bundle(TextBundle { + text: Text::with_section( + "ZX", + style.clone(), + TextAlignment { + vertical: VerticalAlign::Center, + horizontal: HorizontalAlign::Center, + }, + ), style: Style { - justify_content: JustifyContent::SpaceEvenly, - flex_direction: FlexDirection::Row, - align_items: AlignItems::Center, + margin: Rect { + right: Val::Px(5.0), + ..Default::default() + }, ..Default::default() }, - color: Color::NONE.into(), ..Default::default() - }) - .with_children(|c| { - // Axis Shift Controls - c.spawn_bundle(TextBundle { - text: Text::with_section( - "ZX", - style.clone(), - TextAlignment { - vertical: VerticalAlign::Center, - horizontal: HorizontalAlign::Center, - }, - ), - style: Style { - margin: Rect { - right: Val::Px(5.0), - ..Default::default() - }, - ..Default::default() + }); + c.spawn_bundle(TextBundle { + text: Text::with_section( + "QE", + style.clone(), + TextAlignment { + vertical: VerticalAlign::Center, + horizontal: HorizontalAlign::Center, }, - ..Default::default() - }); - c.spawn_bundle(TextBundle { - text: Text::with_section( - "QE", - style.clone(), - TextAlignment { - vertical: VerticalAlign::Center, - horizontal: HorizontalAlign::Center, - }, - ), - style: Style { - margin: Rect { - left: Val::Px(5.0), - ..Default::default() - }, + ), + style: Style { + margin: Rect { + left: Val::Px(5.0), ..Default::default() }, ..Default::default() - }); - }); - - c.spawn_bundle(NodeBundle { - style: Style { - flex_direction: FlexDirection::Row, - align_items: AlignItems::Center, - justify_content: JustifyContent::FlexStart, - ..Default::default() }, - color: Color::NONE.into(), ..Default::default() - }) - .with_children(|c| { - c.spawn_bundle(label("[")); - for i in 0..DIMS { - c.spawn_bundle(column()).with_children(dimension_col(i)); - } - c.spawn_bundle(label("]")); }); }); - } + + c.spawn_bundle(NodeBundle { + style: Style { + flex_direction: FlexDirection::Row, + align_items: AlignItems::Center, + justify_content: JustifyContent::FlexStart, + ..Default::default() + }, + color: Color::NONE.into(), + ..Default::default() + }) + .with_children(|c| { + c.spawn_bundle(label("[")); + for (i, _) in maze.dims_limit().iter().enumerate() { + c.spawn_bundle(column()).with_children(dimension_col(i)); + } + c.spawn_bundle(label("]")); + }); + }); } #[derive(Component)] struct MazeUiRoot; +enum AxisDirection { + Positive, + Negative, +} + #[derive(Component)] -pub struct MazeAxisLabel { - level: Entity, +pub struct MazeAxisLabel { dim: u8, - axis: Axis, + dir: AxisDirection, } -pub fn maze_axis_label_update_listener( - mut query: Query<(&MazeAxisLabel, &mut Visibility)>, +pub fn maze_axis_label_update_listener( + mut query: Query<(&MazeAxisLabel, &mut Text)>, mut axis_changed: EventReader, ) { for changed in axis_changed.iter() { - for (label, mut vis) in query.iter_mut() { - if label.level == changed.level { - vis.is_visible = *label.axis.get(&changed.axis) == label.dim; + for (label, mut text) in query.iter_mut() { + if changed.axis[0] == label.dim { + text.sections[0].value = match label.dir { + AxisDirection::Positive => "S".into(), + AxisDirection::Negative => "W".into(), + }; + } else if changed.axis[1] == label.dim { + text.sections[0].value = match label.dir { + AxisDirection::Positive => "A".into(), + AxisDirection::Negative => "D".into(), + }; + } else { + text.sections[0].value = "".into(); } } } } -// Current position status text -// Position: [X, Y, Z, W, Q] -// Goal: [3, 4, 12, 3, 23] - #[derive(Component)] -pub struct MazePositionLabel { - level: Entity, +pub struct MazePositionLabel { dimension: usize, } -pub fn maze_position_label_update_listener( - mut query: Query<(&MazePositionLabel, &mut Text)>, - mut position_changed: EventReader>, +pub fn maze_position_label_update_listener( + maze: Res, + mut query: Query<(&MazePositionLabel, &mut Text)>, + mut position_changed: EventReader, ) { - for changed in position_changed.iter() { + for _ in position_changed.iter() { for (label, mut text) in query.iter_mut() { - if label.level == changed.level { - if let Some(section) = text.sections.first_mut() { - if let Some(target) = changed.position.get(label.dimension) { - section.value = format!("{}", target); - } + if let Some(section) = text.sections.first_mut() { + if let Some(target) = maze.dims().get(label.dimension) { + section.value = format!("{}", target); } } } diff --git a/src/level/plugin.rs b/src/level/plugin.rs index 7f00378..df57991 100644 --- a/src/level/plugin.rs +++ b/src/level/plugin.rs @@ -1,4 +1,5 @@ use super::*; +use crate::AppState; use bevy::prelude::*; pub struct LevelPlugin; @@ -8,26 +9,20 @@ impl Plugin for LevelPlugin { app.add_system(loader::level_load_system) .add_event::() .add_event::() - .add_plugin(SingleDimMazePlugin::<2>) - .add_plugin(SingleDimMazePlugin::<3>) - .add_plugin(SingleDimMazePlugin::<4>) - .add_plugin(SingleDimMazePlugin::<5>) - .add_plugin(SingleDimMazePlugin::<6>); - } -} - -pub struct SingleDimMazePlugin; - -impl Plugin for SingleDimMazePlugin { - fn build(&self, app: &mut App) { - app.add_system(maze_renderer::maze_level_renderer::) - .add_event::>() - .add_system(maze_renderer::spawn_ui::) - .add_system(maze_ui_renderer::spawn_ui::) - .add_system(maze_ui_renderer::maze_axis_label_update_listener::) - .add_system(maze_ui_renderer::maze_position_label_update_listener::) - .add_system(loader::initial_events_on_load::) - .add_system(maze_renderer::update_maze_offset::) - .add_system(input::level_navigation::); + .add_event::() + .add_system_set( + SystemSet::on_enter(AppState::InMaze) + .with_system(maze_renderer::spawn_maze_root) + .with_system(maze_ui_renderer::spawn_ui) + .with_system(loader::initial_events_on_load), + ) + .add_system_set( + SystemSet::on_update(AppState::InMaze) + .with_system(maze_ui_renderer::maze_axis_label_update_listener) + .with_system(maze_ui_renderer::maze_position_label_update_listener) + .with_system(maze_renderer::maze_level_renderer) + .with_system(maze_renderer::update_maze_offset) + .with_system(input::level_navigation), + ); } } diff --git a/src/main.rs b/src/main.rs index 4db8439..e522f16 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,8 +5,16 @@ mod maze; use bevy::prelude::*; +#[derive(Debug, Clone, Eq, PartialEq, Hash)] +pub enum AppState { + MainMenu, + InMaze, + Paused, +} + fn main() { App::new() + .add_state(AppState::MainMenu) .add_plugins(DefaultPlugins) .add_plugin(level::LevelPlugin) .add_startup_system(setup) From 66a6778d8a8446943bcda40cf0cf97c0d68a3efb Mon Sep 17 00:00:00 2001 From: "Earthmark (Daniel Miller)" Date: Sat, 16 Apr 2022 09:57:49 -0700 Subject: [PATCH 3/6] Cleaned up warnings, and updated to 0.7. --- Cargo.toml | 2 +- src/level/maze_level.rs | 4 +--- src/main.rs | 18 +++++------------- 3 files changed, 7 insertions(+), 17 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 69d972e..af59c92 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,7 +5,7 @@ name = "nothing-moves" version = "0.1.0" [dependencies] -bevy = "0.6" +bevy = "0.7" rand = "0.8" # Enable only a small amount of optimization in debug mode diff --git a/src/level/maze_level.rs b/src/level/maze_level.rs index 75c5594..f403d09 100644 --- a/src/level/maze_level.rs +++ b/src/level/maze_level.rs @@ -1,7 +1,5 @@ use std::ops::{Deref, DerefMut}; -use bevy::{ecs::system::Resource, prelude::*}; - use crate::maze; struct MazeImpl { @@ -164,7 +162,7 @@ impl MazeView for MazeImpl { } } -pub trait MazeView: Resource { +pub trait MazeView: Sync + Send { fn axis(&self) -> [u8; 2]; fn shift_axis(&mut self, axis: Axis, dir: Direction); diff --git a/src/main.rs b/src/main.rs index e522f16..45b2436 100644 --- a/src/main.rs +++ b/src/main.rs @@ -21,17 +21,9 @@ fn main() { .run(); } -fn setup( - mut commands: Commands, - asset_server: Res, - mut maze_spawner: EventWriter, -) { - commands.spawn_bundle(OrthographicCameraBundle::new_2d()); - commands.spawn_bundle(SpriteBundle { - texture: asset_server.load("textures/icon.png"), - ..Default::default() - }); - commands.spawn_bundle(PointLightBundle { +fn setup(mut c: Commands, mut maze_spawner: EventWriter) { + c.spawn_bundle(OrthographicCameraBundle::new_2d()); + c.spawn_bundle(PointLightBundle { point_light: PointLight { intensity: 1500.0, shadows_enabled: true, @@ -41,12 +33,12 @@ fn setup( ..Default::default() }); - commands.spawn_bundle(PerspectiveCameraBundle { + c.spawn_bundle(PerspectiveCameraBundle { transform: Transform::from_xyz(-6.0, 10.0, -4.0) .looking_at(Vec3::new(2.0, 0.0, 2.0), Vec3::Y), ..Default::default() }); - commands.spawn_bundle(UiCameraBundle::default()); + c.spawn_bundle(UiCameraBundle::default()); maze_spawner.send(level::LoadLevel { dimensions: level::DimensionLength::Three([4, 15, 2]), ..Default::default() From a1bd7b8dec27358c7c78c6afdd79c307242a22bb Mon Sep 17 00:00:00 2001 From: "Earthmark (Daniel Miller)" Date: Sat, 16 Apr 2022 15:40:19 -0700 Subject: [PATCH 4/6] Added white backgrounds to show available moves. --- src/level/loader.rs | 39 +++++++++ src/level/maze_level.rs | 39 ++++++--- src/level/maze_renderer.rs | 57 +++---------- src/level/maze_ui_renderer.rs | 147 ++++++++++++++++++++++------------ src/level/plugin.rs | 4 +- 5 files changed, 175 insertions(+), 111 deletions(-) diff --git a/src/level/loader.rs b/src/level/loader.rs index b71d949..707fd98 100644 --- a/src/level/loader.rs +++ b/src/level/loader.rs @@ -68,3 +68,42 @@ pub fn initial_events_on_load( }); axis_changed.send(AxisChanged { axis: maze.axis() }); } + +pub fn spawn_maze_root( + mut c: Commands, + mut meshes: ResMut>, + mut materials: ResMut>, +) { + c.insert_resource(MazeAssets { + joint: meshes.add(Mesh::from(shape::Box::new(0.2, 1.0, 0.2))), + wall: meshes.add(Mesh::from(shape::Box::new(0.1, 0.6, 1.0))), + material: materials.add(Color::rgb(0.8, 0.7, 0.6).into()), + }); +} + +#[derive(Component)] +pub struct MazeAssets { + joint: Handle, + wall: Handle, + material: Handle, +} + +impl MazeAssets { + pub fn wall(&self, transform: Transform) -> PbrBundle { + PbrBundle { + mesh: self.wall.clone(), + material: self.material.clone(), + transform, + ..Default::default() + } + } + + pub fn joint(&self, transform: Transform) -> PbrBundle { + PbrBundle { + mesh: self.joint.clone(), + material: self.material.clone(), + transform, + ..Default::default() + } + } +} diff --git a/src/level/maze_level.rs b/src/level/maze_level.rs index f403d09..fdae27f 100644 --- a/src/level/maze_level.rs +++ b/src/level/maze_level.rs @@ -8,6 +8,12 @@ struct MazeImpl { axis: [u8; 2], } +struct MazeCursor { + maze: MazeImpl, + pos: [u8; DIMS], + axis: [u8; 2], +} + #[derive(Clone, Debug)] pub struct AxisChanged { pub axis: [u8; 2], @@ -131,15 +137,7 @@ impl MazeView for MazeImpl { fn move_pos(&mut self, axis: Axis, dir: Direction) { let dim = *axis.get(&self.axis) as usize; - let mut pos = self.position; - if dir == Direction::Negative { - if let Some(new_pos) = pos[dim].checked_sub(1) { - pos[dim] = new_pos; - } else { - return; - } - } - if let Some(true) = self.maze.can_move(&pos, dim) { + if let Some(true) = self.can_move(dim as u8, dir) { if let Some(new_pos) = if dir == Direction::Positive { self.position[dim].checked_add(1) } else { @@ -150,7 +148,20 @@ impl MazeView for MazeImpl { } } - fn should_make_wall(&self, position: [u8; 2], axis: Axis) -> bool { + fn can_move(&self, dim: u8, dir: Direction) -> Option { + let dim = dim as usize; + let mut pos = self.position; + if dir == Direction::Negative { + if let Some(new_pos) = pos[dim].checked_sub(1) { + pos[dim] = new_pos; + } else { + return None; + } + } + return self.maze.can_move(&pos, dim); + } + + fn wall_in_current(&self, position: [u8; 2], axis: Axis) -> bool { let mut cursor = self.position; cursor[self.axis[0] as usize] = position[0]; cursor[self.axis[1] as usize] = position[1]; @@ -172,7 +183,9 @@ pub trait MazeView: Sync + Send { fn pos(&self) -> [u8; 2]; fn move_pos(&mut self, axis: Axis, dir: Direction); - fn should_make_wall(&self, position: [u8; 2], axis: Axis) -> bool; + fn can_move(&self, dim: u8, dir: Direction) -> Option; + + fn wall_in_current(&self, position: [u8; 2], axis: Axis) -> bool; } pub struct MazeLevel { @@ -217,12 +230,12 @@ impl MazeLevel { .flat_map(move |x| (0..length_y).map(move |y| [x, y])) .flat_map(move |cursor| { [ - if self.should_make_wall(cursor, Axis::X) { + if self.wall_in_current(cursor, Axis::X) { Some((cursor, [cursor[0] + 1, cursor[1]])) } else { None }, - if self.should_make_wall(cursor, Axis::Y) { + if self.wall_in_current(cursor, Axis::Y) { Some((cursor, [cursor[0], cursor[1] + 1])) } else { None diff --git a/src/level/maze_renderer.rs b/src/level/maze_renderer.rs index a365c00..f6fc42d 100644 --- a/src/level/maze_renderer.rs +++ b/src/level/maze_renderer.rs @@ -1,20 +1,11 @@ use std::f32::consts::PI; -use super::maze_level::*; +use super::{loader::MazeAssets, maze_level::*}; use bevy::prelude::*; -pub fn spawn_maze_root( - mut commands: Commands, - mut meshes: ResMut>, - mut materials: ResMut>, -) { - commands.spawn_bundle(MazeRendererBundle { - renderer: MazeRenderer { - last_axis: [0, 0], - joint: meshes.add(Mesh::from(shape::Box::new(0.2, 1.0, 0.2))), - wall: meshes.add(Mesh::from(shape::Box::new(0.1, 0.6, 1.0))), - material: materials.add(Color::rgb(0.8, 0.7, 0.6).into()), - }, +pub fn spawn_maze_root(mut c: Commands) { + c.spawn_bundle(MazeRendererBundle { + renderer: MazeRenderer { last_axis: [0, 0] }, transform: Default::default(), global_transform: Default::default(), }); @@ -30,29 +21,6 @@ pub struct MazeRendererBundle { #[derive(Component)] pub struct MazeRenderer { last_axis: [u8; 2], - joint: Handle, - wall: Handle, - material: Handle, -} - -impl MazeRenderer { - fn wall(&self, transform: Transform) -> PbrBundle { - PbrBundle { - mesh: self.wall.clone(), - material: self.material.clone(), - transform, - ..Default::default() - } - } - - fn joint(&self, transform: Transform) -> PbrBundle { - PbrBundle { - mesh: self.joint.clone(), - material: self.material.clone(), - transform, - ..Default::default() - } - } } pub fn update_maze_offset( @@ -61,32 +29,33 @@ pub fn update_maze_offset( mut position_changed: EventReader, mut axis_changed: EventReader, ) { - for _ in position_changed.iter() { + let mut update_pos = || { for (_, mut trs) in maze_query.iter_mut() { let p = level.pos(); trs.translation = Vec3::new(-(p[0] as f32), 0.0, -(p[1] as f32)) } + }; + for _ in position_changed.iter() { + update_pos(); } for _ in axis_changed.iter() { - for (_, mut trs) in maze_query.iter_mut() { - let p = level.pos(); - trs.translation = Vec3::new(-(p[0] as f32), 0.0, -(p[1] as f32)) - } + update_pos(); } } pub fn maze_level_renderer( level: Res, + assets: Res, mut commands: Commands, mut render_query: Query<(Entity, &mut MazeRenderer)>, mut axis_changed: EventReader, ) { for _ in axis_changed.iter() { - for (entity, mut assets) in render_query.iter_mut() { - if assets.last_axis == level.axis() { + for (entity, mut renderer) in render_query.iter_mut() { + if renderer.last_axis == level.axis() { continue; } - assets.last_axis = level.axis(); + renderer.last_axis = level.axis(); let mut entity = commands.entity(entity); entity.despawn_descendants(); diff --git a/src/level/maze_ui_renderer.rs b/src/level/maze_ui_renderer.rs index 6789830..0bb3fb9 100644 --- a/src/level/maze_ui_renderer.rs +++ b/src/level/maze_ui_renderer.rs @@ -1,4 +1,4 @@ -use super::maze_level::*; +use super::maze_level::{self, *}; use bevy::prelude::*; // Current dimension status text layout: @@ -34,13 +34,16 @@ pub fn spawn_ui(mut c: Commands, maze: Res, assets: Res) let style = TextStyle { font: assets.load("fonts\\UnicaOne-Regular.ttf"), font_size: 50.0, - ..Default::default() + ..default() }; - let label = |s: &str| TextBundle { + let label = |s: &str, c: Color| TextBundle { text: Text::with_section( s, - style.clone(), + TextStyle { + color: c, + ..style.clone() + }, TextAlignment { vertical: VerticalAlign::Center, horizontal: HorizontalAlign::Center, @@ -48,45 +51,50 @@ pub fn spawn_ui(mut c: Commands, maze: Res, assets: Res) ), style: Style { size: Size::new(Val::Auto, Val::Px(50.0)), - ..Default::default() + ..default() }, - ..Default::default() + ..default() }; - fn column() -> NodeBundle { - NodeBundle { - style: Style { - flex_direction: FlexDirection::Column, - justify_content: JustifyContent::SpaceEvenly, - ..Default::default() - }, - color: Color::NONE.into(), - ..Default::default() - } - } - let dimension_col = |dimension: usize| { move |c: &mut ChildBuilder| { - c.spawn_bundle(label("-")).insert(MazeAxisLabel { - dim: dimension as u8, - dir: AxisDirection::Positive, - }); - c.spawn_bundle(label("#")) + c.spawn_bundle(NodeBundle::default()) + .with_children(|c| { + c.spawn_bundle(label("-", Color::DARK_GRAY)) + .insert(MazeAxisLabel { + dim: dimension as u8, + dir: maze_level::Direction::Negative, + }); + }) + .insert(MazeAxisLabel { + dim: dimension as u8, + dir: maze_level::Direction::Negative, + }); + c.spawn_bundle(label("#", Color::WHITE)) .insert(MazePositionLabel { dimension }); - c.spawn_bundle(label("-")).insert(MazeAxisLabel { - dim: dimension as u8, - dir: AxisDirection::Negative, - }); + + c.spawn_bundle(NodeBundle::default()) + .with_children(|c| { + c.spawn_bundle(label("-", Color::DARK_GRAY)) + .insert(MazeAxisLabel { + dim: dimension as u8, + dir: maze_level::Direction::Positive, + }); + }) + .insert(MazeAxisLabel { + dim: dimension as u8, + dir: maze_level::Direction::Positive, + }); } }; c.spawn_bundle(NodeBundle { style: Style { flex_direction: FlexDirection::Column, - ..Default::default() + ..default() }, color: Color::NONE.into(), - ..Default::default() + ..default() }) .with_children(|c| { c.spawn_bundle(NodeBundle { @@ -94,10 +102,10 @@ pub fn spawn_ui(mut c: Commands, maze: Res, assets: Res) justify_content: JustifyContent::SpaceEvenly, flex_direction: FlexDirection::Row, align_items: AlignItems::Center, - ..Default::default() + ..default() }, color: Color::NONE.into(), - ..Default::default() + ..default() }) .with_children(|c| { // Axis Shift Controls @@ -113,11 +121,11 @@ pub fn spawn_ui(mut c: Commands, maze: Res, assets: Res) style: Style { margin: Rect { right: Val::Px(5.0), - ..Default::default() + ..default() }, - ..Default::default() + ..default() }, - ..Default::default() + ..default() }); c.spawn_bundle(TextBundle { text: Text::with_section( @@ -131,11 +139,11 @@ pub fn spawn_ui(mut c: Commands, maze: Res, assets: Res) style: Style { margin: Rect { left: Val::Px(5.0), - ..Default::default() + ..default() }, - ..Default::default() + ..default() }, - ..Default::default() + ..default() }); }); @@ -144,17 +152,31 @@ pub fn spawn_ui(mut c: Commands, maze: Res, assets: Res) flex_direction: FlexDirection::Row, align_items: AlignItems::Center, justify_content: JustifyContent::FlexStart, - ..Default::default() + ..default() }, color: Color::NONE.into(), - ..Default::default() + ..default() }) .with_children(|c| { - c.spawn_bundle(label("[")); + c.spawn_bundle(label("[", Color::WHITE)); for (i, _) in maze.dims_limit().iter().enumerate() { - c.spawn_bundle(column()).with_children(dimension_col(i)); + c.spawn_bundle(NodeBundle { + style: Style { + flex_direction: FlexDirection::Column, + justify_content: JustifyContent::SpaceEvenly, + margin: Rect { + left: Val::Px(3.0), + right: Val::Px(3.0), + ..default() + }, + ..default() + }, + color: Color::NONE.into(), + ..default() + }) + .with_children(dimension_col(i)); } - c.spawn_bundle(label("]")); + c.spawn_bundle(label("]", Color::WHITE)); }); }); } @@ -162,15 +184,34 @@ pub fn spawn_ui(mut c: Commands, maze: Res, assets: Res) #[derive(Component)] struct MazeUiRoot; -enum AxisDirection { - Positive, - Negative, -} - -#[derive(Component)] +#[derive(Component, Clone)] pub struct MazeAxisLabel { dim: u8, - dir: AxisDirection, + dir: maze_level::Direction, +} + +pub fn maze_axis_label_background_updater( + level: Res, + mut query: Query<(&MazeAxisLabel, &mut UiColor)>, + mut axis_changed: EventReader, + mut position_changed: EventReader, +) { + let mut update_bg = || { + for (axis, mut ui_color) in query.iter_mut() { + ui_color.0 = if let Some(true) = level.can_move(axis.dim, axis.dir) { + Color::WHITE + } else { + Color::GRAY + } + .into(); + } + }; + for _ in position_changed.iter() { + update_bg(); + } + for _ in axis_changed.iter() { + update_bg(); + } } pub fn maze_axis_label_update_listener( @@ -181,13 +222,13 @@ pub fn maze_axis_label_update_listener( for (label, mut text) in query.iter_mut() { if changed.axis[0] == label.dim { text.sections[0].value = match label.dir { - AxisDirection::Positive => "S".into(), - AxisDirection::Negative => "W".into(), + maze_level::Direction::Positive => "W".into(), + maze_level::Direction::Negative => "S".into(), }; } else if changed.axis[1] == label.dim { text.sections[0].value = match label.dir { - AxisDirection::Positive => "A".into(), - AxisDirection::Negative => "D".into(), + maze_level::Direction::Positive => "D".into(), + maze_level::Direction::Negative => "A".into(), }; } else { text.sections[0].value = "".into(); diff --git a/src/level/plugin.rs b/src/level/plugin.rs index df57991..d59d685 100644 --- a/src/level/plugin.rs +++ b/src/level/plugin.rs @@ -14,12 +14,14 @@ impl Plugin for LevelPlugin { SystemSet::on_enter(AppState::InMaze) .with_system(maze_renderer::spawn_maze_root) .with_system(maze_ui_renderer::spawn_ui) - .with_system(loader::initial_events_on_load), + .with_system(loader::initial_events_on_load) + .with_system(loader::spawn_maze_root), ) .add_system_set( SystemSet::on_update(AppState::InMaze) .with_system(maze_ui_renderer::maze_axis_label_update_listener) .with_system(maze_ui_renderer::maze_position_label_update_listener) + .with_system(maze_ui_renderer::maze_axis_label_background_updater) .with_system(maze_renderer::maze_level_renderer) .with_system(maze_renderer::update_maze_offset) .with_system(input::level_navigation), From 84acc1c248681f6b29c894ebe6124fa222b011db Mon Sep 17 00:00:00 2001 From: "Earthmark (Daniel Miller)" Date: Sat, 16 Apr 2022 16:08:58 -0700 Subject: [PATCH 5/6] Got text color showing victory states, and added a player. --- src/level/loader.rs | 17 ++++++++++++++++- src/level/maze_level.rs | 6 ------ src/level/maze_ui_renderer.rs | 12 ++++++++---- src/level/plugin.rs | 10 ++++++++-- 4 files changed, 32 insertions(+), 13 deletions(-) diff --git a/src/level/loader.rs b/src/level/loader.rs index 707fd98..6f85bf3 100644 --- a/src/level/loader.rs +++ b/src/level/loader.rs @@ -69,7 +69,7 @@ pub fn initial_events_on_load( axis_changed.send(AxisChanged { axis: maze.axis() }); } -pub fn spawn_maze_root( +pub fn load_maze_assets( mut c: Commands, mut meshes: ResMut>, mut materials: ResMut>, @@ -81,6 +81,21 @@ pub fn spawn_maze_root( }); } +pub fn spawn_player( + mut c: Commands, + mut meshes: ResMut>, + mut materials: ResMut>, +) { + c.spawn_bundle(PbrBundle { + mesh: meshes.add(Mesh::from(shape::Capsule { + radius: 0.3, + ..default() + })), + material: materials.add(Color::rgb(0.5, 0.5, 0.8).into()), + ..Default::default() + }); +} + #[derive(Component)] pub struct MazeAssets { joint: Handle, diff --git a/src/level/maze_level.rs b/src/level/maze_level.rs index fdae27f..c13adea 100644 --- a/src/level/maze_level.rs +++ b/src/level/maze_level.rs @@ -8,12 +8,6 @@ struct MazeImpl { axis: [u8; 2], } -struct MazeCursor { - maze: MazeImpl, - pos: [u8; DIMS], - axis: [u8; 2], -} - #[derive(Clone, Debug)] pub struct AxisChanged { pub axis: [u8; 2], diff --git a/src/level/maze_ui_renderer.rs b/src/level/maze_ui_renderer.rs index 0bb3fb9..e4124ab 100644 --- a/src/level/maze_ui_renderer.rs +++ b/src/level/maze_ui_renderer.rs @@ -181,9 +181,6 @@ pub fn spawn_ui(mut c: Commands, maze: Res, assets: Res) }); } -#[derive(Component)] -struct MazeUiRoot; - #[derive(Component, Clone)] pub struct MazeAxisLabel { dim: u8, @@ -251,7 +248,14 @@ pub fn maze_position_label_update_listener( for (label, mut text) in query.iter_mut() { if let Some(section) = text.sections.first_mut() { if let Some(target) = maze.dims().get(label.dimension) { - section.value = format!("{}", target); + let position = target + 1; + section.value = format!("{}", position); + section.style.color = + if maze.dims_limit().get(label.dimension) == Some(&position) { + Color::LIME_GREEN + } else { + Color::WHITE + }; } } } diff --git a/src/level/plugin.rs b/src/level/plugin.rs index d59d685..4873cde 100644 --- a/src/level/plugin.rs +++ b/src/level/plugin.rs @@ -2,23 +2,29 @@ use super::*; use crate::AppState; use bevy::prelude::*; +#[derive(Debug, Clone, PartialEq, Eq, Hash, SystemLabel)] +struct LevelInit; + pub struct LevelPlugin; impl Plugin for LevelPlugin { fn build(&self, app: &mut App) { - app.add_system(loader::level_load_system) + app.add_startup_system(loader::load_maze_assets) + .add_system(loader::level_load_system.before(LevelInit)) .add_event::() .add_event::() .add_event::() .add_system_set( SystemSet::on_enter(AppState::InMaze) + .label(LevelInit) .with_system(maze_renderer::spawn_maze_root) .with_system(maze_ui_renderer::spawn_ui) .with_system(loader::initial_events_on_load) - .with_system(loader::spawn_maze_root), + .with_system(loader::spawn_player), ) .add_system_set( SystemSet::on_update(AppState::InMaze) + .after(LevelInit) .with_system(maze_ui_renderer::maze_axis_label_update_listener) .with_system(maze_ui_renderer::maze_position_label_update_listener) .with_system(maze_ui_renderer::maze_axis_label_background_updater) From d3002d5759208cce7eaacc096c8c02a485b6e0d6 Mon Sep 17 00:00:00 2001 From: "Earthmark (Daniel Miller)" Date: Sat, 16 Apr 2022 16:17:30 -0700 Subject: [PATCH 6/6] Fixed clippy findings. --- src/level/loader.rs | 2 +- src/level/maze_level.rs | 2 +- src/level/maze_ui_renderer.rs | 3 +-- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/level/loader.rs b/src/level/loader.rs index 6f85bf3..afb7d26 100644 --- a/src/level/loader.rs +++ b/src/level/loader.rs @@ -64,7 +64,7 @@ pub fn initial_events_on_load( mut axis_changed: EventWriter, ) { position_changed.send(PositionChanged { - position: maze.pos().into(), + position: maze.pos(), }); axis_changed.send(AxisChanged { axis: maze.axis() }); } diff --git a/src/level/maze_level.rs b/src/level/maze_level.rs index c13adea..f2875b6 100644 --- a/src/level/maze_level.rs +++ b/src/level/maze_level.rs @@ -152,7 +152,7 @@ impl MazeView for MazeImpl { return None; } } - return self.maze.can_move(&pos, dim); + self.maze.can_move(&pos, dim) } fn wall_in_current(&self, position: [u8; 2], axis: Axis) -> bool { diff --git a/src/level/maze_ui_renderer.rs b/src/level/maze_ui_renderer.rs index e4124ab..396eef3 100644 --- a/src/level/maze_ui_renderer.rs +++ b/src/level/maze_ui_renderer.rs @@ -199,8 +199,7 @@ pub fn maze_axis_label_background_updater( Color::WHITE } else { Color::GRAY - } - .into(); + }; } }; for _ in position_changed.iter() {