Merge branch 'feature/isometric-camera'

This commit is contained in:
Kristofers Solo 2024-11-04 20:45:36 +02:00
commit 5eefa234e1
14 changed files with 956 additions and 23 deletions

402
Cargo.lock generated
View File

@ -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",
"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.27.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cac12a22e5de801323bc5bc344949de086b9b8db02c34e109f128ffd41514e5d"
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",
"pretty-type-name",
"smallvec",
"winit",
]
[[package]]
name = "bevy-inspector-egui-derive"
version = "0.27.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89f3be3ba88a25445c0c10684709b1ccd07e37f5f6b5d1b8dcf11d34548f1d61"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.72",
]
[[package]]
name = "bevy_a11y"
version = "0.14.1"
@ -579,6 +641,28 @@ dependencies = [
"syn 2.0.72",
]
[[package]]
name = "bevy_egui"
version = "0.30.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d0b8c164da1303ac3e6dc8d1a649be3e4399f12fd132f7665f3d018884236f9c"
dependencies = [
"arboard",
"bevy",
"bytemuck",
"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"
@ -818,6 +902,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"
@ -1368,6 +1464,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"
@ -1482,10 +1587,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"
@ -1494,7 +1609,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",
@ -1507,7 +1622,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",
]
@ -1643,12 +1758,43 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f25c0e292a7ca6d6498557ff1df68f32c99850012b6ea401cf8daf771f22ff53"
[[package]]
name = "ecolor"
version = "0.29.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "775cfde491852059e386c4e1deb4aef381c617dc364184c6f6afee99b87c402b"
dependencies = [
"bytemuck",
"emath",
]
[[package]]
name = "egui"
version = "0.29.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "53eafabcce0cb2325a59a98736efe0bf060585b437763f8c476957fb274bb974"
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.29.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1fe0049ce51d0fb414d029e668dd72eb30bc2b739bf34296ed97bd33df544f3"
dependencies = [
"bytemuck",
]
[[package]]
name = "encase"
version = "0.8.0"
@ -1681,6 +1827,28 @@ dependencies = [
"syn 2.0.72",
]
[[package]]
name = "epaint"
version = "0.29.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
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"
@ -1707,6 +1875,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"
@ -1801,6 +1975,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"
@ -1834,6 +2014,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"
@ -1868,6 +2057,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"
@ -1910,7 +2108,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",
@ -2137,6 +2335,36 @@ 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 = "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.25.2"
@ -2147,6 +2375,7 @@ dependencies = [
"byteorder-lite",
"num-traits",
"png",
"tiff",
]
[[package]]
@ -2261,6 +2490,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"
@ -2316,6 +2551,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"
@ -2365,6 +2609,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"
@ -2414,6 +2664,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"
@ -2606,6 +2898,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"
@ -2692,6 +2990,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
dependencies = [
"autocfg",
"libm",
]
[[package]]
@ -3137,6 +3436,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"
@ -3452,6 +3757,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"
@ -3537,6 +3848,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"
@ -3597,9 +3918,12 @@ dependencies = [
[[package]]
name = "the-labyrinth-of-echoes"
version = "0.0.1"
version = "0.0.4"
dependencies = [
"bevy",
"bevy-inspector-egui",
"bevy_prototype_lyon",
"hexx",
"log",
"rand",
"tracing",
@ -3635,6 +3959,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"
@ -3797,12 +4132,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"
@ -3821,6 +4171,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"
@ -4036,6 +4397,7 @@ checksum = "43676fe2daf68754ecf1d72026e4e6c15483198b5d24e888b74d3f22f887a148"
dependencies = [
"dlib",
"log",
"once_cell",
"pkg-config",
]
@ -4059,6 +4421,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"
@ -4570,7 +4956,7 @@ dependencies = [
"calloop",
"cfg_aliases 0.2.1",
"concurrent-queue",
"core-foundation",
"core-foundation 0.9.4",
"core-graphics",
"cursor-icon",
"dpi",

View File

@ -1,7 +1,7 @@
[package]
name = "the-labyrinth-of-echoes"
authors = ["Kristofers Solo <dev@kristofers.xyz>"]
version = "0.0.1"
version = "0.0.4"
edition = "2021"
[dependencies]
@ -17,6 +17,10 @@ tracing = { version = "0.1", features = [
"max_level_debug",
"release_max_level_warn",
] }
hexx = { version = "0.18", features = ["bevy_reflect", "grid"] }
bevy_prototype_lyon = "0.12"
bevy-inspector-egui = { version = "0.27", optional = true }
[features]
default = [
@ -27,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",
@ -35,6 +40,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.

20
justfile Normal file
View File

@ -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

View File

@ -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)),

View File

@ -1,8 +1,11 @@
mod asset_tracking;
pub mod audio;
#[cfg(feature = "demo")]
mod demo;
#[cfg(feature = "dev")]
mod dev_tools;
#[cfg(not(feature = "demo"))]
mod maze;
mod screens;
mod theme;
@ -37,7 +40,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,
@ -48,7 +51,7 @@ impl Plugin for AppPlugin {
})
.set(AudioPlugin {
global_volume: GlobalVolume {
volume: Volume::new(0.3),
volume: Volume::new(0.),
},
..default()
}),
@ -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"))]
maze::plugin::MazePlugin,
screens::plugin,
theme::plugin,
));
@ -84,7 +90,10 @@ enum AppSet {
fn spawn_camera(mut commands: Commands) {
commands.spawn((
Name::new("Camera"),
Camera2dBundle::default(),
Camera3dBundle {
transform: Transform::from_xyz(0., 300., 300.).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

220
src/maze/grid.rs Normal file
View File

@ -0,0 +1,220 @@
use bevy::{
color::palettes::css::{BLACK, GREEN, RED},
pbr::wireframe::{WireframeConfig, WireframePlugin},
prelude::*,
utils::hashbrown::HashMap,
};
use bevy_prototype_lyon::{
draw::{Fill, Stroke},
entity::ShapeBundle,
path::PathBuilder,
plugin::ShapePlugin,
};
use hexx::{EdgeDirection, Hex};
use rand::{prelude::SliceRandom, rngs::ThreadRng, thread_rng};
use super::{
resource::{Layout, MazeConfig, HEX_SIZE},
tile::{Tile, TileBundle, Walls},
};
pub(super) fn plugin(app: &mut App) {
app.add_plugins((ShapePlugin, WireframePlugin));
app.init_resource::<MazeConfig>();
app.init_resource::<Layout>();
app.insert_resource(WireframeConfig {
global: false,
..default()
});
}
pub(super) fn _spawn_hex_grid(mut commands: Commands, config: Res<MazeConfig>) {
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<MazeConfig>,
) {
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<Hex, (Entity, Tile, Walls)>,
current_hex: Hex,
rng: &mut ThreadRng,
) {
{
let (_, tile, _) = tiles.get_mut(&current_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<Hex, (Entity, Tile, Walls)>,
current_hex: Hex,
neighbor_hex: Hex,
direction: EdgeDirection,
) {
{
let (_, _, walls) = tiles.get_mut(&current_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: Vec3,
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.xy();
layout.hex_size = Vec2::splat(size);
layout.hex_to_world_pos(v.origin + v.direction)
})
.collect::<Vec<Vec2>>();
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<Layout>,
config: Res<MazeConfig>,
) {
for (tile, walls) in query.iter() {
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(),
_ => Color::srgb(0.8, 0.8, 0.8),
};
_add_hex_tile(
&mut commands,
world_pos,
HEX_SIZE,
tile,
walls,
fill_color,
&layout,
);
}
}

11
src/maze/mod.rs Normal file
View File

@ -0,0 +1,11 @@
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 fn spawn_grid(world: &mut World) {
MazePlugin.apply(world);
}

29
src/maze/plugin.rs Normal file
View File

@ -0,0 +1,29 @@
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);
// app.insert_resource(AmbientLight {
// brightness: f32::MAX,
// color: Color::WHITE,
// });
}
}
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);
}
}

146
src/maze/prism.rs Normal file
View File

@ -0,0 +1,146 @@
use bevy::prelude::*;
use core::f32;
use std::f32::consts::{FRAC_PI_2, FRAC_PI_3};
use super::{
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,
mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<StandardMaterial>>,
config: Res<MazeConfig>,
layout: Res<Layout>,
) {
let radius = config.radius as i32;
let assets = create_base_assets(&mut meshes, &mut materials, &config);
// spawn_single_hex_tile(&mut commands, &assets, &config);
commands
.spawn((
Name::new("Floor"),
SpatialBundle {
transform: Transform::from_translation(Vec3::ZERO),
..default()
},
))
.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(parent, &tile, &layout, &assets, &config);
}
}
});
}
fn spawn_single_hex_tile(
parent: &mut ChildBuilder,
tile: &Tile,
layout: &Res<Layout>,
assets: &MazeAssets,
config: &Res<MazeConfig>,
) {
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<MazeConfig>) {
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<Assets<Mesh>>,
materials: &mut ResMut<Assets<StandardMaterial>>,
config: &Res<MazeConfig>,
) -> 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).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<Mesh>,
wall_mesh: Handle<Mesh>,
hex_material: Handle<StandardMaterial>,
wall_material: Handle<StandardMaterial>,
}

51
src/maze/resource.rs Normal file
View File

@ -0,0 +1,51 @@
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 height: f32,
pub start_pos: Hex,
pub end_pos: Hex,
}
impl Default for MazeConfig {
fn default() -> Self {
let mut rng = thread_rng();
let radius = 11;
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,
height: 20.,
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 {
Self(HexLayout {
orientation: HexOrientation::Pointy,
hex_size: Vec2::splat(HEX_SIZE),
..default()
})
}
}

55
src/maze/tile.rs Normal file
View File

@ -0,0 +1,55 @@
use std::fmt::Display;
use bevy::prelude::*;
use hexx::{Hex, HexLayout};
#[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;
}
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 {
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])
}
}

View File

@ -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::maze::spawn_grid 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);

View File

@ -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<NextState<Screen>>) {
}
fn all_assets_loaded(
player_assets: Option<Res<PlayerAssets>>,
interaction_assets: Option<Res<InteractionAssets>>,
credits_music: Option<Res<CreditsMusic>>,
gameplay_music: Option<Res<GameplayMusic>>,
) -> 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()
}

View File

@ -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,