diff --git a/.gitattributes b/.gitattributes
index 74b6958..e40cfc3 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -1,2 +1,3 @@
*.png filter=lfs diff=lfs merge=lfs -text
*.ttf filter=lfs diff=lfs merge=lfs -text
+*.xcf filter=lfs diff=lfs merge=lfs -text
diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml
index 76de216..35a5df6 100644
--- a/.github/workflows/ci.yaml
+++ b/.github/workflows/ci.yaml
@@ -2,99 +2,44 @@ name: CI
on:
push:
- branches: [main]
+ branches: [ main ]
pull_request:
- branches: [main]
+ branches: [ main ]
env:
CARGO_TERM_COLOR: always
+concurrency:
+ group: ${{ github.workflow }}-${{ github.ref }}
+ cancel-in-progress: true
+
+permissions:
+ contents: read
+
jobs:
- # Run cargo test
test:
- name: Test Suite
+ name: CI
runs-on: ubuntu-latest
steps:
- - name: Checkout sources
- uses: actions/checkout@v2
+ - uses: actions/checkout@v7
with:
lfs: 'true'
- - name: Cache
- uses: actions/cache@v2
- with:
- path: |
- ~/.cargo/bin/
- ~/.cargo/registry/index/
- ~/.cargo/registry/cache/
- ~/.cargo/git/db/
- target/
- key: ${{ runner.os }}-cargo-test-${{ hashFiles('**/Cargo.toml') }}
- - name: Install stable toolchain
- uses: actions-rs/toolchain@v1
- with:
- profile: minimal
- toolchain: stable
- override: true
- - name: Install Dependencies
- run: sudo apt-get update; sudo apt-get install pkg-config libx11-dev libasound2-dev libudev-dev libxcb-render0-dev libxcb-shape0-dev libxcb-xfixes0-dev
- - name: Run cargo test
- uses: actions-rs/cargo@v1
- with:
- command: test
- # Run cargo clippy -- -D warnings
- clippy_check:
- name: Clippy
- runs-on: ubuntu-latest
- steps:
- - name: Checkout sources
- uses: actions/checkout@v2
- with:
- lfs: 'true'
- - name: Cache
- uses: actions/cache@v2
+ - uses: dtolnay/rust-toolchain@stable
with:
- path: |
- ~/.cargo/bin/
- ~/.cargo/registry/index/
- ~/.cargo/registry/cache/
- ~/.cargo/git/db/
- target/
- key: ${{ runner.os }}-cargo-clippy-${{ hashFiles('**/Cargo.toml') }}
- - name: Install stable toolchain
- uses: actions-rs/toolchain@v1
- with:
- toolchain: stable
- profile: minimal
- components: clippy
- override: true
+ components: clippy, rustfmt
+ targets: wasm32-unknown-unknown
+ - uses: Swatinem/rust-cache@v2
+
- name: Install Dependencies
- run: sudo apt-get update; sudo apt-get install pkg-config libx11-dev libasound2-dev libudev-dev
- - name: Run clippy
- uses: actions-rs/clippy-check@v1
- with:
- token: ${{ secrets.GITHUB_TOKEN }}
- args: -- -D warnings
+ run: sudo apt-get update && sudo apt-get install -y g++ pkg-config libx11-dev libasound2-dev libudev-dev libwayland-dev libxkbcommon-dev
- # Run cargo fmt --all -- --check
- format:
- name: Format
- runs-on: ubuntu-latest
- steps:
- - name: Checkout sources
- uses: actions/checkout@v2
- with:
- lfs: 'true'
- - name: Install stable toolchain
- uses: actions-rs/toolchain@v1
- with:
- toolchain: stable
- profile: minimal
- components: rustfmt
- override: true
- - name: Run cargo fmt
- uses: actions-rs/cargo@v1
- with:
- command: fmt
- args: --all -- --check
\ No newline at end of file
+ - name: Fmt
+ run: cargo fmt --all --check
+ - name: Clippy
+ run: cargo clippy --all-targets -- -D warnings
+ - name: Test
+ run: cargo test
+ - name: Wasm Test
+ run: cargo check --target wasm32-unknown-unknown
diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml
index 82c7b06..907f798 100644
--- a/.github/workflows/release.yaml
+++ b/.github/workflows/release.yaml
@@ -4,166 +4,46 @@ on:
push:
tags:
- '*'
+ workflow_dispatch:
env:
- # update with the name of the main binary
binary: nothing-moves
+permissions:
+ contents: write
jobs:
- # Build for wasm
release-wasm:
runs-on: ubuntu-latest
steps:
- - uses: little-core-labs/get-git-tag@v3.0.1
- id: get_version
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v7
with:
lfs: 'true'
- - uses: actions-rs/toolchain@v1
+ - uses: dtolnay/rust-toolchain@stable
with:
- toolchain: stable
target: wasm32-unknown-unknown
- override: true
- - name: install trunk
- run: |
- cargo install trunk
- - name: Build
- run: |
- trunk build --release
- - name: Prepare package
- run: |
- cp -r assets dist/
- - name: Package as a zip
- uses: vimtor/action-zip@v1
- with:
- files: dist
- dest: ${{ env.binary }}.zip
-
- - name: Upload binaries to release
- uses: svenstaro/upload-release-action@v2
- with:
- repo_token: ${{ secrets.GITHUB_TOKEN }}
- file: ${{ env.binary }}.zip
- asset_name: ${{ env.binary }}-wasm-${{ steps.get_version.outputs.tag }}.zip
- tag: ${{ github.ref }}
- overwrite: true
+ - uses: Swatinem/rust-cache@v2
+ - uses: jetli/trunk-action@v0.5.1
- # Build for Linux
- release-linux:
- runs-on: ubuntu-latest
-
- steps:
- - uses: little-core-labs/get-git-tag@v3.0.1
- id: get_version
- - uses: actions/checkout@v2
- with:
- lfs: 'true'
- - uses: actions-rs/toolchain@v1
- with:
- toolchain: stable
- target: x86_64-unknown-linux-gnu
- override: true
- - name: install dependencies
- run: |
- sudo apt-get update; sudo apt-get install pkg-config libx11-dev libasound2-dev libudev-dev libxcb-render0-dev libxcb-shape0-dev libxcb-xfixes0-dev
- name: Build
- run: |
- cargo build --release --target x86_64-unknown-linux-gnu
- - name: Prepare package
- run: |
- mkdir linux
- cp target/x86_64-unknown-linux-gnu/release/${{ env.binary }} linux/
- cp -r assets linux/
+ run: trunk build --release
- name: Package as a zip
- uses: vimtor/action-zip@v1
- with:
- files: linux
- dest: ${{ env.binary }}.zip
-
- - name: Upload binaries to release
- uses: svenstaro/upload-release-action@v2
- with:
- repo_token: ${{ secrets.GITHUB_TOKEN }}
- file: ${{ env.binary }}.zip
- asset_name: ${{ env.binary }}-linux-${{ steps.get_version.outputs.tag }}.zip
- tag: ${{ github.ref }}
- overwrite: true
-
- # Build for Windows
- release-windows:
- runs-on: windows-latest
-
- steps:
- - uses: little-core-labs/get-git-tag@v3.0.1
- id: get_version
- - uses: actions/checkout@v2
- with:
- lfs: 'true'
- - uses: actions-rs/toolchain@v1
- with:
- toolchain: stable
- target: x86_64-pc-windows-msvc
- override: true
+ run: zip -r ${{ env.binary }}.zip dist
- - name: Build
- run: |
- cargo build --release --target x86_64-pc-windows-msvc
- - name: Prepare package
- run: |
- mkdir windows
- cp target/x86_64-pc-windows-msvc/release/${{ env.binary }}.exe windows/
- cp -r assets windows/
- - name: Package as a zip
- uses: vimtor/action-zip@v1
+ - name: Upload binaries to build
+ uses: actions/upload-artifact@v4
with:
- files: windows
- dest: ${{ env.binary }}.zip
+ name: ${{ env.binary }}-wasm
+ path: dist
- name: Upload binaries to release
+ if: startsWith(github.ref, 'refs/tags/')
uses: svenstaro/upload-release-action@v2
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
file: ${{ env.binary }}.zip
- asset_name: ${{ env.binary }}-windows-${{ steps.get_version.outputs.tag }}.zip
+ asset_name: ${{ env.binary }}-wasm-${{ github.ref_name }}.zip
tag: ${{ github.ref }}
overwrite: true
-
- # Build for macOS
- release-macos:
- runs-on: macOS-latest
-
- steps:
- - uses: little-core-labs/get-git-tag@v3.0.1
- id: get_version
- - uses: actions/checkout@v2
- with:
- lfs: 'true'
- - uses: actions-rs/toolchain@v1
- with:
- toolchain: stable
- target: x86_64-apple-darwin
- override: true
- - name: Environment Setup
- run: |
- export CFLAGS="-fno-stack-check"
- export MACOSX_DEPLOYMENT_TARGET="10.9"
- - name: Build
- run: |
- cargo build --release --target x86_64-apple-darwin
- - name: Prepare Package
- run: |
- mkdir -p ${{ env.binary }}.app/Contents/MacOS
- cp target/x86_64-apple-darwin/release/${{ env.binary }} ${{ env.binary }}.app/Contents/MacOS/
- cp -r assets ${{ env.binary }}.app/Contents/MacOS/
- hdiutil create -fs HFS+ -volname "${{ env.binary }}" -srcfolder ${{ env.binary }}.app ${{ env.binary }}.dmg
- - name: Upload binaries to release
- uses: svenstaro/upload-release-action@v2
- with:
- repo_token: ${{ secrets.GITHUB_TOKEN }}
- file: ${{ env.binary }}.dmg
- asset_name: ${{ env.binary }}-macos-${{ steps.get_version.outputs.tag }}.dmg
- tag: ${{ github.ref }}
- overwrite: true
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index 40ce561..2b1cd31 100644
--- a/.gitignore
+++ b/.gitignore
@@ -15,3 +15,6 @@ Cargo.lock
/target
/dist
+
+# RustRover
+.idea
diff --git a/Cargo.toml b/Cargo.toml
index af59c92..6305fc1 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -5,8 +5,9 @@ name = "nothing-moves"
version = "0.1.0"
[dependencies]
-bevy = "0.7"
-rand = "0.8"
+bevy = "*"
+rand = "*"
+bevy-inspector-egui = "*"
# Enable only a small amount of optimization in debug mode
[profile.dev]
@@ -15,3 +16,19 @@ opt-level = 1
# Enable high optimizations for dependencies (incl. Bevy), but not for our code:
[profile.dev.package."*"]
opt-level = 3
+
+[profile.wasm-release]
+# Use release profile as default values
+inherits = "release"
+
+# Optimize with size in mind, also try "s", sometimes it is better.
+# This doesn't increase compilation times compared to -O3, great improvements
+opt-level = "z"
+
+# Do a second optimization pass removing duplicate or unused code from dependencies.
+# Slows compile times, marginal improvements
+lto = "fat"
+
+# When building crates, optimize larger chunks at a time
+# Slows compile times, marginal improvements
+codegen-units = 1
diff --git a/Trunk.toml b/Trunk.toml
new file mode 100644
index 0000000..36598c5
--- /dev/null
+++ b/Trunk.toml
@@ -0,0 +1,5 @@
+[build]
+public_url = "./"
+
+[serve]
+port = 8080
diff --git a/asset_bases/arrow.xcf b/asset_bases/arrow.xcf
new file mode 100644
index 0000000..501009a
--- /dev/null
+++ b/asset_bases/arrow.xcf
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:8bb59464ba36eeb7a604ebbd31f63af002d61654fe2da7f460bf687fad3d3d0b
+size 2701
diff --git a/asset_bases/circle_arrow.xcf b/asset_bases/circle_arrow.xcf
new file mode 100644
index 0000000..4246842
--- /dev/null
+++ b/asset_bases/circle_arrow.xcf
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:1e85ea5ccc8e3920bf41f5497695d3ef3604b5dab4fc9b60f2869b616e394d5d
+size 7058
diff --git a/asset_bases/circle_dash_arrow.xcf b/asset_bases/circle_dash_arrow.xcf
new file mode 100644
index 0000000..edcef5f
--- /dev/null
+++ b/asset_bases/circle_dash_arrow.xcf
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:ba116e1d44d9dc1d29189718732081acbb781b8dd775f4c203ed295b12294122
+size 6318
diff --git a/asset_bases/dash_arrow.xcf b/asset_bases/dash_arrow.xcf
new file mode 100644
index 0000000..b18e3c0
--- /dev/null
+++ b/asset_bases/dash_arrow.xcf
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:d44edb8e4603aac095049587fbb222c025dcde24fa8a46663cd2ff19b8c13c8b
+size 2468
diff --git a/assets/scenes/ui/maze_controls.scn.ron b/assets/scenes/ui/maze_controls.scn.ron
new file mode 100644
index 0000000..c296e5d
--- /dev/null
+++ b/assets/scenes/ui/maze_controls.scn.ron
@@ -0,0 +1,12 @@
+(
+ entities: {
+ 0: (
+ components: {
+ "bevy_ui::ui_node::Style": (),
+ "bevy_ui::ui_node::Node": (),
+ "bevy_ui::ui_node::BackgroundColor": (WHITE),
+ "bevy_transform::components::transform::Transform": ()
+ }
+ )
+ }
+)
diff --git a/assets/textures/arrow.png b/assets/textures/arrow.png
new file mode 100644
index 0000000..af2633a
--- /dev/null
+++ b/assets/textures/arrow.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:73b4eae4d9e6cb1693b9f501b5cd466159307558353ab8eaaf497e3ff360a9c7
+size 2337
diff --git a/assets/textures/circle_arrow.png b/assets/textures/circle_arrow.png
new file mode 100644
index 0000000..1389ae4
--- /dev/null
+++ b/assets/textures/circle_arrow.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:1fac63123788ac28e25720441da14e31a15006d34f2d315451a4fe24f9c4040e
+size 4717
diff --git a/assets/textures/circle_arrow_flip.png b/assets/textures/circle_arrow_flip.png
new file mode 100644
index 0000000..d7ceb64
--- /dev/null
+++ b/assets/textures/circle_arrow_flip.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:92ca24a455fe7df148fe9e22b592b57f7f0ba53379cfb1bfd8fa62ef4a951faf
+size 12935
diff --git a/assets/textures/circle_dash_arrow.png b/assets/textures/circle_dash_arrow.png
new file mode 100644
index 0000000..3c6a8a0
--- /dev/null
+++ b/assets/textures/circle_dash_arrow.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:d826945e1d400351e4e80499599a3e327f817e4e75b2ebe2af8255f18953c8cd
+size 4081
diff --git a/assets/textures/circle_dash_arrow_flip.png b/assets/textures/circle_dash_arrow_flip.png
new file mode 100644
index 0000000..f60f972
--- /dev/null
+++ b/assets/textures/circle_dash_arrow_flip.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:0848f8e5c7bc5321d74d3f3b3e433ebebb82233960d4a702f5d41cd50394ee26
+size 11965
diff --git a/assets/textures/dash_arrow.png b/assets/textures/dash_arrow.png
new file mode 100644
index 0000000..d6069f3
--- /dev/null
+++ b/assets/textures/dash_arrow.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:99e9e19bbd4ad4ae1ffa4c44b392cf1808428e74b84032abefd6a40b17a1cff6
+size 2987
diff --git a/index.html b/index.html
index e69de29..a45bc29 100644
--- a/index.html
+++ b/index.html
@@ -0,0 +1,17 @@
+
+
+
+
+
+ Nothing Moves
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/assets.rs b/src/assets.rs
new file mode 100644
index 0000000..23996ef
--- /dev/null
+++ b/src/assets.rs
@@ -0,0 +1,39 @@
+use bevy::prelude::*;
+
+#[derive(Resource)]
+pub struct CommonAssets {
+ common_font: Handle,
+}
+
+pub trait CommonSpawnable {
+ fn spawn_under(self, assets: &CommonAssets, c: &mut ChildSpawnerCommands, bundle: impl Bundle);
+}
+
+impl CommonAssets {
+ pub fn load_resource(mut c: Commands, assets: Res) {
+ c.insert_resource(Self::load(assets))
+ }
+
+ fn load(assets: Res) -> Self {
+ Self {
+ common_font: assets.load("fonts\\UnicaOne-Regular.ttf"),
+ }
+ }
+
+ pub fn spawn_common(
+ &self,
+ c: &mut ChildSpawnerCommands,
+ common: impl CommonSpawnable,
+ bundle: impl Bundle,
+ ) {
+ common.spawn_under(self, c, bundle);
+ }
+
+ pub fn common_text_style(&self) -> TextFont {
+ TextFont {
+ font: FontSource::Handle(self.common_font.clone()),
+ font_size: FontSize::Px(50.0),
+ ..default()
+ }
+ }
+}
diff --git a/src/level/bundle.rs b/src/level/bundle.rs
new file mode 100644
index 0000000..f9f63e8
--- /dev/null
+++ b/src/level/bundle.rs
@@ -0,0 +1,14 @@
+use super::*;
+use bevy::{app::PluginGroupBuilder, prelude::*};
+
+pub struct LevelPluginBundle;
+
+impl PluginGroup for LevelPluginBundle {
+ fn build(self) -> PluginGroupBuilder {
+ PluginGroupBuilder::start::()
+ .add(maze_ui_renderer::MazeUiRendererPlugin)
+ .add(maze_renderer::MazeRendererPlugin)
+ .add(input::MazeInputBundle)
+ .add(loader::MazeLoaderPlugin)
+ }
+}
diff --git a/src/level/input.rs b/src/level/input.rs
index 885c375..e89b13c 100644
--- a/src/level/input.rs
+++ b/src/level/input.rs
@@ -3,52 +3,85 @@ use bevy::prelude::*;
use super::maze_level::*;
use super::maze_level::{Axis, Direction};
-pub fn level_navigation(
- level: Option>,
- keys: Res>,
- mut position_event: EventWriter,
- mut axis_event: EventWriter,
+pub struct MazeInputBundle;
+
+impl Plugin for MazeInputBundle {
+ fn build(&self, app: &mut App) {
+ app.add_message::()
+ .add_message::()
+ .add_systems(OnEnter(crate::AppState::InMaze), initial_events_on_load)
+ .add_systems(
+ Update,
+ level_navigation.run_if(in_state(crate::AppState::InMaze)),
+ );
+ }
+}
+
+#[derive(Clone, Debug, Message)]
+pub struct AxisChanged {
+ pub axis: [u8; 2],
+ pub previous_axis: [u8; 2],
+}
+
+#[derive(Clone, Debug, Message)]
+pub struct PositionChanged {
+ pub _position: [u8; 2],
+ pub _previous_position: [u8; 2],
+}
+
+fn initial_events_on_load(
+ maze: Res,
+ mut position_changed: MessageWriter,
+ mut axis_changed: MessageWriter,
) {
- if let Some(mut level) = level {
- if keys.just_pressed(KeyCode::Q) {
- level.shift_axis(Axis::X, Direction::Negative);
- axis_event.send(AxisChanged { axis: level.axis() });
- }
- if keys.just_pressed(KeyCode::E) {
- level.shift_axis(Axis::X, Direction::Positive);
- axis_event.send(AxisChanged { axis: level.axis() });
- }
- 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 {
- position: level.pos(),
- });
- }
- if keys.just_pressed(KeyCode::S) {
- level.move_pos(Axis::X, Direction::Negative);
- position_event.send(PositionChanged {
- position: level.pos(),
- });
- }
- if keys.just_pressed(KeyCode::D) {
- level.move_pos(Axis::Y, Direction::Positive);
- position_event.send(PositionChanged {
- position: level.pos(),
- });
+ position_changed.write(PositionChanged {
+ _position: maze.pos(),
+ _previous_position: maze.pos(),
+ });
+ axis_changed.write(AxisChanged {
+ axis: maze.axis(),
+ previous_axis: maze.axis(),
+ });
+}
+
+fn level_navigation(
+ mut level: ResMut,
+ keys: Res>,
+ mut position_event: MessageWriter,
+ mut axis_event: MessageWriter,
+) {
+ let mut shift_axis = |key: KeyCode, axis: Axis, dir: Direction| {
+ if keys.just_pressed(key) {
+ let previous_axis = level.axis();
+ level.shift_axis(axis, dir);
+ let axis = level.axis();
+ if previous_axis != axis {
+ axis_event.write(AxisChanged {
+ axis,
+ previous_axis,
+ });
+ }
}
- if keys.just_pressed(KeyCode::A) {
- level.move_pos(Axis::Y, Direction::Negative);
- position_event.send(PositionChanged {
- position: level.pos(),
- });
+ };
+ shift_axis(KeyCode::KeyQ, Axis::X, Direction::Negative);
+ shift_axis(KeyCode::KeyE, Axis::X, Direction::Positive);
+ shift_axis(KeyCode::KeyZ, Axis::Y, Direction::Negative);
+ shift_axis(KeyCode::KeyX, Axis::Y, Direction::Positive);
+ let mut shift_position = |key: KeyCode, axis: Axis, dir: Direction| {
+ if keys.just_pressed(key) {
+ let previous_position = level.pos();
+ level.move_pos(axis, dir);
+ let position = level.pos();
+ if previous_position != position {
+ position_event.write(PositionChanged {
+ _position: position,
+ _previous_position: previous_position,
+ });
+ }
}
- }
+ };
+ shift_position(KeyCode::KeyW, Axis::X, Direction::Positive);
+ shift_position(KeyCode::KeyS, Axis::X, Direction::Negative);
+ shift_position(KeyCode::KeyD, Axis::Y, Direction::Positive);
+ shift_position(KeyCode::KeyA, Axis::Y, Direction::Negative);
}
diff --git a/src/level/loader.rs b/src/level/loader.rs
index afb7d26..ce9c7d9 100644
--- a/src/level/loader.rs
+++ b/src/level/loader.rs
@@ -2,12 +2,18 @@ use crate::AppState;
use bevy::prelude::*;
use rand::prelude::*;
-use super::{
- maze_level::{AxisChanged, PositionChanged},
- MazeLevel,
-};
+use super::maze_level::MazeLevel;
-#[derive(Clone, Debug)]
+pub struct MazeLoaderPlugin;
+
+impl Plugin for MazeLoaderPlugin {
+ fn build(&self, app: &mut App) {
+ app.add_systems(Update, level_load_system)
+ .add_message::();
+ }
+}
+
+#[derive(Clone, Debug, Message)]
pub struct LoadLevel {
pub rng_source: RngSource,
pub dimensions: DimensionLength,
@@ -38,12 +44,29 @@ impl Default for LoadLevel {
}
}
-pub fn level_load_system(
+impl LoadLevel {
+ pub fn new(d: &[u8]) -> Self {
+ let dimensions = match d.len() {
+ 2 => DimensionLength::Two([d[0], d[1]]),
+ 3 => DimensionLength::Three([d[0], d[1], d[2]]),
+ 4 => DimensionLength::Four([d[0], d[1], d[2], d[3]]),
+ 5 => DimensionLength::Five([d[0], d[1], d[2], d[3], d[4]]),
+ 6 => DimensionLength::Six([d[0], d[1], d[2], d[3], d[4], d[5]]),
+ _ => panic!("Unexpected dimension length, it must be 2-6."),
+ };
+ Self {
+ dimensions,
+ ..default()
+ }
+ }
+}
+
+fn level_load_system(
mut c: Commands,
- mut events: EventReader,
- mut app_state: ResMut>,
+ mut events: MessageReader,
+ mut app_state: ResMut>,
) {
- for level_loader in events.iter() {
+ for level_loader in events.read() {
let mut rng = match level_loader.rng_source {
RngSource::Seeded(seed) => StdRng::seed_from_u64(seed),
};
@@ -54,71 +77,6 @@ pub fn level_load_system(
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(
- maze: Res,
- mut position_changed: EventWriter,
- mut axis_changed: EventWriter,
-) {
- position_changed.send(PositionChanged {
- position: maze.pos(),
- });
- axis_changed.send(AxisChanged { axis: maze.axis() });
-}
-
-pub fn load_maze_assets(
- 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()),
- });
-}
-
-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,
- 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()
- }
+ app_state.set(AppState::InMaze);
}
}
diff --git a/src/level/maze_level.rs b/src/level/maze_level.rs
index f2875b6..3aa515c 100644
--- a/src/level/maze_level.rs
+++ b/src/level/maze_level.rs
@@ -1,5 +1,7 @@
use std::ops::{Deref, DerefMut};
+use bevy::prelude::Resource;
+
use crate::maze;
struct MazeImpl {
@@ -8,16 +10,6 @@ struct MazeImpl {
axis: [u8; 2],
}
-#[derive(Clone, Debug)]
-pub struct AxisChanged {
- pub axis: [u8; 2],
-}
-
-#[derive(Clone, Debug)]
-pub struct PositionChanged {
- pub position: [u8; 2],
-}
-
#[derive(PartialEq, Eq, Clone, Copy)]
pub enum Axis {
X,
@@ -53,11 +45,21 @@ pub enum Direction {
}
impl Direction {
+ /*
fn shift_wrapped(&self, value: u8, limit: u8) -> u8 {
(match self {
Direction::Positive => value.checked_add(1).unwrap_or(0),
- Direction::Negative => value.checked_sub(1).unwrap_or(limit - 2),
- } % (limit - 1))
+ Direction::Negative => value.checked_sub(1).unwrap_or(limit - 1),
+ } % limit)
+ }
+ */
+
+ fn shift_clamped(&self, value: u8, limit: u8) -> u8 {
+ match self {
+ Direction::Positive => value.checked_add(1).unwrap_or(limit - 1),
+ Direction::Negative => value.saturating_sub(1),
+ }
+ .clamp(0, limit - 1)
}
}
@@ -96,7 +98,7 @@ impl MazeView for MazeImpl {
target_axis
};
- let new_off_axis = dir.shift_wrapped(linear_current, DIMS as u8);
+ let new_off_axis = dir.shift_clamped(linear_current, DIMS as u8 - 1);
let dest = if new_off_axis >= off_target_axis {
new_off_axis + 1
} else {
@@ -129,6 +131,13 @@ impl MazeView for MazeImpl {
]
}
+ fn pos_in(&self, axis: [u8; 2]) -> [u8; 2] {
+ [
+ self.position[axis[0] as usize],
+ self.position[axis[1] as usize],
+ ]
+ }
+
fn move_pos(&mut self, axis: Axis, dir: Direction) {
let dim = *axis.get(&self.axis) as usize;
if let Some(true) = self.can_move(dim as u8, dir) {
@@ -146,11 +155,8 @@ impl MazeView for MazeImpl {
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;
- }
+ let new_pos = pos[dim].checked_sub(1)?;
+ pos[dim] = new_pos;
}
self.maze.can_move(&pos, dim)
}
@@ -175,6 +181,7 @@ pub trait MazeView: Sync + Send {
fn dims(&self) -> &[u8];
fn pos_limit(&self) -> [u8; 2];
fn pos(&self) -> [u8; 2];
+ fn pos_in(&self, axis: [u8; 2]) -> [u8; 2];
fn move_pos(&mut self, axis: Axis, dir: Direction);
fn can_move(&self, dim: u8, dir: Direction) -> Option;
@@ -182,6 +189,7 @@ pub trait MazeView: Sync + Send {
fn wall_in_current(&self, position: [u8; 2], axis: Axis) -> bool;
}
+#[derive(Resource)]
pub struct MazeLevel {
inner: Box,
}
@@ -189,7 +197,7 @@ pub struct MazeLevel {
impl Default for MazeLevel {
fn default() -> Self {
Self {
- inner: Box::new(MazeImpl::<2>::default()),
+ inner: Box::>::default(),
}
}
}
diff --git a/src/level/maze_renderer.rs b/src/level/maze_renderer.rs
index f6fc42d..2305d14 100644
--- a/src/level/maze_renderer.rs
+++ b/src/level/maze_renderer.rs
@@ -1,105 +1,231 @@
+use super::maze_level::*;
+use bevy::prelude::*;
+use std::cmp::Ordering;
use std::f32::consts::PI;
+use std::time::Duration;
-use super::{loader::MazeAssets, maze_level::*};
-use bevy::prelude::*;
+pub struct MazeRendererPlugin;
+
+impl Plugin for MazeRendererPlugin {
+ fn build(&self, app: &mut App) {
+ app.add_systems(Startup, load_maze_assets)
+ .add_systems(OnEnter(crate::AppState::InMaze), spawn_player)
+ .add_systems(
+ Update,
+ (
+ maze_level_renderer,
+ rotate_for_n_update,
+ remove_after_time::,
+ remove_after_time::,
+ update_maze_offset.after(maze_level_renderer),
+ start_despawn_of_render,
+ )
+ .run_if(in_state(crate::AppState::InMaze)),
+ );
+ }
+}
-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(),
+fn load_maze_assets(
+ mut c: Commands,
+ mut meshes: ResMut>,
+ mut materials: ResMut>,
+) {
+ c.insert_resource(MazeAssets {
+ joint: meshes.add(Cuboid::new(0.2, 1.0, 0.2)),
+ wall: meshes.add(Cuboid::new(0.1, 0.6, 1.0)),
+ material: materials.add(StandardMaterial {
+ base_color: Color::srgb(0.8, 0.7, 0.6),
+ ..default()
+ }),
});
}
-#[derive(Bundle)]
-pub struct MazeRendererBundle {
- pub renderer: MazeRenderer,
+#[derive(Resource)]
+struct MazeAssets {
+ joint: Handle,
+ wall: Handle,
+ material: Handle,
+}
+
+impl MazeAssets {
+ pub fn wall(&self) -> (Mesh3d, MeshMaterial3d) {
+ (
+ Mesh3d(self.wall.clone()),
+ MeshMaterial3d(self.material.clone()),
+ )
+ }
+
+ pub fn joint(&self) -> (Mesh3d, MeshMaterial3d) {
+ (
+ Mesh3d(self.joint.clone()),
+ MeshMaterial3d(self.material.clone()),
+ )
+ }
+}
+
+fn spawn_player(
+ mut c: Commands,
+ mut meshes: ResMut>,
+ mut materials: ResMut>,
+) {
+ c.spawn((
+ Mesh3d(meshes.add(Mesh::from(Capsule3d {
+ radius: 0.3,
+ ..default()
+ }))),
+ MeshMaterial3d(materials.add(StandardMaterial::from(Color::srgb(0.5, 0.5, 0.8)))),
+ Transform::default(),
+ ));
+}
+
+#[derive(Bundle, Default)]
+pub struct MazePositionTrackerBundle {
+ pub position_tracker: MazePositionTracker,
pub transform: Transform,
pub global_transform: GlobalTransform,
+ pub computed_visibility: InheritedVisibility,
+ pub visibility: Visibility,
}
-#[derive(Component)]
-pub struct MazeRenderer {
- last_axis: [u8; 2],
+#[derive(Component, Default)]
+pub struct MazePositionTracker {
+ visible_axis: [u8; 2],
+}
+
+fn maze_level_offset(maze: &MazeLevel, axis: [u8; 2]) -> Vec3 {
+ let p = maze.pos_in(axis);
+ Vec3::new(-(p[0] as f32), 0.0, -(p[1] as f32))
}
-pub fn update_maze_offset(
+fn update_maze_offset(
level: Res,
- mut maze_query: Query<(&MazeRenderer, &mut Transform)>,
- mut position_changed: EventReader,
- mut axis_changed: EventReader,
+ time: Res