Merge branch 'clean-up'
This commit is contained in:
commit
26f2331743
10 changed files with 681 additions and 578 deletions
93
Cargo.lock
generated
93
Cargo.lock
generated
|
@ -152,14 +152,14 @@ checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bevy"
|
name = "bevy"
|
||||||
version = "0.5.0"
|
version = "0.6.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bevy_internal",
|
"bevy_internal",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bevy-crevice-derive"
|
name = "bevy-crevice-derive"
|
||||||
version = "0.5.0"
|
version = "0.6.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bevy_macro_utils",
|
"bevy_macro_utils",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
|
@ -169,7 +169,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bevy_app"
|
name = "bevy_app"
|
||||||
version = "0.5.0"
|
version = "0.6.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bevy_derive",
|
"bevy_derive",
|
||||||
"bevy_ecs",
|
"bevy_ecs",
|
||||||
|
@ -181,7 +181,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bevy_asset"
|
name = "bevy_asset"
|
||||||
version = "0.5.0"
|
version = "0.6.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"bevy_app",
|
"bevy_app",
|
||||||
|
@ -206,7 +206,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bevy_core"
|
name = "bevy_core"
|
||||||
version = "0.5.0"
|
version = "0.6.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bevy_app",
|
"bevy_app",
|
||||||
"bevy_derive",
|
"bevy_derive",
|
||||||
|
@ -220,7 +220,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bevy_core_pipeline"
|
name = "bevy_core_pipeline"
|
||||||
version = "0.5.0"
|
version = "0.6.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bevy_app",
|
"bevy_app",
|
||||||
"bevy_asset",
|
"bevy_asset",
|
||||||
|
@ -231,7 +231,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bevy_crevice"
|
name = "bevy_crevice"
|
||||||
version = "0.5.0"
|
version = "0.6.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bevy-crevice-derive",
|
"bevy-crevice-derive",
|
||||||
"bytemuck",
|
"bytemuck",
|
||||||
|
@ -241,7 +241,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bevy_derive"
|
name = "bevy_derive"
|
||||||
version = "0.5.0"
|
version = "0.6.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bevy_macro_utils",
|
"bevy_macro_utils",
|
||||||
"quote",
|
"quote",
|
||||||
|
@ -250,7 +250,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bevy_diagnostic"
|
name = "bevy_diagnostic"
|
||||||
version = "0.5.0"
|
version = "0.6.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bevy_app",
|
"bevy_app",
|
||||||
"bevy_core",
|
"bevy_core",
|
||||||
|
@ -261,7 +261,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bevy_ecs"
|
name = "bevy_ecs"
|
||||||
version = "0.5.0"
|
version = "0.6.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-channel",
|
"async-channel",
|
||||||
"bevy_ecs_macros",
|
"bevy_ecs_macros",
|
||||||
|
@ -277,7 +277,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bevy_ecs_macros"
|
name = "bevy_ecs_macros"
|
||||||
version = "0.5.0"
|
version = "0.6.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bevy_macro_utils",
|
"bevy_macro_utils",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
|
@ -287,7 +287,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bevy_gilrs"
|
name = "bevy_gilrs"
|
||||||
version = "0.5.0"
|
version = "0.6.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bevy_app",
|
"bevy_app",
|
||||||
"bevy_ecs",
|
"bevy_ecs",
|
||||||
|
@ -298,7 +298,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bevy_gltf"
|
name = "bevy_gltf"
|
||||||
version = "0.5.0"
|
version = "0.6.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"base64",
|
"base64",
|
||||||
|
@ -321,7 +321,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bevy_input"
|
name = "bevy_input"
|
||||||
version = "0.5.0"
|
version = "0.6.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bevy_app",
|
"bevy_app",
|
||||||
"bevy_ecs",
|
"bevy_ecs",
|
||||||
|
@ -331,7 +331,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bevy_internal"
|
name = "bevy_internal"
|
||||||
version = "0.5.0"
|
version = "0.6.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bevy_app",
|
"bevy_app",
|
||||||
"bevy_asset",
|
"bevy_asset",
|
||||||
|
@ -362,7 +362,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bevy_log"
|
name = "bevy_log"
|
||||||
version = "0.5.0"
|
version = "0.6.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"android_log-sys",
|
"android_log-sys",
|
||||||
"bevy_app",
|
"bevy_app",
|
||||||
|
@ -375,7 +375,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bevy_macro_utils"
|
name = "bevy_macro_utils"
|
||||||
version = "0.5.0"
|
version = "0.6.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cargo-manifest",
|
"cargo-manifest",
|
||||||
"quote",
|
"quote",
|
||||||
|
@ -384,7 +384,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bevy_math"
|
name = "bevy_math"
|
||||||
version = "0.5.0"
|
version = "0.6.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bevy_reflect",
|
"bevy_reflect",
|
||||||
"glam",
|
"glam",
|
||||||
|
@ -392,7 +392,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bevy_pbr"
|
name = "bevy_pbr"
|
||||||
version = "0.5.0"
|
version = "0.6.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bevy_app",
|
"bevy_app",
|
||||||
"bevy_asset",
|
"bevy_asset",
|
||||||
|
@ -411,7 +411,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bevy_reflect"
|
name = "bevy_reflect"
|
||||||
version = "0.5.0"
|
version = "0.6.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bevy_reflect_derive",
|
"bevy_reflect_derive",
|
||||||
"bevy_utils",
|
"bevy_utils",
|
||||||
|
@ -426,7 +426,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bevy_reflect_derive"
|
name = "bevy_reflect_derive"
|
||||||
version = "0.5.0"
|
version = "0.6.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bevy_macro_utils",
|
"bevy_macro_utils",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
|
@ -437,7 +437,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bevy_render"
|
name = "bevy_render"
|
||||||
version = "0.5.0"
|
version = "0.6.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"bevy_app",
|
"bevy_app",
|
||||||
|
@ -453,6 +453,7 @@ dependencies = [
|
||||||
"bevy_window",
|
"bevy_window",
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"codespan-reporting",
|
"codespan-reporting",
|
||||||
|
"copyless",
|
||||||
"downcast-rs",
|
"downcast-rs",
|
||||||
"futures-lite",
|
"futures-lite",
|
||||||
"hex",
|
"hex",
|
||||||
|
@ -470,7 +471,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bevy_scene"
|
name = "bevy_scene"
|
||||||
version = "0.5.0"
|
version = "0.6.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"bevy_app",
|
"bevy_app",
|
||||||
|
@ -487,7 +488,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bevy_sprite"
|
name = "bevy_sprite"
|
||||||
version = "0.5.0"
|
version = "0.6.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bevy_app",
|
"bevy_app",
|
||||||
"bevy_asset",
|
"bevy_asset",
|
||||||
|
@ -500,7 +501,9 @@ dependencies = [
|
||||||
"bevy_render",
|
"bevy_render",
|
||||||
"bevy_transform",
|
"bevy_transform",
|
||||||
"bevy_utils",
|
"bevy_utils",
|
||||||
|
"bitflags",
|
||||||
"bytemuck",
|
"bytemuck",
|
||||||
|
"copyless",
|
||||||
"guillotiere",
|
"guillotiere",
|
||||||
"rectangle-pack",
|
"rectangle-pack",
|
||||||
"serde",
|
"serde",
|
||||||
|
@ -509,7 +512,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bevy_tasks"
|
name = "bevy_tasks"
|
||||||
version = "0.5.0"
|
version = "0.6.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-channel",
|
"async-channel",
|
||||||
"async-executor",
|
"async-executor",
|
||||||
|
@ -521,7 +524,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bevy_text"
|
name = "bevy_text"
|
||||||
version = "0.5.0"
|
version = "0.6.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ab_glyph",
|
"ab_glyph",
|
||||||
"anyhow",
|
"anyhow",
|
||||||
|
@ -543,7 +546,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bevy_transform"
|
name = "bevy_transform"
|
||||||
version = "0.5.0"
|
version = "0.6.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bevy_app",
|
"bevy_app",
|
||||||
"bevy_ecs",
|
"bevy_ecs",
|
||||||
|
@ -555,7 +558,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bevy_ui"
|
name = "bevy_ui"
|
||||||
version = "0.5.0"
|
version = "0.6.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bevy_app",
|
"bevy_app",
|
||||||
"bevy_asset",
|
"bevy_asset",
|
||||||
|
@ -581,7 +584,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bevy_utils"
|
name = "bevy_utils"
|
||||||
version = "0.5.0"
|
version = "0.6.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ahash",
|
"ahash",
|
||||||
"bevy_derive",
|
"bevy_derive",
|
||||||
|
@ -593,7 +596,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bevy_window"
|
name = "bevy_window"
|
||||||
version = "0.5.0"
|
version = "0.6.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bevy_app",
|
"bevy_app",
|
||||||
"bevy_math",
|
"bevy_math",
|
||||||
|
@ -604,7 +607,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bevy_winit"
|
name = "bevy_winit"
|
||||||
version = "0.5.0"
|
version = "0.6.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"approx",
|
"approx",
|
||||||
"bevy_app",
|
"bevy_app",
|
||||||
|
@ -914,9 +917,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "crossbeam-channel"
|
name = "crossbeam-channel"
|
||||||
version = "0.5.1"
|
version = "0.5.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "06ed27e177f16d65f0f0c22a213e17c696ace5dd64b14258b52f9417ccb52db4"
|
checksum = "e54ea8bc3fb1ee042f5aace6e3c6e025d3874866da222930f70ce62aceba0bfa"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if 1.0.0",
|
"cfg-if 1.0.0",
|
||||||
"crossbeam-utils",
|
"crossbeam-utils",
|
||||||
|
@ -935,9 +938,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "crossbeam-epoch"
|
name = "crossbeam-epoch"
|
||||||
version = "0.9.5"
|
version = "0.9.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4ec02e091aa634e2c3ada4a392989e7c3116673ef0ac5b72232439094d73b7fd"
|
checksum = "97242a70df9b89a65d0b6df3c4bf5b9ce03c5b7309019777fbde37e7537f8762"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if 1.0.0",
|
"cfg-if 1.0.0",
|
||||||
"crossbeam-utils",
|
"crossbeam-utils",
|
||||||
|
@ -948,9 +951,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "crossbeam-queue"
|
name = "crossbeam-queue"
|
||||||
version = "0.3.2"
|
version = "0.3.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9b10ddc024425c88c2ad148c1b0fd53f4c6d38db9697c9f1588381212fa657c9"
|
checksum = "b979d76c9fcb84dffc80a73f7290da0f83e4c95773494674cb44b76d13a7a110"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if 1.0.0",
|
"cfg-if 1.0.0",
|
||||||
"crossbeam-utils",
|
"crossbeam-utils",
|
||||||
|
@ -958,9 +961,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "crossbeam-utils"
|
name = "crossbeam-utils"
|
||||||
version = "0.8.5"
|
version = "0.8.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d82cfc11ce7f2c3faef78d8a684447b40d503d9681acebed6cb728d45940c4db"
|
checksum = "cfcae03edb34f947e64acdb1c33ec169824e20657e9ecb61cef6c8c74dcb8120"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if 1.0.0",
|
"cfg-if 1.0.0",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
|
@ -1370,7 +1373,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "heron"
|
name = "heron"
|
||||||
version = "0.12.1"
|
version = "1.0.1-rc.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bevy",
|
"bevy",
|
||||||
"cfg_aliases",
|
"cfg_aliases",
|
||||||
|
@ -1381,7 +1384,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "heron_core"
|
name = "heron_core"
|
||||||
version = "0.12.1"
|
version = "1.0.1-rc.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bevy",
|
"bevy",
|
||||||
"cfg_aliases",
|
"cfg_aliases",
|
||||||
|
@ -1390,7 +1393,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "heron_macros"
|
name = "heron_macros"
|
||||||
version = "0.12.1"
|
version = "1.0.1-rc.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"heron_core",
|
"heron_core",
|
||||||
"quote",
|
"quote",
|
||||||
|
@ -1399,7 +1402,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "heron_rapier"
|
name = "heron_rapier"
|
||||||
version = "0.12.1"
|
version = "1.0.1-rc.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bevy",
|
"bevy",
|
||||||
"cfg_aliases",
|
"cfg_aliases",
|
||||||
|
@ -1455,9 +1458,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "indexmap"
|
name = "indexmap"
|
||||||
version = "1.7.0"
|
version = "1.8.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bc633605454125dec4b66843673f01c7df2b89479b32e0ed634e43a91cff62a5"
|
checksum = "282a6247722caba404c065016bbfa522806e51714c34f5dfc3e4a3a46fcb4223"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"autocfg",
|
"autocfg",
|
||||||
"hashbrown",
|
"hashbrown",
|
||||||
|
|
63
src/camera.rs
Normal file
63
src/camera.rs
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
use bevy::prelude::*;
|
||||||
|
|
||||||
|
use crate::{geometry::CyberBike, input::InputState, physics::MovementSettings};
|
||||||
|
|
||||||
|
pub(crate) const CAM_DIST: f32 = 50.0;
|
||||||
|
|
||||||
|
#[derive(Component, Debug)]
|
||||||
|
pub struct CyberCam;
|
||||||
|
|
||||||
|
fn setup_cybercam(mut commands: Commands) {
|
||||||
|
use crate::geometry::PLAYER_DIST;
|
||||||
|
commands
|
||||||
|
.spawn_bundle(PerspectiveCameraBundle {
|
||||||
|
transform: Transform::from_xyz(PLAYER_DIST + CAM_DIST, 0.0, 0.0)
|
||||||
|
.looking_at(Vec3::ZERO, Vec3::Y),
|
||||||
|
..Default::default()
|
||||||
|
})
|
||||||
|
.insert(CyberCam);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn follow_player(
|
||||||
|
bike_query: Query<(&Transform, &CyberBike), Without<CyberCam>>,
|
||||||
|
mut cam_query: Query<(&mut Transform, &CyberCam), Without<CyberBike>>,
|
||||||
|
) {
|
||||||
|
let (bike_xform, _) = bike_query.single();
|
||||||
|
let up = bike_xform.translation.normalize();
|
||||||
|
|
||||||
|
let look_at = bike_xform.translation;
|
||||||
|
let cam_pos = bike_xform.translation + (bike_xform.back() * CAM_DIST * 1.3) + (up * CAM_DIST);
|
||||||
|
|
||||||
|
let (mut cam_xform, _) = cam_query.single_mut();
|
||||||
|
cam_xform.translation = cam_pos;
|
||||||
|
cam_xform.look_at(look_at, up);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn player_look(
|
||||||
|
settings: Res<MovementSettings>,
|
||||||
|
windows: Res<Windows>,
|
||||||
|
time: Res<Time>,
|
||||||
|
istate: Res<InputState>,
|
||||||
|
mut query: Query<(&mut Transform, &CyberBike)>,
|
||||||
|
) {
|
||||||
|
let window = windows.get_primary().unwrap();
|
||||||
|
let window_scale = window.height().min(window.width());
|
||||||
|
let dt = time.delta_seconds();
|
||||||
|
let (mut transform, _) = query.single_mut();
|
||||||
|
|
||||||
|
let d_alt = (settings.sensitivity * dt * window_scale * istate.pitch).to_radians();
|
||||||
|
let d_az = (settings.sensitivity * dt * window_scale * istate.yaw).to_radians();
|
||||||
|
let rotation = Quat::from_axis_angle(transform.local_y(), d_az)
|
||||||
|
* Quat::from_axis_angle(transform.local_x(), d_alt);
|
||||||
|
|
||||||
|
transform.rotate(rotation);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct CyberCamPlugin;
|
||||||
|
impl Plugin for CyberCamPlugin {
|
||||||
|
fn build(&self, app: &mut bevy::prelude::App) {
|
||||||
|
app.add_startup_system(setup_cybercam)
|
||||||
|
.add_system(follow_player)
|
||||||
|
.add_system(player_look);
|
||||||
|
}
|
||||||
|
}
|
295
src/flycam.rs
295
src/flycam.rs
|
@ -1,295 +0,0 @@
|
||||||
use bevy::{
|
|
||||||
app::{Events, ManualEventReader},
|
|
||||||
input::{
|
|
||||||
gamepad::{GamepadAxisType, GamepadEvent, GamepadEventType},
|
|
||||||
Input,
|
|
||||||
},
|
|
||||||
prelude::*,
|
|
||||||
utils::tracing::info,
|
|
||||||
};
|
|
||||||
use heron::{
|
|
||||||
prelude::{CollisionShape, RigidBody},
|
|
||||||
CollisionEvent,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const PLANET_RADIUS: f32 = 150.0;
|
|
||||||
|
|
||||||
const PLAYER_DIST: f32 = PLANET_RADIUS + 100.0;
|
|
||||||
const CAM_DIST: f32 = 50.0;
|
|
||||||
|
|
||||||
#[derive(Component, Default)]
|
|
||||||
struct PlayerState {
|
|
||||||
velocity: Vec3,
|
|
||||||
colliding: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Default)]
|
|
||||||
struct InputState {
|
|
||||||
event_reader: ManualEventReader<GamepadEvent>,
|
|
||||||
pitch: f32,
|
|
||||||
yaw: f32,
|
|
||||||
throttle: f32,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Mouse sensitivity and movement speed
|
|
||||||
pub struct MovementSettings {
|
|
||||||
pub sensitivity: f32,
|
|
||||||
pub accel: f32,
|
|
||||||
pub drag: f32,
|
|
||||||
pub gravity: f32,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for MovementSettings {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self {
|
|
||||||
sensitivity: 1.0,
|
|
||||||
accel: 40.,
|
|
||||||
drag: 0.0005,
|
|
||||||
gravity: 10.0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Used in queries when you want flycams and not other cameras
|
|
||||||
#[derive(Component, Debug)]
|
|
||||||
pub struct FlyCam;
|
|
||||||
|
|
||||||
#[derive(Component, Debug)]
|
|
||||||
pub struct CyberBike;
|
|
||||||
|
|
||||||
#[derive(Component)]
|
|
||||||
struct UpText;
|
|
||||||
|
|
||||||
/// Spawns the `Camera3dBundle` to be controlled
|
|
||||||
fn setup_player(mut commands: Commands, asset_server: Res<AssetServer>) {
|
|
||||||
commands
|
|
||||||
.spawn_bundle(PerspectiveCameraBundle {
|
|
||||||
transform: Transform::from_xyz(PLAYER_DIST + CAM_DIST, 0.0, 0.0)
|
|
||||||
.looking_at(Vec3::ZERO, Vec3::Y),
|
|
||||||
..Default::default()
|
|
||||||
})
|
|
||||||
.insert(FlyCam);
|
|
||||||
|
|
||||||
commands
|
|
||||||
.spawn_bundle((
|
|
||||||
Transform {
|
|
||||||
translation: Vec3::new(PLAYER_DIST, 0.0, 0.0),
|
|
||||||
..Default::default()
|
|
||||||
}
|
|
||||||
.looking_at(Vec3::ZERO, Vec3::Y),
|
|
||||||
GlobalTransform::identity(),
|
|
||||||
))
|
|
||||||
.with_children(|rider| {
|
|
||||||
rider.spawn_scene(asset_server.load("cyber-bike_no_y_up.glb#Scene0"));
|
|
||||||
})
|
|
||||||
.insert(CyberBike)
|
|
||||||
.insert(RigidBody::Dynamic)
|
|
||||||
.insert(CollisionShape::Cone {
|
|
||||||
half_height: 2.0,
|
|
||||||
radius: 0.8,
|
|
||||||
})
|
|
||||||
.insert(PlayerState::default());
|
|
||||||
}
|
|
||||||
|
|
||||||
fn setup_ui(mut commands: Commands, asset_server: Res<AssetServer>) {
|
|
||||||
commands.spawn_bundle(UiCameraBundle::default());
|
|
||||||
|
|
||||||
commands
|
|
||||||
.spawn_bundle(TextBundle {
|
|
||||||
style: Style {
|
|
||||||
align_self: AlignSelf::FlexEnd,
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
// Use `Text` directly
|
|
||||||
text: Text {
|
|
||||||
// Construct a `Vec` of `TextSection`s
|
|
||||||
sections: vec![TextSection {
|
|
||||||
value: "".to_string(),
|
|
||||||
style: TextStyle {
|
|
||||||
font: asset_server.load("fonts/FiraMono-Medium.ttf"),
|
|
||||||
font_size: 40.0,
|
|
||||||
color: Color::GOLD,
|
|
||||||
},
|
|
||||||
}],
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
..Default::default()
|
|
||||||
})
|
|
||||||
.insert(UpText);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn ui_system(pstate_query: Query<&PlayerState>, mut text_query: Query<&mut Text, With<UpText>>) {
|
|
||||||
let mut text = text_query.single_mut();
|
|
||||||
let pstate = pstate_query.single();
|
|
||||||
text.sections[0].value = format!("{:.2}", pstate.velocity.length());
|
|
||||||
}
|
|
||||||
|
|
||||||
fn player_move(
|
|
||||||
time: Res<Time>,
|
|
||||||
mut bike_query: Query<(&mut Transform, &PlayerState), Without<FlyCam>>,
|
|
||||||
mut cam_query: Query<(&mut Transform, &FlyCam), Without<PlayerState>>,
|
|
||||||
) {
|
|
||||||
let dt = time.delta_seconds();
|
|
||||||
|
|
||||||
let (mut bike_xform, player_state) = bike_query.single_mut();
|
|
||||||
let up = bike_xform.translation.normalize();
|
|
||||||
let cam_up = bike_xform.up();
|
|
||||||
let cos = up.dot(cam_up);
|
|
||||||
|
|
||||||
let theta = cos.acos();
|
|
||||||
let rate = if !theta.is_normal() {
|
|
||||||
0.0
|
|
||||||
} else if theta.is_sign_negative() {
|
|
||||||
-0.4
|
|
||||||
} else {
|
|
||||||
0.4
|
|
||||||
} * dt;
|
|
||||||
let angle = if rate.is_sign_negative() {
|
|
||||||
rate.max(theta)
|
|
||||||
} else {
|
|
||||||
rate.min(theta)
|
|
||||||
};
|
|
||||||
|
|
||||||
let rot = Quat::from_axis_angle(cam_up.cross(up).normalize(), angle);
|
|
||||||
|
|
||||||
if rot.is_finite() && theta.abs() > 0.0085 {
|
|
||||||
bike_xform.rotate(rot);
|
|
||||||
}
|
|
||||||
|
|
||||||
if player_state.velocity.is_finite() {
|
|
||||||
bike_xform.translation += player_state.velocity * dt;
|
|
||||||
}
|
|
||||||
|
|
||||||
let look_at = bike_xform.translation;
|
|
||||||
let cam_pos = bike_xform.translation + (bike_xform.back() * CAM_DIST * 1.3) + (up * CAM_DIST);
|
|
||||||
|
|
||||||
let (mut cam_xform, _) = cam_query.single_mut();
|
|
||||||
cam_xform.translation = cam_pos;
|
|
||||||
cam_xform.look_at(look_at, up);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn player_look(
|
|
||||||
settings: Res<MovementSettings>,
|
|
||||||
windows: Res<Windows>,
|
|
||||||
events: Res<Events<GamepadEvent>>,
|
|
||||||
time: Res<Time>,
|
|
||||||
mut istate: ResMut<InputState>,
|
|
||||||
mut query: Query<(&mut Transform, &mut PlayerState)>,
|
|
||||||
) {
|
|
||||||
let window = windows.get_primary().unwrap();
|
|
||||||
let window_scale = window.height().min(window.width());
|
|
||||||
let dt = time.delta_seconds();
|
|
||||||
let (mut transform, mut pstate) = query.single_mut();
|
|
||||||
let mut vel = pstate.velocity;
|
|
||||||
|
|
||||||
if pstate.velocity.is_finite() {
|
|
||||||
for GamepadEvent(_, ev) in istate.event_reader.iter(&events) {
|
|
||||||
match *ev {
|
|
||||||
GamepadEventType::ButtonChanged(GamepadButtonType::RightTrigger2, val) => {
|
|
||||||
istate.throttle = val;
|
|
||||||
}
|
|
||||||
GamepadEventType::ButtonChanged(GamepadButtonType::LeftTrigger2, val) => {
|
|
||||||
istate.throttle = -val;
|
|
||||||
}
|
|
||||||
GamepadEventType::ButtonChanged(GamepadButtonType::East, val) => {
|
|
||||||
if val > 0.5 {
|
|
||||||
vel = Vec3::ZERO;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
GamepadEventType::AxisChanged(GamepadAxisType::LeftStickX, val) => {
|
|
||||||
istate.yaw = -val;
|
|
||||||
}
|
|
||||||
GamepadEventType::AxisChanged(GamepadAxisType::LeftStickY, val) => {
|
|
||||||
istate.pitch = -val;
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
info!("unhandled gamepad event: {:?}", ev);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let accel = settings.accel * dt * istate.throttle;
|
|
||||||
|
|
||||||
vel += transform.forward() * accel;
|
|
||||||
|
|
||||||
// drag
|
|
||||||
let v2 = vel.length_squared().min(100_000.0);
|
|
||||||
if v2 < 0.05 {
|
|
||||||
vel = Vec3::ZERO;
|
|
||||||
} else {
|
|
||||||
let drag = vel * settings.drag * v2.sqrt() * time.delta_seconds();
|
|
||||||
vel -= drag;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
vel = Vec3::ZERO;
|
|
||||||
}
|
|
||||||
|
|
||||||
let d_alt = (settings.sensitivity * dt * window_scale * istate.pitch).to_radians();
|
|
||||||
let d_az = (settings.sensitivity * dt * window_scale * istate.yaw).to_radians();
|
|
||||||
let rotation = Quat::from_axis_angle(transform.local_y(), d_az)
|
|
||||||
* Quat::from_axis_angle(transform.local_x(), d_alt);
|
|
||||||
|
|
||||||
transform.rotate(rotation);
|
|
||||||
|
|
||||||
pstate.velocity = vel;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn collision_detection(
|
|
||||||
mut events: EventReader<CollisionEvent>,
|
|
||||||
mut query: Query<&mut PlayerState>,
|
|
||||||
) {
|
|
||||||
let mut pstate = query.single_mut();
|
|
||||||
|
|
||||||
for event in events.iter() {
|
|
||||||
if let CollisionEvent::Started(_, _) = event {
|
|
||||||
pstate.colliding = true;
|
|
||||||
} else {
|
|
||||||
pstate.colliding = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn gravity_collision_reaction(
|
|
||||||
time: Res<Time>,
|
|
||||||
settings: Res<MovementSettings>,
|
|
||||||
mut query: Query<(&mut PlayerState, &Transform)>,
|
|
||||||
) {
|
|
||||||
let dt = time.delta_seconds();
|
|
||||||
let g = settings.gravity;
|
|
||||||
let (mut pstate, xform) = query.single_mut();
|
|
||||||
|
|
||||||
// first gravity
|
|
||||||
let down = -xform.translation.normalize();
|
|
||||||
let dvel = down * g * dt;
|
|
||||||
let mut vel = if pstate.velocity.is_finite() {
|
|
||||||
pstate.velocity + dvel
|
|
||||||
} else {
|
|
||||||
dvel
|
|
||||||
};
|
|
||||||
|
|
||||||
// now see if we're currently colliding
|
|
||||||
if pstate.colliding {
|
|
||||||
let dvel = down * vel.dot(down) * 1.02;
|
|
||||||
vel -= dvel;
|
|
||||||
}
|
|
||||||
|
|
||||||
pstate.velocity = vel;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Contains everything needed to add first-person fly camera behavior to your
|
|
||||||
/// game
|
|
||||||
pub struct PlayerPlugin;
|
|
||||||
impl Plugin for PlayerPlugin {
|
|
||||||
fn build(&self, app: &mut bevy::prelude::App) {
|
|
||||||
app.init_resource::<PlayerState>()
|
|
||||||
.init_resource::<MovementSettings>()
|
|
||||||
.init_resource::<InputState>()
|
|
||||||
.add_startup_system(setup_player)
|
|
||||||
.add_startup_system(setup_ui)
|
|
||||||
.add_system(ui_system)
|
|
||||||
.add_system(player_move.label("move"))
|
|
||||||
.add_system(player_look.after("move"))
|
|
||||||
.add_system(collision_detection)
|
|
||||||
.add_system(gravity_collision_reaction);
|
|
||||||
}
|
|
||||||
}
|
|
67
src/geometry.rs
Normal file
67
src/geometry.rs
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
use bevy::prelude::*;
|
||||||
|
use heron::prelude::{CollisionShape, RigidBody};
|
||||||
|
|
||||||
|
pub const PLANET_RADIUS: f32 = 150.0;
|
||||||
|
pub(crate) const PLAYER_DIST: f32 = PLANET_RADIUS + 100.0;
|
||||||
|
|
||||||
|
pub struct CyberGeomPlugin;
|
||||||
|
|
||||||
|
impl Plugin for CyberGeomPlugin {
|
||||||
|
fn build(&self, app: &mut App) {
|
||||||
|
app.add_startup_system(setup_giant_sphere)
|
||||||
|
.add_startup_system(setup_player);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Component, Debug)]
|
||||||
|
pub struct CyberBike;
|
||||||
|
|
||||||
|
fn setup_giant_sphere(
|
||||||
|
mut commands: Commands,
|
||||||
|
mut meshes: ResMut<Assets<Mesh>>,
|
||||||
|
mut materials: ResMut<Assets<StandardMaterial>>,
|
||||||
|
) {
|
||||||
|
// world
|
||||||
|
commands
|
||||||
|
.spawn_bundle(PbrBundle {
|
||||||
|
mesh: meshes.add(Mesh::from(shape::Icosphere {
|
||||||
|
radius: PLANET_RADIUS,
|
||||||
|
subdivisions: 6,
|
||||||
|
})),
|
||||||
|
material: materials.add(StandardMaterial {
|
||||||
|
base_color: Color::GRAY,
|
||||||
|
metallic: 0.7,
|
||||||
|
perceptual_roughness: 0.5,
|
||||||
|
..Default::default()
|
||||||
|
}),
|
||||||
|
|
||||||
|
..Default::default()
|
||||||
|
})
|
||||||
|
.insert(RigidBody::Static)
|
||||||
|
.insert(CollisionShape::Sphere {
|
||||||
|
radius: PLANET_RADIUS,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn setup_player(mut commands: Commands, asset_server: Res<AssetServer>) {
|
||||||
|
use crate::physics::PlayerState;
|
||||||
|
commands
|
||||||
|
.spawn_bundle((
|
||||||
|
Transform {
|
||||||
|
translation: Vec3::new(PLAYER_DIST, 0.0, 0.0),
|
||||||
|
..Default::default()
|
||||||
|
}
|
||||||
|
.looking_at(Vec3::ZERO, Vec3::Y),
|
||||||
|
GlobalTransform::identity(),
|
||||||
|
))
|
||||||
|
.with_children(|rider| {
|
||||||
|
rider.spawn_scene(asset_server.load("cyber-bike_no_y_up.glb#Scene0"));
|
||||||
|
})
|
||||||
|
.insert(CyberBike)
|
||||||
|
.insert(RigidBody::Dynamic)
|
||||||
|
.insert(CollisionShape::Cone {
|
||||||
|
half_height: 2.0,
|
||||||
|
radius: 0.8,
|
||||||
|
})
|
||||||
|
.insert(PlayerState::default());
|
||||||
|
}
|
49
src/input.rs
Normal file
49
src/input.rs
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
use bevy::{
|
||||||
|
app::{Events, ManualEventReader},
|
||||||
|
prelude::*,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub(crate) struct InputState {
|
||||||
|
event_reader: ManualEventReader<GamepadEvent>,
|
||||||
|
pub pitch: f32,
|
||||||
|
pub yaw: f32,
|
||||||
|
pub throttle: f32,
|
||||||
|
pub brake: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update_input(events: Res<Events<GamepadEvent>>, mut istate: ResMut<InputState>) {
|
||||||
|
for GamepadEvent(_, ev) in istate.event_reader.iter(&events) {
|
||||||
|
match *ev {
|
||||||
|
GamepadEventType::ButtonChanged(GamepadButtonType::RightTrigger2, val) => {
|
||||||
|
istate.throttle = val;
|
||||||
|
}
|
||||||
|
GamepadEventType::ButtonChanged(GamepadButtonType::LeftTrigger2, val) => {
|
||||||
|
istate.throttle = -val;
|
||||||
|
}
|
||||||
|
GamepadEventType::ButtonChanged(GamepadButtonType::East, val) => {
|
||||||
|
if val > 0.5 {
|
||||||
|
istate.brake = true;
|
||||||
|
} else {
|
||||||
|
istate.brake = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
GamepadEventType::AxisChanged(GamepadAxisType::LeftStickX, val) => {
|
||||||
|
istate.yaw = -val;
|
||||||
|
}
|
||||||
|
GamepadEventType::AxisChanged(GamepadAxisType::LeftStickY, val) => {
|
||||||
|
istate.pitch = -val;
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
info!("unhandled gamepad event: {:?}", ev);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct CyberInputPlugin;
|
||||||
|
impl Plugin for CyberInputPlugin {
|
||||||
|
fn build(&self, app: &mut App) {
|
||||||
|
app.init_resource::<InputState>().add_system(update_input);
|
||||||
|
}
|
||||||
|
}
|
15
src/lib.rs
15
src/lib.rs
|
@ -1 +1,14 @@
|
||||||
pub mod flycam;
|
use bevy::prelude::{ResMut, Windows};
|
||||||
|
|
||||||
|
pub mod camera;
|
||||||
|
pub mod geometry;
|
||||||
|
pub mod input;
|
||||||
|
pub mod lights;
|
||||||
|
pub mod physics;
|
||||||
|
pub mod ui;
|
||||||
|
|
||||||
|
pub fn disable_mouse_trap(mut windows: ResMut<Windows>) {
|
||||||
|
let window = windows.get_primary_mut().unwrap();
|
||||||
|
window.set_cursor_lock_mode(false);
|
||||||
|
window.set_cursor_visibility(true);
|
||||||
|
}
|
||||||
|
|
209
src/lights.rs
Normal file
209
src/lights.rs
Normal file
|
@ -0,0 +1,209 @@
|
||||||
|
use bevy::prelude::*;
|
||||||
|
|
||||||
|
use crate::geometry::PLANET_RADIUS;
|
||||||
|
|
||||||
|
pub const LIGHT_RANGE: f32 = PLANET_RADIUS * 0.6;
|
||||||
|
pub const LIGHT_DIST: f32 = PLANET_RADIUS * 1.2;
|
||||||
|
|
||||||
|
pub struct CyberSpaceLightsPlugin;
|
||||||
|
|
||||||
|
impl Plugin for CyberSpaceLightsPlugin {
|
||||||
|
fn build(&self, app: &mut App) {
|
||||||
|
app.add_startup_system(setup).add_system(animate_lights);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Component)]
|
||||||
|
struct Animate;
|
||||||
|
|
||||||
|
fn setup(
|
||||||
|
mut commands: Commands,
|
||||||
|
mut meshes: ResMut<Assets<Mesh>>,
|
||||||
|
mut materials: ResMut<Assets<StandardMaterial>>,
|
||||||
|
) {
|
||||||
|
let red_light = PointLight {
|
||||||
|
intensity: 1_000.0,
|
||||||
|
range: LIGHT_RANGE,
|
||||||
|
color: Color::RED,
|
||||||
|
radius: 1.0,
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
let blue_light = PointLight {
|
||||||
|
intensity: 1_000.0,
|
||||||
|
range: LIGHT_RANGE,
|
||||||
|
color: Color::BLUE,
|
||||||
|
radius: 1.0,
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
let purple_light = PointLight {
|
||||||
|
intensity: 1_000.0,
|
||||||
|
range: LIGHT_RANGE,
|
||||||
|
color: Color::PURPLE,
|
||||||
|
radius: 1.0,
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
commands.insert_resource(AmbientLight {
|
||||||
|
color: Color::WHITE,
|
||||||
|
brightness: 0.32,
|
||||||
|
});
|
||||||
|
|
||||||
|
// east light
|
||||||
|
commands
|
||||||
|
.spawn_bundle(PointLightBundle {
|
||||||
|
transform: Transform::from_xyz(LIGHT_DIST, 0.0, 0.0),
|
||||||
|
point_light: purple_light,
|
||||||
|
..Default::default()
|
||||||
|
})
|
||||||
|
.with_children(|builder| {
|
||||||
|
builder.spawn_bundle(PbrBundle {
|
||||||
|
mesh: meshes.add(Mesh::from(shape::UVSphere {
|
||||||
|
radius: 10.0,
|
||||||
|
..Default::default()
|
||||||
|
})),
|
||||||
|
material: materials.add(StandardMaterial {
|
||||||
|
base_color: Color::PURPLE,
|
||||||
|
emissive: Color::rgba_linear(50.0, 0.0, 50.0, 0.0),
|
||||||
|
..Default::default()
|
||||||
|
}),
|
||||||
|
..Default::default()
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.insert(Animate);
|
||||||
|
|
||||||
|
// west light
|
||||||
|
commands
|
||||||
|
.spawn_bundle(PointLightBundle {
|
||||||
|
transform: Transform::from_xyz(-LIGHT_DIST, 0.0, 0.0),
|
||||||
|
point_light: purple_light,
|
||||||
|
..Default::default()
|
||||||
|
})
|
||||||
|
.with_children(|builder| {
|
||||||
|
builder.spawn_bundle(PbrBundle {
|
||||||
|
mesh: meshes.add(Mesh::from(shape::UVSphere {
|
||||||
|
radius: 10.0,
|
||||||
|
..Default::default()
|
||||||
|
})),
|
||||||
|
material: materials.add(StandardMaterial {
|
||||||
|
base_color: Color::PURPLE,
|
||||||
|
emissive: Color::rgba_linear(50.0, 0.0, 50.0, 0.0),
|
||||||
|
..Default::default()
|
||||||
|
}),
|
||||||
|
..Default::default()
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.insert(Animate);
|
||||||
|
// north light
|
||||||
|
commands
|
||||||
|
.spawn_bundle(PointLightBundle {
|
||||||
|
transform: Transform::from_xyz(0.0, 0.0, LIGHT_DIST),
|
||||||
|
point_light: purple_light,
|
||||||
|
..Default::default()
|
||||||
|
})
|
||||||
|
.with_children(|builder| {
|
||||||
|
builder.spawn_bundle(PbrBundle {
|
||||||
|
mesh: meshes.add(Mesh::from(shape::UVSphere {
|
||||||
|
radius: 10.0,
|
||||||
|
..Default::default()
|
||||||
|
})),
|
||||||
|
material: materials.add(StandardMaterial {
|
||||||
|
base_color: Color::PURPLE,
|
||||||
|
emissive: Color::rgba_linear(50.0, 0.0, 50.0, 0.0),
|
||||||
|
..Default::default()
|
||||||
|
}),
|
||||||
|
..Default::default()
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.insert(Animate);
|
||||||
|
// south light
|
||||||
|
commands
|
||||||
|
.spawn_bundle(PointLightBundle {
|
||||||
|
transform: Transform::from_xyz(0.0, 0.0, -LIGHT_DIST),
|
||||||
|
point_light: purple_light,
|
||||||
|
..Default::default()
|
||||||
|
})
|
||||||
|
.with_children(|builder| {
|
||||||
|
builder.spawn_bundle(PbrBundle {
|
||||||
|
mesh: meshes.add(Mesh::from(shape::UVSphere {
|
||||||
|
radius: 10.0,
|
||||||
|
..Default::default()
|
||||||
|
})),
|
||||||
|
material: materials.add(StandardMaterial {
|
||||||
|
base_color: Color::PURPLE,
|
||||||
|
emissive: Color::rgba_linear(50.0, 0.0, 50.0, 0.0),
|
||||||
|
..Default::default()
|
||||||
|
}),
|
||||||
|
..Default::default()
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.insert(Animate);
|
||||||
|
// up light
|
||||||
|
commands
|
||||||
|
.spawn_bundle(PointLightBundle {
|
||||||
|
transform: Transform::from_xyz(0.0, LIGHT_DIST, 0.0),
|
||||||
|
point_light: red_light,
|
||||||
|
..Default::default()
|
||||||
|
})
|
||||||
|
.with_children(|builder| {
|
||||||
|
builder.spawn_bundle(PbrBundle {
|
||||||
|
mesh: meshes.add(Mesh::from(shape::Icosphere {
|
||||||
|
radius: 10.0,
|
||||||
|
subdivisions: 2,
|
||||||
|
})),
|
||||||
|
material: materials.add(StandardMaterial {
|
||||||
|
base_color: Color::RED,
|
||||||
|
emissive: Color::rgba_linear(100.0, 0.0, 0.0, 0.0),
|
||||||
|
..Default::default()
|
||||||
|
}),
|
||||||
|
..Default::default()
|
||||||
|
});
|
||||||
|
});
|
||||||
|
// down light
|
||||||
|
commands
|
||||||
|
.spawn_bundle(PointLightBundle {
|
||||||
|
transform: Transform::from_xyz(0.0, -LIGHT_DIST, 0.0),
|
||||||
|
point_light: blue_light,
|
||||||
|
..Default::default()
|
||||||
|
})
|
||||||
|
.with_children(|builder| {
|
||||||
|
builder.spawn_bundle(PbrBundle {
|
||||||
|
mesh: meshes.add(Mesh::from(shape::Icosphere {
|
||||||
|
radius: 10.0,
|
||||||
|
subdivisions: 2,
|
||||||
|
})),
|
||||||
|
material: materials.add(StandardMaterial {
|
||||||
|
base_color: Color::BLUE,
|
||||||
|
emissive: Color::rgba_linear(0.0, 0.0, 100.0, 0.0),
|
||||||
|
..Default::default()
|
||||||
|
}),
|
||||||
|
..Default::default()
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn animate_lights(
|
||||||
|
time: Res<Time>,
|
||||||
|
mut query: Query<&mut Transform, (With<PointLight>, With<Animate>)>,
|
||||||
|
) {
|
||||||
|
let dt = time.delta_seconds();
|
||||||
|
for mut transform in query.iter_mut() {
|
||||||
|
let translation = &transform.translation;
|
||||||
|
let x = translation.x;
|
||||||
|
let y = translation.y;
|
||||||
|
let z = if translation.z.abs() < 0.1 {
|
||||||
|
translation.z + 0.15
|
||||||
|
} else {
|
||||||
|
translation.z
|
||||||
|
};
|
||||||
|
|
||||||
|
let rads = 10.0f32.to_radians();
|
||||||
|
let anim_rate = rads * dt;
|
||||||
|
let theta = z.atan2(x) + anim_rate;
|
||||||
|
let x_new = LIGHT_DIST * theta.cos();
|
||||||
|
let z_new = LIGHT_DIST * theta.sin();
|
||||||
|
|
||||||
|
*transform = Transform::from_xyz(x_new, y, z_new);
|
||||||
|
}
|
||||||
|
}
|
260
src/main.rs
260
src/main.rs
|
@ -1,247 +1,33 @@
|
||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
use cyber_rider::flycam::{MovementSettings, PlayerPlugin, PLANET_RADIUS};
|
use cyber_rider::{
|
||||||
use heron::prelude::*;
|
camera::CyberCamPlugin,
|
||||||
|
disable_mouse_trap,
|
||||||
|
geometry::CyberGeomPlugin,
|
||||||
|
input::CyberInputPlugin,
|
||||||
|
lights::CyberSpaceLightsPlugin,
|
||||||
|
physics::{CyberPhysicsPlugin, MovementSettings},
|
||||||
|
ui::CyberUIPlugin,
|
||||||
|
};
|
||||||
|
|
||||||
const LIGHT_RANGE: f32 = PLANET_RADIUS * 0.6;
|
const MOVEMENT_SETTINGS: MovementSettings = MovementSettings {
|
||||||
const LIGHT_DIST: f32 = PLANET_RADIUS * 1.2;
|
sensitivity: 0.3, // default: 1.0
|
||||||
|
accel: 20.0, // default: 40.0
|
||||||
|
drag: 0.0001, // default: 0.0005
|
||||||
|
gravity: 10.0, // default: 10.0
|
||||||
|
};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
App::new()
|
App::new()
|
||||||
.insert_resource(Msaa { samples: 4 })
|
.insert_resource(Msaa { samples: 4 })
|
||||||
.add_plugins(DefaultPlugins)
|
.add_plugins(DefaultPlugins)
|
||||||
.add_plugin(PlayerPlugin)
|
.add_plugin(CyberGeomPlugin)
|
||||||
.add_plugin(PhysicsPlugin::default())
|
.add_plugin(CyberInputPlugin)
|
||||||
.insert_resource(MovementSettings {
|
.add_plugin(CyberPhysicsPlugin)
|
||||||
sensitivity: 0.3, // default: 1.0
|
.insert_resource(MOVEMENT_SETTINGS)
|
||||||
accel: 20.0, // default: 40.0
|
.add_plugin(CyberCamPlugin)
|
||||||
drag: 0.01, // default: 0.0005
|
.add_plugin(CyberSpaceLightsPlugin)
|
||||||
gravity: 10.0, // default: 10.0
|
.add_plugin(CyberUIPlugin)
|
||||||
})
|
.add_startup_system(disable_mouse_trap)
|
||||||
.add_startup_system(setup.label("world"))
|
|
||||||
.add_startup_system(disable_cursor.after("world"))
|
|
||||||
.add_system(animate_lights)
|
|
||||||
.add_system(bevy::input::system::exit_on_esc_system)
|
.add_system(bevy::input::system::exit_on_esc_system)
|
||||||
.run();
|
.run();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn disable_cursor(mut windows: ResMut<Windows>) {
|
|
||||||
let window = windows.get_primary_mut().unwrap();
|
|
||||||
window.set_cursor_lock_mode(false);
|
|
||||||
window.set_cursor_visibility(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Component)]
|
|
||||||
struct Animate;
|
|
||||||
|
|
||||||
fn setup(
|
|
||||||
mut commands: Commands,
|
|
||||||
mut meshes: ResMut<Assets<Mesh>>,
|
|
||||||
mut materials: ResMut<Assets<StandardMaterial>>,
|
|
||||||
) {
|
|
||||||
let red_light = PointLight {
|
|
||||||
intensity: 1_000.0,
|
|
||||||
range: LIGHT_RANGE,
|
|
||||||
color: Color::RED,
|
|
||||||
radius: 10.0,
|
|
||||||
..Default::default()
|
|
||||||
};
|
|
||||||
|
|
||||||
let blue_light = PointLight {
|
|
||||||
intensity: 1_000.0,
|
|
||||||
range: LIGHT_RANGE,
|
|
||||||
color: Color::BLUE,
|
|
||||||
radius: 10.0,
|
|
||||||
..Default::default()
|
|
||||||
};
|
|
||||||
|
|
||||||
let purple_light = PointLight {
|
|
||||||
intensity: 1_000.0,
|
|
||||||
range: LIGHT_RANGE,
|
|
||||||
color: Color::PURPLE,
|
|
||||||
radius: 10.0,
|
|
||||||
..Default::default()
|
|
||||||
};
|
|
||||||
|
|
||||||
commands.insert_resource(AmbientLight {
|
|
||||||
color: Color::WHITE,
|
|
||||||
brightness: 0.32,
|
|
||||||
});
|
|
||||||
|
|
||||||
// world
|
|
||||||
commands
|
|
||||||
.spawn_bundle(PbrBundle {
|
|
||||||
mesh: meshes.add(Mesh::from(shape::Icosphere {
|
|
||||||
radius: PLANET_RADIUS,
|
|
||||||
subdivisions: 6,
|
|
||||||
})),
|
|
||||||
material: materials.add(StandardMaterial {
|
|
||||||
base_color: Color::GRAY,
|
|
||||||
metallic: 0.7,
|
|
||||||
perceptual_roughness: 0.5,
|
|
||||||
..Default::default()
|
|
||||||
}),
|
|
||||||
|
|
||||||
..Default::default()
|
|
||||||
})
|
|
||||||
.insert(RigidBody::Static)
|
|
||||||
.insert(CollisionShape::Sphere {
|
|
||||||
radius: PLANET_RADIUS,
|
|
||||||
});
|
|
||||||
|
|
||||||
// east light
|
|
||||||
commands
|
|
||||||
.spawn_bundle(PointLightBundle {
|
|
||||||
transform: Transform::from_xyz(LIGHT_DIST, 0.0, 0.0),
|
|
||||||
point_light: purple_light,
|
|
||||||
..Default::default()
|
|
||||||
})
|
|
||||||
.with_children(|builder| {
|
|
||||||
builder.spawn_bundle(PbrBundle {
|
|
||||||
mesh: meshes.add(Mesh::from(shape::UVSphere {
|
|
||||||
radius: 10.0,
|
|
||||||
..Default::default()
|
|
||||||
})),
|
|
||||||
material: materials.add(StandardMaterial {
|
|
||||||
base_color: Color::PURPLE,
|
|
||||||
emissive: Color::rgba_linear(50.0, 0.0, 50.0, 0.0),
|
|
||||||
..Default::default()
|
|
||||||
}),
|
|
||||||
..Default::default()
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.insert(Animate);
|
|
||||||
|
|
||||||
// west light
|
|
||||||
commands
|
|
||||||
.spawn_bundle(PointLightBundle {
|
|
||||||
transform: Transform::from_xyz(-LIGHT_DIST, 0.0, 0.0),
|
|
||||||
point_light: purple_light,
|
|
||||||
..Default::default()
|
|
||||||
})
|
|
||||||
.with_children(|builder| {
|
|
||||||
builder.spawn_bundle(PbrBundle {
|
|
||||||
mesh: meshes.add(Mesh::from(shape::UVSphere {
|
|
||||||
radius: 10.0,
|
|
||||||
..Default::default()
|
|
||||||
})),
|
|
||||||
material: materials.add(StandardMaterial {
|
|
||||||
base_color: Color::PURPLE,
|
|
||||||
emissive: Color::rgba_linear(50.0, 0.0, 50.0, 0.0),
|
|
||||||
..Default::default()
|
|
||||||
}),
|
|
||||||
..Default::default()
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.insert(Animate);
|
|
||||||
// north light
|
|
||||||
commands
|
|
||||||
.spawn_bundle(PointLightBundle {
|
|
||||||
transform: Transform::from_xyz(0.0, 0.0, LIGHT_DIST),
|
|
||||||
point_light: purple_light,
|
|
||||||
..Default::default()
|
|
||||||
})
|
|
||||||
.with_children(|builder| {
|
|
||||||
builder.spawn_bundle(PbrBundle {
|
|
||||||
mesh: meshes.add(Mesh::from(shape::UVSphere {
|
|
||||||
radius: 10.0,
|
|
||||||
..Default::default()
|
|
||||||
})),
|
|
||||||
material: materials.add(StandardMaterial {
|
|
||||||
base_color: Color::PURPLE,
|
|
||||||
emissive: Color::rgba_linear(50.0, 0.0, 50.0, 0.0),
|
|
||||||
..Default::default()
|
|
||||||
}),
|
|
||||||
..Default::default()
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.insert(Animate);
|
|
||||||
// south light
|
|
||||||
commands
|
|
||||||
.spawn_bundle(PointLightBundle {
|
|
||||||
transform: Transform::from_xyz(0.0, 0.0, -LIGHT_DIST),
|
|
||||||
point_light: purple_light,
|
|
||||||
..Default::default()
|
|
||||||
})
|
|
||||||
.with_children(|builder| {
|
|
||||||
builder.spawn_bundle(PbrBundle {
|
|
||||||
mesh: meshes.add(Mesh::from(shape::UVSphere {
|
|
||||||
radius: 10.0,
|
|
||||||
..Default::default()
|
|
||||||
})),
|
|
||||||
material: materials.add(StandardMaterial {
|
|
||||||
base_color: Color::PURPLE,
|
|
||||||
emissive: Color::rgba_linear(50.0, 0.0, 50.0, 0.0),
|
|
||||||
..Default::default()
|
|
||||||
}),
|
|
||||||
..Default::default()
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.insert(Animate);
|
|
||||||
// up light
|
|
||||||
commands
|
|
||||||
.spawn_bundle(PointLightBundle {
|
|
||||||
transform: Transform::from_xyz(0.0, LIGHT_DIST, 0.0),
|
|
||||||
point_light: red_light,
|
|
||||||
..Default::default()
|
|
||||||
})
|
|
||||||
.with_children(|builder| {
|
|
||||||
builder.spawn_bundle(PbrBundle {
|
|
||||||
mesh: meshes.add(Mesh::from(shape::Icosphere {
|
|
||||||
radius: 10.0,
|
|
||||||
subdivisions: 2,
|
|
||||||
})),
|
|
||||||
material: materials.add(StandardMaterial {
|
|
||||||
base_color: Color::RED,
|
|
||||||
emissive: Color::rgba_linear(100.0, 0.0, 0.0, 0.0),
|
|
||||||
..Default::default()
|
|
||||||
}),
|
|
||||||
..Default::default()
|
|
||||||
});
|
|
||||||
});
|
|
||||||
// down light
|
|
||||||
commands
|
|
||||||
.spawn_bundle(PointLightBundle {
|
|
||||||
transform: Transform::from_xyz(0.0, -LIGHT_DIST, 0.0),
|
|
||||||
point_light: blue_light,
|
|
||||||
..Default::default()
|
|
||||||
})
|
|
||||||
.with_children(|builder| {
|
|
||||||
builder.spawn_bundle(PbrBundle {
|
|
||||||
mesh: meshes.add(Mesh::from(shape::Icosphere {
|
|
||||||
radius: 10.0,
|
|
||||||
subdivisions: 2,
|
|
||||||
})),
|
|
||||||
material: materials.add(StandardMaterial {
|
|
||||||
base_color: Color::BLUE,
|
|
||||||
emissive: Color::rgba_linear(0.0, 0.0, 100.0, 0.0),
|
|
||||||
..Default::default()
|
|
||||||
}),
|
|
||||||
..Default::default()
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
fn animate_lights(
|
|
||||||
time: Res<Time>,
|
|
||||||
mut query: Query<&mut Transform, (With<PointLight>, With<Animate>)>,
|
|
||||||
) {
|
|
||||||
let dt = time.delta_seconds();
|
|
||||||
for mut transform in query.iter_mut() {
|
|
||||||
let translation = &transform.translation;
|
|
||||||
let x = translation.x;
|
|
||||||
let y = translation.y;
|
|
||||||
let z = if translation.z.abs() < 0.1 {
|
|
||||||
translation.z + 0.15
|
|
||||||
} else {
|
|
||||||
translation.z
|
|
||||||
};
|
|
||||||
|
|
||||||
// 10 degrees == 0.174533 radians
|
|
||||||
let anim_rate = 0.174533 * dt;
|
|
||||||
let theta = z.atan2(x) + anim_rate;
|
|
||||||
let x_new = LIGHT_DIST * theta.cos();
|
|
||||||
let z_new = LIGHT_DIST * theta.sin();
|
|
||||||
|
|
||||||
*transform = Transform::from_xyz(x_new, y, z_new);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
161
src/physics.rs
Normal file
161
src/physics.rs
Normal file
|
@ -0,0 +1,161 @@
|
||||||
|
use bevy::prelude::*;
|
||||||
|
use heron::prelude::*;
|
||||||
|
|
||||||
|
use crate::{geometry::CyberBike, input::InputState};
|
||||||
|
|
||||||
|
/// Mouse sensitivity and movement speed
|
||||||
|
pub struct MovementSettings {
|
||||||
|
pub sensitivity: f32,
|
||||||
|
pub accel: f32,
|
||||||
|
pub drag: f32,
|
||||||
|
pub gravity: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for MovementSettings {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
sensitivity: 1.0,
|
||||||
|
accel: 40.,
|
||||||
|
drag: 0.0005,
|
||||||
|
gravity: 10.0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Component, Default)]
|
||||||
|
pub(crate) struct PlayerState {
|
||||||
|
pub velocity: Vec3,
|
||||||
|
pub colliding: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn falling_cat(time: Res<Time>, mut bike_query: Query<(&mut Transform, &CyberBike)>) {
|
||||||
|
let dt = time.delta_seconds();
|
||||||
|
|
||||||
|
let (mut bike_xform, _) = bike_query.single_mut();
|
||||||
|
let up = bike_xform.translation.normalize();
|
||||||
|
let cam_up = bike_xform.up();
|
||||||
|
let cos = up.dot(cam_up);
|
||||||
|
|
||||||
|
let theta = cos.acos();
|
||||||
|
let rate = if !theta.is_normal() {
|
||||||
|
0.0
|
||||||
|
} else if theta.is_sign_negative() {
|
||||||
|
-0.4
|
||||||
|
} else {
|
||||||
|
0.4
|
||||||
|
} * dt;
|
||||||
|
let angle = if rate.is_sign_negative() {
|
||||||
|
rate.max(theta)
|
||||||
|
} else {
|
||||||
|
rate.min(theta)
|
||||||
|
};
|
||||||
|
|
||||||
|
let rot = Quat::from_axis_angle(cam_up.cross(up).normalize(), angle);
|
||||||
|
|
||||||
|
if rot.is_finite() && theta.abs() > 0.0085 {
|
||||||
|
bike_xform.rotate(rot);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn apply_velocity(
|
||||||
|
time: Res<Time>,
|
||||||
|
mut bike_query: Query<(&mut Transform, &PlayerState, &CyberBike)>,
|
||||||
|
) {
|
||||||
|
let dt = time.delta_seconds();
|
||||||
|
|
||||||
|
let (mut bike_xform, player_state, _) = bike_query.single_mut();
|
||||||
|
|
||||||
|
if player_state.velocity.is_finite() {
|
||||||
|
bike_xform.translation += player_state.velocity * dt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update_player_vel(
|
||||||
|
time: Res<Time>,
|
||||||
|
settings: Res<MovementSettings>,
|
||||||
|
input: Res<InputState>,
|
||||||
|
mut query: Query<(&Transform, &mut PlayerState, &CyberBike)>,
|
||||||
|
) {
|
||||||
|
let dt = time.delta_seconds();
|
||||||
|
let (xform, mut pstate, _) = query.single_mut();
|
||||||
|
|
||||||
|
// first gravity
|
||||||
|
let down = -xform.translation.normalize();
|
||||||
|
let dvel = down * settings.gravity * dt;
|
||||||
|
let mut vel = if pstate.velocity.is_finite() {
|
||||||
|
pstate.velocity + dvel
|
||||||
|
} else {
|
||||||
|
dvel
|
||||||
|
};
|
||||||
|
|
||||||
|
// thrust or brake
|
||||||
|
let accel = xform.forward() * input.throttle * dt * settings.accel;
|
||||||
|
if pstate.velocity.is_finite() {
|
||||||
|
vel += accel;
|
||||||
|
} else {
|
||||||
|
vel = accel;
|
||||||
|
}
|
||||||
|
|
||||||
|
// brake
|
||||||
|
if input.brake {
|
||||||
|
let s = vel.length_squared();
|
||||||
|
if s < 0.05 {
|
||||||
|
vel = Vec3::ZERO;
|
||||||
|
} else {
|
||||||
|
vel -= vel.normalize() * settings.accel * dt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// drag
|
||||||
|
let v2 = vel.length_squared().min(100_000.0);
|
||||||
|
if v2 < 0.05 {
|
||||||
|
vel = Vec3::ZERO;
|
||||||
|
} else {
|
||||||
|
let drag = vel * settings.drag * v2 * dt;
|
||||||
|
vel -= drag;
|
||||||
|
}
|
||||||
|
|
||||||
|
pstate.velocity = vel;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn collision_detection(
|
||||||
|
mut events: EventReader<CollisionEvent>,
|
||||||
|
mut query: Query<&mut PlayerState>,
|
||||||
|
) {
|
||||||
|
let mut pstate = query.single_mut();
|
||||||
|
|
||||||
|
for event in events.iter() {
|
||||||
|
if let CollisionEvent::Started(_, _) = event {
|
||||||
|
pstate.colliding = true;
|
||||||
|
} else {
|
||||||
|
pstate.colliding = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn collision_reaction(mut query: Query<(&mut PlayerState, &Transform)>) {
|
||||||
|
let (mut pstate, xform) = query.single_mut();
|
||||||
|
|
||||||
|
let down = -xform.translation.normalize();
|
||||||
|
|
||||||
|
// now see if we're currently colliding
|
||||||
|
if pstate.colliding {
|
||||||
|
let vel = pstate.velocity;
|
||||||
|
let dvel = down * vel.dot(down) * 1.02;
|
||||||
|
pstate.velocity -= dvel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct CyberPhysicsPlugin;
|
||||||
|
impl Plugin for CyberPhysicsPlugin {
|
||||||
|
fn build(&self, app: &mut App) {
|
||||||
|
app.init_resource::<PlayerState>()
|
||||||
|
.init_resource::<MovementSettings>()
|
||||||
|
.add_plugin(PhysicsPlugin::default())
|
||||||
|
.add_system(collision_detection)
|
||||||
|
.add_system(collision_reaction)
|
||||||
|
.add_system(falling_cat)
|
||||||
|
.add_system(update_player_vel)
|
||||||
|
.add_system(apply_velocity);
|
||||||
|
}
|
||||||
|
}
|
47
src/ui.rs
Normal file
47
src/ui.rs
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
use bevy::prelude::*;
|
||||||
|
|
||||||
|
use crate::physics::PlayerState;
|
||||||
|
|
||||||
|
#[derive(Component)]
|
||||||
|
struct UpText;
|
||||||
|
|
||||||
|
fn setup_ui(mut commands: Commands, asset_server: Res<AssetServer>) {
|
||||||
|
commands.spawn_bundle(UiCameraBundle::default());
|
||||||
|
|
||||||
|
commands
|
||||||
|
.spawn_bundle(TextBundle {
|
||||||
|
style: Style {
|
||||||
|
align_self: AlignSelf::FlexEnd,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
// Use `Text` directly
|
||||||
|
text: Text {
|
||||||
|
// Construct a `Vec` of `TextSection`s
|
||||||
|
sections: vec![TextSection {
|
||||||
|
value: "".to_string(),
|
||||||
|
style: TextStyle {
|
||||||
|
font: asset_server.load("fonts/FiraMono-Medium.ttf"),
|
||||||
|
font_size: 40.0,
|
||||||
|
color: Color::GOLD,
|
||||||
|
},
|
||||||
|
}],
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
..Default::default()
|
||||||
|
})
|
||||||
|
.insert(UpText);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update_ui(pstate_query: Query<&PlayerState>, mut text_query: Query<&mut Text, With<UpText>>) {
|
||||||
|
let mut text = text_query.single_mut();
|
||||||
|
let pstate = pstate_query.single();
|
||||||
|
text.sections[0].value = format!("{:.2}", pstate.velocity.length());
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct CyberUIPlugin;
|
||||||
|
|
||||||
|
impl Plugin for CyberUIPlugin {
|
||||||
|
fn build(&self, app: &mut App) {
|
||||||
|
app.add_startup_system(setup_ui).add_system(update_ui);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue