Merge branch 'physics'
This commit is contained in:
commit
d1a8c536eb
280
Cargo.lock
generated
280
Cargo.lock
generated
|
@ -1020,6 +1020,34 @@ dependencies = [
|
|||
"winit",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bevy_xpbd_3d"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0425ea7361b9b27c2a382e0663deb42f41147eee60fb2b3d5fa7e42d363ea848"
|
||||
dependencies = [
|
||||
"bevy",
|
||||
"bevy_math",
|
||||
"bevy_xpbd_derive",
|
||||
"derive_more",
|
||||
"fxhash",
|
||||
"indexmap",
|
||||
"itertools",
|
||||
"nalgebra",
|
||||
"parry3d",
|
||||
"parry3d-f64",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bevy_xpbd_derive"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3e1ef1d5e328abe1b76df974245f78e17fd17867583883d5e77444c6a8223a64"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"syn 2.0.52",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bindgen"
|
||||
version = "0.69.4"
|
||||
|
@ -1358,6 +1386,12 @@ dependencies = [
|
|||
"const_soft_float",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "convert_case"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e"
|
||||
|
||||
[[package]]
|
||||
name = "core-foundation"
|
||||
version = "0.9.4"
|
||||
|
@ -1459,6 +1493,25 @@ dependencies = [
|
|||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-deque"
|
||||
version = "0.8.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d"
|
||||
dependencies = [
|
||||
"crossbeam-epoch",
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-epoch"
|
||||
version = "0.9.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e"
|
||||
dependencies = [
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-utils"
|
||||
version = "0.8.19"
|
||||
|
@ -1500,8 +1553,10 @@ version = "0.99.17"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321"
|
||||
dependencies = [
|
||||
"convert_case",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"rustc_version",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
|
@ -1729,6 +1784,15 @@ dependencies = [
|
|||
"pin-project-lite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fxhash"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gethostname"
|
||||
version = "0.4.3"
|
||||
|
@ -2134,6 +2198,12 @@ dependencies = [
|
|||
"windows-targets 0.52.4",
|
||||
]
|
||||
|
||||
[[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"
|
||||
|
@ -2194,6 +2264,16 @@ dependencies = [
|
|||
"regex-automata 0.1.10",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "matrixmultiply"
|
||||
version = "0.3.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7574c1cf36da4798ab73da5b215bbf444f50718207754cb522201d78d1cd0ff2"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"rawpointer",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.7.1"
|
||||
|
@ -2272,6 +2352,34 @@ dependencies = [
|
|||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nalgebra"
|
||||
version = "0.32.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3ea4908d4f23254adda3daa60ffef0f1ac7b8c3e9a864cf3cc154b251908a2ef"
|
||||
dependencies = [
|
||||
"approx",
|
||||
"glam",
|
||||
"matrixmultiply",
|
||||
"nalgebra-macros",
|
||||
"num-complex",
|
||||
"num-rational",
|
||||
"num-traits",
|
||||
"simba",
|
||||
"typenum",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nalgebra-macros"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "91761aed67d03ad966ef783ae962ef9bbaca728d2dd7ceb7939ec110fffad998"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ndk"
|
||||
version = "0.8.0"
|
||||
|
@ -2337,6 +2445,15 @@ dependencies = [
|
|||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-complex"
|
||||
version = "0.4.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "23c6602fda94a57c990fe0df199a035d83576b496aa29f4e634a8ac6004e68a6"
|
||||
dependencies = [
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-derive"
|
||||
version = "0.4.2"
|
||||
|
@ -2348,6 +2465,26 @@ dependencies = [
|
|||
"syn 2.0.52",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-integer"
|
||||
version = "0.1.46"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f"
|
||||
dependencies = [
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-rational"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.18"
|
||||
|
@ -2355,6 +2492,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"libm",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2498,6 +2636,7 @@ version = "0.3.0"
|
|||
dependencies = [
|
||||
"bevy",
|
||||
"bevy_embedded_assets",
|
||||
"bevy_xpbd_3d",
|
||||
"regex",
|
||||
]
|
||||
|
||||
|
@ -2545,6 +2684,50 @@ dependencies = [
|
|||
"windows-targets 0.48.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parry3d"
|
||||
version = "0.13.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6ccba18a65dba56c08dadfa936e0c9efbc883b3a26dc77d2685f78be10f7667c"
|
||||
dependencies = [
|
||||
"approx",
|
||||
"arrayvec",
|
||||
"bitflags 1.3.2",
|
||||
"downcast-rs",
|
||||
"either",
|
||||
"nalgebra",
|
||||
"num-derive",
|
||||
"num-traits",
|
||||
"rayon",
|
||||
"rustc-hash",
|
||||
"simba",
|
||||
"slab",
|
||||
"smallvec",
|
||||
"spade",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parry3d-f64"
|
||||
version = "0.13.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d259245abcc09379798e4d373d9019e0df4dc6f7f128ecd68700a5927dc32034"
|
||||
dependencies = [
|
||||
"approx",
|
||||
"arrayvec",
|
||||
"bitflags 1.3.2",
|
||||
"downcast-rs",
|
||||
"either",
|
||||
"nalgebra",
|
||||
"num-derive",
|
||||
"num-traits",
|
||||
"rayon",
|
||||
"rustc-hash",
|
||||
"simba",
|
||||
"slab",
|
||||
"smallvec",
|
||||
"spade",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "paste"
|
||||
version = "1.0.14"
|
||||
|
@ -2683,6 +2866,32 @@ version = "0.6.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "42a9830a0e1b9fb145ebb365b8bc4ccd75f290f98c0247deafbbe2c75cefb544"
|
||||
|
||||
[[package]]
|
||||
name = "rawpointer"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3"
|
||||
|
||||
[[package]]
|
||||
name = "rayon"
|
||||
version = "1.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa"
|
||||
dependencies = [
|
||||
"either",
|
||||
"rayon-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rayon-core"
|
||||
version = "1.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2"
|
||||
dependencies = [
|
||||
"crossbeam-deque",
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rectangle-pack"
|
||||
version = "0.4.2"
|
||||
|
@ -2757,6 +2966,12 @@ version = "1.1.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "19b30a45b0cd0bcca8037f3d0dc3421eaf95327a17cad11964fb8179b4fc4832"
|
||||
|
||||
[[package]]
|
||||
name = "robust"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cbf4a6aa5f6d6888f39e980649f3ad6b666acdce1d78e95b8a2cb076e687ae30"
|
||||
|
||||
[[package]]
|
||||
name = "rodio"
|
||||
version = "0.17.3"
|
||||
|
@ -2785,6 +3000,15 @@ version = "1.1.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
|
||||
|
||||
[[package]]
|
||||
name = "rustc_version"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366"
|
||||
dependencies = [
|
||||
"semver",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "0.38.31"
|
||||
|
@ -2815,6 +3039,15 @@ version = "1.0.17"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1"
|
||||
|
||||
[[package]]
|
||||
name = "safe_arch"
|
||||
version = "0.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f398075ce1e6a179b46f51bd88d0598b92b00d3551f1a2d4ac49e771b56ac354"
|
||||
dependencies = [
|
||||
"bytemuck",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "same-file"
|
||||
version = "1.0.6"
|
||||
|
@ -2830,6 +3063,12 @@ version = "1.2.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
||||
|
||||
[[package]]
|
||||
name = "semver"
|
||||
version = "1.0.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.197"
|
||||
|
@ -2876,6 +3115,19 @@ version = "1.3.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
|
||||
|
||||
[[package]]
|
||||
name = "simba"
|
||||
version = "0.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "061507c94fc6ab4ba1c9a0305018408e312e17c041eb63bef8aa726fa33aceae"
|
||||
dependencies = [
|
||||
"approx",
|
||||
"num-complex",
|
||||
"num-traits",
|
||||
"paste",
|
||||
"wide",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "simd-adler32"
|
||||
version = "0.3.7"
|
||||
|
@ -2918,6 +3170,18 @@ dependencies = [
|
|||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "spade"
|
||||
version = "2.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "61addf9117b11d1f5b4bf6fe94242ba25f59d2d4b2080544b771bd647024fd00"
|
||||
dependencies = [
|
||||
"hashbrown",
|
||||
"num-traits",
|
||||
"robust",
|
||||
"smallvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "spirv"
|
||||
version = "0.3.0+sdk-1.3.268.0"
|
||||
|
@ -3157,6 +3421,12 @@ dependencies = [
|
|||
"static_assertions",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "typenum"
|
||||
version = "1.17.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.12"
|
||||
|
@ -3412,6 +3682,16 @@ dependencies = [
|
|||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wide"
|
||||
version = "0.7.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "89beec544f246e679fc25490e3f8e08003bc4bf612068f325120dad4cea02c1c"
|
||||
dependencies = [
|
||||
"bytemuck",
|
||||
"safe_arch",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "widestring"
|
||||
version = "1.0.2"
|
||||
|
|
|
@ -11,8 +11,9 @@ rust-version = "1.76.0"
|
|||
|
||||
[dependencies]
|
||||
regex = "1"
|
||||
bevy_embedded_assets = "0.10.2"
|
||||
bevy = { version = "0.13.0", default-features = false, features = ["jpeg", "bevy_asset", "bevy_audio", "bevy_scene", "bevy_winit", "bevy_core_pipeline", "bevy_pbr", "bevy_gltf", "bevy_render", "bevy_text", "bevy_ui", "multi-threaded", "png", "vorbis", "x11", "tonemapping_luts"]}
|
||||
bevy_xpbd_3d = { version = "0.4", default-features = false, features = ["3d", "f32", "parry-f32", "parallel"] }
|
||||
bevy_embedded_assets = "0.10.2"
|
||||
|
||||
[features]
|
||||
dev = ["bevy/dynamic_linking"]
|
||||
|
|
|
@ -24,6 +24,7 @@ Key features:
|
|||
- t: toggle music (NOTE: currently no music is included in the git repo)
|
||||
- m: mute sound effects
|
||||
- q: enter/exit vehicle
|
||||
- f: toggle 3rd person view
|
||||
- TAB: toggle augmented reality overlay (HUD, low-light amplifier)
|
||||
|
||||
# System Requirements
|
||||
|
@ -113,6 +114,7 @@ cargo run --release
|
|||
- https://pixabay.com/sound-effects/electricity-6353
|
||||
- https://pixabay.com/sound-effects/ducati-696-monster-33217
|
||||
- https://pixabay.com/sound-effects/high-energy-humming-195612
|
||||
- https://pixabay.com/sound-effects/box-crash-106687
|
||||
- Music: [Dead Space Style Ambient Music](https://pixabay.com/music/ambient-dead-space-style-ambient-music-184793) by [Sharvarian](https://www.fiverr.com/sharvarian)
|
||||
- Star chart based on the [HYG Stellar database](https://github.com/astronexus/HYG-Database)
|
||||
- Custom font Yupiter is based on:
|
||||
|
|
Binary file not shown.
BIN
assets/sounds/crash.ogg
Normal file
BIN
assets/sounds/crash.ogg
Normal file
Binary file not shown.
83
src/actor.rs
83
src/actor.rs
|
@ -1,4 +1,6 @@
|
|||
use bevy::prelude::*;
|
||||
use bevy::transform::TransformSystem;
|
||||
use bevy_xpbd_3d::prelude::*;
|
||||
use crate::{nature, settings, actor, audio, hud};
|
||||
|
||||
pub const ENGINE_SPEED_FACTOR: f32 = 30.0;
|
||||
|
@ -11,7 +13,6 @@ impl Plugin for ActorPlugin {
|
|||
app.register_type::<ChatBranch>();
|
||||
app.add_systems(FixedUpdate, (
|
||||
update_physics_lifeforms,
|
||||
update_physics_actors,
|
||||
));
|
||||
app.add_systems(Update, (
|
||||
handle_new_conversations,
|
||||
|
@ -19,7 +20,8 @@ impl Plugin for ActorPlugin {
|
|||
handle_conversations,
|
||||
handle_input,
|
||||
handle_chat_scripts,
|
||||
handle_vehicle_enter_exit,
|
||||
handle_vehicle_enter_exit.after(PhysicsSet::Sync).before(TransformSystem::TransformPropagate),
|
||||
handle_collisions,
|
||||
));
|
||||
app.add_event::<StartConversationEvent>();
|
||||
app.add_event::<SendMessageEvent>();
|
||||
|
@ -63,6 +65,7 @@ pub struct Actor {
|
|||
pub v: Vec3, // velocity
|
||||
pub angular_momentum: Quat,
|
||||
pub inside_entity: u32,
|
||||
pub camdistance: f32,
|
||||
}
|
||||
|
||||
impl Default for Actor {
|
||||
|
@ -74,12 +77,14 @@ impl Default for Actor {
|
|||
v: Vec3::ZERO,
|
||||
inside_entity: NO_RIDE,
|
||||
angular_momentum: Quat::from_euler(EulerRot::XYZ, 0.001, 0.01, 0.003),
|
||||
camdistance: 15.0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Component)] pub struct Player;
|
||||
#[derive(Component)] pub struct PlayerDrivesThis;
|
||||
#[derive(Component)] pub struct Player; // Attached to the suit of the player
|
||||
#[derive(Component)] pub struct PlayerDrivesThis; // Attached to the entered vehicle
|
||||
#[derive(Component)] pub struct PlayerCamera; // Attached to the actor to use as point of view
|
||||
#[derive(Component)] pub struct PlayerInConversation;
|
||||
#[derive(Component)] pub struct InConversationWithPlayer;
|
||||
#[derive(Component)] pub struct ActorEnteringVehicle;
|
||||
|
@ -187,19 +192,6 @@ const SUIT_SIMPLE: Suit = Suit {
|
|||
integrity: 1e5,
|
||||
};
|
||||
|
||||
pub fn update_physics_actors(
|
||||
time: Res<Time>,
|
||||
mut q_actors: Query<(&mut Actor, &mut Transform)>,
|
||||
) {
|
||||
let d = time.delta_seconds();
|
||||
for (actor, mut transform) in q_actors.iter_mut() {
|
||||
transform.rotate(actor.angular_momentum);
|
||||
// TODO: animate only a step based on time between update:
|
||||
//transform.rotate(actor.angular_momentum.slerp(Quat::IDENTITY, d)); // not working
|
||||
transform.translation += d * actor.v;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update_physics_lifeforms(
|
||||
time: Res<Time>,
|
||||
mut query: Query<(&mut LifeForm, &mut Suit, &Actor)>,
|
||||
|
@ -294,6 +286,7 @@ pub fn handle_input(
|
|||
is_entering: false,
|
||||
is_player: true,
|
||||
});
|
||||
commands.entity(player_entity).insert(RigidBody::Dynamic);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -304,41 +297,43 @@ pub fn handle_input(
|
|||
pub fn handle_vehicle_enter_exit(
|
||||
mut commands: Commands,
|
||||
mut er_vehicle: EventReader<VehicleEnterExitEvent>,
|
||||
mut q_drivers: Query<(Entity, &mut Actor, &mut Visibility, &mut Transform), (Without<ActorVehicleBeingEntered>, With<ActorEnteringVehicle>)>,
|
||||
mut q_vehicles: Query<(Entity, &mut Actor, &mut Visibility, &mut Transform), (With<ActorVehicleBeingEntered>, Without<ActorEnteringVehicle>)>,
|
||||
mut q_drivers: Query<(Entity, &mut Visibility, &mut Transform, &mut LinearVelocity, &mut AngularVelocity), (Without<ActorVehicleBeingEntered>, With<ActorEnteringVehicle>)>,
|
||||
mut q_vehicles: Query<(Entity, &mut Visibility, &mut Transform, &LinearVelocity, &AngularVelocity), (With<ActorVehicleBeingEntered>, Without<ActorEnteringVehicle>)>,
|
||||
mut ew_sfx: EventWriter<audio::PlaySfxEvent>,
|
||||
) {
|
||||
for event in er_vehicle.read() {
|
||||
for (driver, mut driver_actor, mut driver_vis, mut driver_trans) in q_drivers.iter_mut() {
|
||||
for (driver, mut driver_vis, mut driver_trans, mut driver_linv, mut driver_angv) in q_drivers.iter_mut() {
|
||||
if driver == event.driver {
|
||||
for (vehicle, mut vehicle_actor, mut vehicle_vis, mut vehicle_trans) in q_vehicles.iter_mut() {
|
||||
for (vehicle, mut vehicle_vis, vehicle_trans, vehicle_linv, vehicle_angv) in q_vehicles.iter_mut() {
|
||||
if vehicle == event.vehicle {
|
||||
if event.is_entering {
|
||||
// Entering Vehicle
|
||||
ew_sfx.send(audio::PlaySfxEvent(audio::Sfx::EnterVehicle));
|
||||
*driver_vis = Visibility::Hidden;
|
||||
*driver_trans = vehicle_trans.clone();
|
||||
commands.entity(driver).remove::<RigidBody>();
|
||||
*driver_vis = Visibility::Hidden; //seems to have no effect...
|
||||
if event.is_player {
|
||||
//player_actor.inside_entity = entity.index();
|
||||
*vehicle_vis = Visibility::Hidden;
|
||||
driver_actor.v = vehicle_actor.v;
|
||||
ew_sfx.send(audio::PlaySfxEvent(audio::Sfx::EnterVehicle));
|
||||
commands.entity(driver).remove::<PlayerCamera>();
|
||||
commands.entity(vehicle).insert(PlayerCamera);
|
||||
commands.entity(vehicle).insert(PlayerDrivesThis);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Exiting Vehicle
|
||||
ew_sfx.send(audio::PlaySfxEvent(audio::Sfx::Switch));
|
||||
*driver_vis = Visibility::Inherited;
|
||||
*driver_linv = vehicle_linv.clone();
|
||||
*driver_angv = vehicle_angv.clone();
|
||||
driver_trans.translation = vehicle_trans.translation + Vec3::new(0.0, 0.0, 10.0);
|
||||
driver_trans.rotation = vehicle_trans.rotation;
|
||||
// NOTE: I would rather have the following line here,
|
||||
// but then, for some reason, changing driver translation
|
||||
// does not work. For now, you must manually insert the RigidBody
|
||||
// component from the place that adds this event.
|
||||
//commands.entity(driver).insert(RigidBody::Dynamic);
|
||||
if event.is_player {
|
||||
*vehicle_vis = Visibility::Inherited;
|
||||
vehicle_actor.v = driver_actor.v;
|
||||
vehicle_actor.angular_momentum = driver_actor.angular_momentum;
|
||||
*vehicle_trans = driver_trans.clone();
|
||||
ew_sfx.send(audio::PlaySfxEvent(audio::Sfx::Switch));
|
||||
commands.entity(vehicle).remove::<PlayerCamera>();
|
||||
commands.entity(driver).insert(PlayerCamera);
|
||||
commands.entity(vehicle).remove::<PlayerDrivesThis>();
|
||||
}
|
||||
else {
|
||||
*driver_trans = vehicle_trans.clone();
|
||||
*driver_trans = vehicle_trans.clone();
|
||||
*vehicle_vis = Visibility::Inherited;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -566,3 +561,17 @@ pub fn handle_chat_scripts(
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_collisions(
|
||||
mut collision_event_reader: EventReader<Collision>,
|
||||
mut ew_sfx: EventWriter<audio::PlaySfxEvent>,
|
||||
q_player: Query<Entity, With<PlayerCamera>>,
|
||||
) {
|
||||
if let Ok(player) = q_player.get_single() {
|
||||
for Collision(contacts) in collision_event_reader.read() {
|
||||
if contacts.entity1 == player || contacts.entity2 == player {
|
||||
ew_sfx.send(audio::PlaySfxEvent(audio::Sfx::Crash));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@ const ASSET_ROCKET: &str = "sounds/rocket.ogg";
|
|||
const ASSET_ION: &str = "sounds/ion.ogg";
|
||||
//const ASSET_WAKEUP: &str = "sounds/wakeup.ogg";
|
||||
const ASSET_BIKESTART: &str = "sounds/bikestart.ogg";
|
||||
const ASSET_CRASH: &str = "sounds/crash.ogg";
|
||||
|
||||
pub struct AudioPlugin;
|
||||
impl Plugin for AudioPlugin {
|
||||
|
@ -33,6 +34,7 @@ pub enum Sfx {
|
|||
Ping,
|
||||
Connect,
|
||||
EnterVehicle,
|
||||
Crash,
|
||||
None,
|
||||
}
|
||||
|
||||
|
@ -49,6 +51,7 @@ pub enum Sfx {
|
|||
#[derive(Resource)] pub struct SoundPing(Handle<AudioSource>);
|
||||
#[derive(Resource)] pub struct SoundConnect(Handle<AudioSource>);
|
||||
#[derive(Resource)] pub struct SoundBikeStart(Handle<AudioSource>);
|
||||
#[derive(Resource)] pub struct SoundCrash(Handle<AudioSource>);
|
||||
|
||||
pub fn setup(
|
||||
mut commands: Commands,
|
||||
|
@ -113,6 +116,7 @@ pub fn setup(
|
|||
commands.insert_resource(SoundPing(asset_server.load(ASSET_PING)));
|
||||
commands.insert_resource(SoundConnect(asset_server.load(ASSET_CONNECT)));
|
||||
commands.insert_resource(SoundBikeStart(asset_server.load(ASSET_BIKESTART)));
|
||||
commands.insert_resource(SoundCrash(asset_server.load(ASSET_CRASH)));
|
||||
}
|
||||
|
||||
pub fn toggle_bgm(
|
||||
|
@ -143,6 +147,7 @@ pub fn play_sfx(
|
|||
sound_ping: Res<SoundPing>,
|
||||
sound_connect: Res<SoundConnect>,
|
||||
sound_bikestart: Res<SoundBikeStart>,
|
||||
sound_crash: Res<SoundCrash>,
|
||||
) {
|
||||
if settings.mute_sfx && !events_sfx.is_empty() {
|
||||
events_sfx.clear();
|
||||
|
@ -160,6 +165,7 @@ pub fn play_sfx(
|
|||
Sfx::Ping => sound_ping.0.clone(),
|
||||
Sfx::Connect => sound_connect.0.clone(),
|
||||
Sfx::EnterVehicle => sound_bikestart.0.clone(),
|
||||
Sfx::Crash => sound_crash.0.clone(),
|
||||
Sfx::None => sound_ping.0.clone(),
|
||||
},
|
||||
settings: PlaybackSettings::DESPAWN,
|
||||
|
@ -175,6 +181,7 @@ pub fn str2sfx(sfx_label: &str) -> Sfx {
|
|||
"ping" => Sfx::Ping,
|
||||
"connect" => Sfx::Connect,
|
||||
"entervehicle" => Sfx::EnterVehicle,
|
||||
"crash" => Sfx::Crash,
|
||||
_ => Sfx::None,
|
||||
};
|
||||
}
|
||||
|
|
177
src/camera.rs
177
src/camera.rs
|
@ -1,6 +1,10 @@
|
|||
use bevy::prelude::*;
|
||||
use bevy::input::mouse::MouseMotion;
|
||||
use bevy::window::PrimaryWindow;
|
||||
use bevy::core_pipeline::bloom::{BloomCompositeMode, BloomSettings};
|
||||
use bevy::core_pipeline::tonemapping::Tonemapping;
|
||||
use bevy::transform::TransformSystem;
|
||||
use bevy_xpbd_3d::prelude::*;
|
||||
use std::f32::consts::*;
|
||||
use crate::{settings, audio, actor};
|
||||
|
||||
|
@ -8,7 +12,14 @@ pub struct CameraControllerPlugin;
|
|||
|
||||
impl Plugin for CameraControllerPlugin {
|
||||
fn build(&self, app: &mut App) {
|
||||
app.add_systems(Update, run_camera_controller);
|
||||
app.add_systems(Startup, setup_camera);
|
||||
app.add_systems(Update, handle_input);
|
||||
app.add_systems(Update, manage_player_actor.after(handle_input));
|
||||
app.add_systems(PostUpdate, sync_camera_to_player
|
||||
.after(PhysicsSet::Sync)
|
||||
.before(TransformSystem::TransformPropagate));
|
||||
app.add_systems(Update, update_fov);
|
||||
app.add_systems(Update, apply_input_to_player);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -17,29 +28,90 @@ impl Plugin for CameraControllerPlugin {
|
|||
// it because it felt nice.
|
||||
pub const RADIANS_PER_DOT: f32 = 1.0 / 180.0;
|
||||
|
||||
#[derive(Component)]
|
||||
pub struct CameraController {
|
||||
pub enabled: bool,
|
||||
pub initialized: bool,
|
||||
pub sensitivity: f32,
|
||||
pub pitch: f32,
|
||||
pub yaw: f32,
|
||||
fn setup_camera(
|
||||
mut commands: Commands,
|
||||
) {
|
||||
// Add player
|
||||
commands.spawn((
|
||||
Camera3dBundle {
|
||||
camera: Camera {
|
||||
hdr: true, // HDR is required for bloom
|
||||
..default()
|
||||
},
|
||||
tonemapping: Tonemapping::TonyMcMapface,
|
||||
transform: Transform::from_xyz(0.0, 0.0, 8.0).looking_at(Vec3::ZERO, Vec3::Y),
|
||||
..default()
|
||||
},
|
||||
BloomSettings {
|
||||
composite_mode: BloomCompositeMode::EnergyConserving,
|
||||
..default()
|
||||
},
|
||||
));
|
||||
}
|
||||
|
||||
impl Default for CameraController {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
enabled: true,
|
||||
initialized: false,
|
||||
sensitivity: 0.5,
|
||||
pitch: 1.0, // pitch=0/yaw=0 -> face sun
|
||||
yaw: 0.3,
|
||||
pub fn sync_camera_to_player(
|
||||
settings: Res<settings::Settings>,
|
||||
mut q_camera: Query<&mut Transform, With<Camera>>,
|
||||
q_playercam: Query<(&actor::Actor, &Transform), (With<actor::PlayerCamera>, Without<Camera>)>,
|
||||
) {
|
||||
if q_camera.is_empty() || q_playercam.is_empty() {
|
||||
return;
|
||||
}
|
||||
let mut camera_transform = q_camera.get_single_mut().unwrap();
|
||||
let (actor, player_transform) = q_playercam.get_single().unwrap();
|
||||
|
||||
// Rotation
|
||||
camera_transform.rotation = player_transform.rotation * Quat::from_array([0.0, -1.0, 0.0, 0.0]);
|
||||
|
||||
// Translation
|
||||
if settings.third_person {
|
||||
camera_transform.translation = player_transform.translation + camera_transform.rotation * (actor.camdistance * Vec3::new(0.0, 0.2, 1.0));
|
||||
}
|
||||
else {
|
||||
camera_transform.translation = player_transform.translation;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update_fov(
|
||||
q_player: Query<&actor::LifeForm, With<actor::Player>>,
|
||||
mut q_camera: Query<&mut Projection, With<Camera>>,
|
||||
) {
|
||||
if let (Ok(lifeform), Ok(mut projection)) = (q_player.get_single(), q_camera.get_single_mut())
|
||||
{
|
||||
let fov = (lifeform.adrenaline.powf(3.0) * 45.0 + 45.0).to_radians();
|
||||
*projection = Projection::Perspective(PerspectiveProjection { fov: fov, ..default() });
|
||||
}
|
||||
}
|
||||
|
||||
pub fn handle_input(
|
||||
keyboard_input: Res<ButtonInput<KeyCode>>,
|
||||
mut settings: ResMut<settings::Settings>,
|
||||
) {
|
||||
if keyboard_input.just_pressed(settings.key_camera) {
|
||||
settings.third_person ^= true;
|
||||
}
|
||||
}
|
||||
|
||||
fn manage_player_actor(
|
||||
settings: Res<settings::Settings>,
|
||||
mut q_playercam: Query<&mut Visibility, With<actor::PlayerCamera>>,
|
||||
mut q_hiddenplayer: Query<&mut Visibility, (With<actor::Player>, Without<actor::PlayerCamera>)>,
|
||||
) {
|
||||
for mut vis in &mut q_playercam {
|
||||
if settings.third_person {
|
||||
*vis = Visibility::Inherited;
|
||||
}
|
||||
else {
|
||||
*vis = Visibility::Hidden;
|
||||
}
|
||||
}
|
||||
for mut vis in &mut q_hiddenplayer {
|
||||
*vis = Visibility::Hidden;
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn run_camera_controller(
|
||||
fn apply_input_to_player(
|
||||
time: Res<Time>,
|
||||
settings: Res<settings::Settings>,
|
||||
mut windows: Query<&mut Window, With<PrimaryWindow>>,
|
||||
|
@ -48,15 +120,12 @@ fn run_camera_controller(
|
|||
thruster_sound_controller: Query<&AudioSink, With<audio::ComponentThrusterSound>>,
|
||||
rocket_sound_controller: Query<&AudioSink, With<audio::ComponentRocketSound>>,
|
||||
ion_sound_controller: Query<&AudioSink, With<audio::ComponentIonSound>>,
|
||||
mut q_engine: Query<&mut actor::Engine, With<actor::PlayerDrivesThis>>,
|
||||
mut query: Query<(
|
||||
mut q_playercam: Query<(
|
||||
&mut Transform,
|
||||
&mut CameraController,
|
||||
&mut Projection,
|
||||
&mut actor::Actor,
|
||||
&actor::LifeForm,
|
||||
&mut actor::Engine
|
||||
), (With<Camera>, Without<actor::PlayerDrivesThis>)>,
|
||||
&mut actor::Engine,
|
||||
&mut AngularVelocity,
|
||||
&mut LinearVelocity,
|
||||
), (With<actor::PlayerCamera>, Without<Camera>)>,
|
||||
) {
|
||||
let dt = time.delta_seconds();
|
||||
let mut play_thruster_sound = false;
|
||||
|
@ -67,31 +136,31 @@ fn run_camera_controller(
|
|||
focused = window_result.unwrap().focused;
|
||||
}
|
||||
|
||||
if let Ok((mut transform, mut controller, mut projection, mut actor, lifeform, player_engine)) = query.get_single_mut() {
|
||||
if !controller.initialized {
|
||||
controller.initialized = true;
|
||||
transform.rotation =
|
||||
Quat::from_euler(EulerRot::ZYX, 0.0, controller.yaw, controller.pitch);
|
||||
if let Ok((mut player_transform, mut engine, mut angularvelocity, mut v)) = q_playercam.get_single_mut() {
|
||||
|
||||
if angularvelocity.length_squared() > 0.0001 {
|
||||
angularvelocity.x *= 0.98;
|
||||
angularvelocity.y *= 0.98;
|
||||
angularvelocity.z *= 0.98;
|
||||
}
|
||||
if !controller.enabled {
|
||||
mouse_events.clear();
|
||||
return;
|
||||
else {
|
||||
angularvelocity.0 = Vec3::splat(0.0);
|
||||
}
|
||||
|
||||
// Handle key input
|
||||
let mut axis_input = Vec3::ZERO;
|
||||
if focused {
|
||||
if key_input.pressed(settings.key_forward) {
|
||||
axis_input.z -= 1.2;
|
||||
}
|
||||
if key_input.pressed(settings.key_back) {
|
||||
axis_input.z += 1.2;
|
||||
}
|
||||
if key_input.pressed(settings.key_back) {
|
||||
axis_input.z -= 1.2;
|
||||
}
|
||||
if key_input.pressed(settings.key_right) {
|
||||
axis_input.x += 1.2;
|
||||
axis_input.x -= 1.2;
|
||||
}
|
||||
if key_input.pressed(settings.key_left) {
|
||||
axis_input.x -= 1.2;
|
||||
axis_input.x += 1.2;
|
||||
}
|
||||
if key_input.pressed(settings.key_up) {
|
||||
axis_input.y += 1.2;
|
||||
|
@ -100,9 +169,9 @@ fn run_camera_controller(
|
|||
axis_input.y -= 1.2;
|
||||
}
|
||||
if key_input.pressed(settings.key_stop) {
|
||||
let stop_direction = -actor.v.normalize();
|
||||
let stop_direction = -v.normalize();
|
||||
if stop_direction.length_squared() > 0.3 {
|
||||
axis_input += 1.0 * (transform.rotation.inverse() * stop_direction);
|
||||
axis_input += 1.0 * (player_transform.rotation.inverse() * stop_direction);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -113,10 +182,8 @@ fn run_camera_controller(
|
|||
// total diagonal acceleration is faster than the forward acceleration alone.
|
||||
axis_input = axis_input.clamp(Vec3::splat(-1.0), Vec3::splat(1.0));
|
||||
|
||||
let mut engine = if let Ok(engine) = q_engine.get_single_mut() { engine } else { player_engine };
|
||||
|
||||
// Apply movement update
|
||||
let forward_factor = engine.current_warmup * (if axis_input.z < 0.0 {
|
||||
let forward_factor = engine.current_warmup * (if axis_input.z > 0.0 {
|
||||
engine.thrust_forward
|
||||
} else {
|
||||
engine.thrust_back
|
||||
|
@ -126,22 +193,22 @@ fn run_camera_controller(
|
|||
let factor = Vec3::new(right_factor, up_factor, forward_factor);
|
||||
|
||||
if axis_input.length_squared() > 0.003 {
|
||||
let acceleration_global = transform.rotation * (axis_input * factor);
|
||||
let acceleration_global = player_transform.rotation * (axis_input * factor);
|
||||
let mut acceleration_total = actor::ENGINE_SPEED_FACTOR * dt * acceleration_global;
|
||||
let threshold = 1e-5;
|
||||
if key_input.pressed(settings.key_stop) {
|
||||
for i in 0..3 {
|
||||
if actor.v[i].abs() < threshold {
|
||||
actor.v[i] = 0.0;
|
||||
if v[i].abs() < threshold {
|
||||
v[i] = 0.0;
|
||||
}
|
||||
else if actor.v[i].signum() != (actor.v[i] + acceleration_total[i]).signum() {
|
||||
else if v[i].signum() != (v[i] + acceleration_total[i]).signum() {
|
||||
// Overshoot
|
||||
actor.v[i] = 0.0;
|
||||
v[i] = 0.0;
|
||||
acceleration_total[i] = 0.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
actor.v += acceleration_total;
|
||||
v.0 += acceleration_total;
|
||||
engine.current_warmup = (engine.current_warmup + dt / engine.warmup_seconds).clamp(0.0, 1.0);
|
||||
play_thruster_sound = !settings.mute_sfx;
|
||||
}
|
||||
|
@ -157,17 +224,11 @@ fn run_camera_controller(
|
|||
|
||||
if mouse_delta != Vec2::ZERO {
|
||||
// Apply look update
|
||||
controller.pitch = (controller.pitch
|
||||
- mouse_delta.y * RADIANS_PER_DOT * controller.sensitivity)
|
||||
.clamp(-PI / 2., PI / 2.);
|
||||
controller.yaw -= mouse_delta.x * RADIANS_PER_DOT * controller.sensitivity;
|
||||
transform.rotation =
|
||||
Quat::from_euler(EulerRot::ZYX, 0.0, controller.yaw, controller.pitch);
|
||||
let pitch = (mouse_delta.y * RADIANS_PER_DOT * settings.mouse_sensitivity).clamp(-PI / 2., PI / 2.);
|
||||
let yaw = mouse_delta.x * RADIANS_PER_DOT * settings.mouse_sensitivity;
|
||||
player_transform.rotation *= Quat::from_euler(EulerRot::ZYX, 0.0, -yaw, pitch).normalize();
|
||||
}
|
||||
|
||||
let fov = (lifeform.adrenaline * lifeform.adrenaline * lifeform.adrenaline * 45.0 + 45.0).to_radians();
|
||||
*projection = Projection::Perspective(PerspectiveProjection { fov: fov, ..default() });
|
||||
|
||||
if let Ok(sink) = thruster_sound_controller.get_single() {
|
||||
if play_thruster_sound && engine.engine_type == actor::EngineType::Monopropellant {
|
||||
sink.play()
|
||||
|
|
18
src/defs.txt
18
src/defs.txt
|
@ -1,3 +1,13 @@
|
|||
actor 0 0 0 suit
|
||||
player yes
|
||||
mass 200.0
|
||||
scale 1
|
||||
oxygen 0.008
|
||||
health 0.3
|
||||
collider capsule 2 1
|
||||
thrust 1.2 1 1 1 1.5
|
||||
engine monopropellant
|
||||
|
||||
actor 300000 0 500000 jupiter
|
||||
scale 200000
|
||||
rotationy -1.40
|
||||
|
@ -12,6 +22,11 @@ actor 1000 20 300 monolith
|
|||
rotationx 0.5
|
||||
angularmomentum 0.0 0.0 0.01
|
||||
|
||||
actor 10 20 30 monolith
|
||||
scale 2
|
||||
rotationx 0.5
|
||||
angularmomentum 0.0 0.0 0.01
|
||||
|
||||
actor 10000 2000 -3500 monolith
|
||||
scale 2
|
||||
rotationx 0.5
|
||||
|
@ -97,6 +112,9 @@ actor 10 -30 20 MeteorAceGT
|
|||
vehicle yes
|
||||
thrust 70 13.7 9.4 0.5 20
|
||||
engine ion
|
||||
collider sphere 1.5
|
||||
camdistance 50
|
||||
mass 500
|
||||
|
||||
actor 10 0 70 suit
|
||||
name Icarus
|
||||
|
|
12
src/hud.rs
12
src/hud.rs
|
@ -1,6 +1,7 @@
|
|||
use crate::{settings, actor, audio, nature};
|
||||
use bevy::prelude::*;
|
||||
use bevy::diagnostic::{DiagnosticsStore, FrameTimeDiagnosticsPlugin};
|
||||
use bevy_xpbd_3d::prelude::*;
|
||||
use std::collections::VecDeque;
|
||||
use std::time::SystemTime;
|
||||
|
||||
|
@ -370,7 +371,8 @@ fn update(
|
|||
diagnostics: Res<DiagnosticsStore>,
|
||||
time: Res<Time>,
|
||||
mut log: ResMut<Log>,
|
||||
player: Query<(&actor::Suit, &actor::LifeForm, &actor::Actor), With<actor::Player>>,
|
||||
player: Query<(&actor::Suit, &actor::LifeForm), With<actor::Player>>,
|
||||
q_camera: Query<&LinearVelocity, With<actor::PlayerCamera>>,
|
||||
mut timer: ResMut<FPSUpdateTimer>,
|
||||
mut query: Query<&mut Text, With<GaugesText>>,
|
||||
q_choices: Query<&ChoiceAvailable>,
|
||||
|
@ -380,9 +382,11 @@ fn update(
|
|||
) {
|
||||
// TODO only when hud is actually on
|
||||
if timer.0.tick(time.delta()).just_finished() || log.needs_rerendering {
|
||||
let q_camera_result = q_camera.get_single();
|
||||
let player = player.get_single();
|
||||
if player.is_ok() {
|
||||
let (suit, lifeform, actor) = player.unwrap();
|
||||
if player.is_ok() && q_camera_result.is_ok() {
|
||||
let (suit, lifeform) = player.unwrap();
|
||||
let cam_v = q_camera_result.unwrap();
|
||||
for mut text in &mut query {
|
||||
if let Some(fps) = diagnostics.get(&FrameTimeDiagnosticsPlugin::FPS) {
|
||||
if let Some(value) = fps.smoothed() {
|
||||
|
@ -409,7 +413,7 @@ fn update(
|
|||
text.sections[10].value = format!("{all_actors:.0}");
|
||||
let integrity = suit.integrity * 100.0;
|
||||
text.sections[12].value = format!("{integrity:.0}%");
|
||||
let speed = actor.v.length();
|
||||
let speed = cam_v.length();
|
||||
let kmh = speed * 60.0 * 60.0 / 1000.0;
|
||||
text.sections[14].value = format!("{speed:.0}m/s | {kmh:.0}km/h");
|
||||
}
|
||||
|
|
|
@ -28,10 +28,9 @@ fn main() {
|
|||
}
|
||||
}
|
||||
if cfg!(debug_assertions) {
|
||||
App::new().add_plugins((
|
||||
OutFlyPlugin,
|
||||
)).run();
|
||||
App::new().add_plugins(OutFlyPlugin).run();
|
||||
} else {
|
||||
// In release builds, embed assets into the binary
|
||||
App::new().add_plugins((
|
||||
EmbeddedAssetPlugin { mode: PluginMode::ReplaceDefault },
|
||||
OutFlyPlugin,
|
||||
|
|
|
@ -7,9 +7,11 @@ pub struct Settings {
|
|||
pub mute_music: bool,
|
||||
pub volume_sfx: u8,
|
||||
pub volume_music: u8,
|
||||
pub mouse_sensitivity: f32,
|
||||
pub font_size_hud: f32,
|
||||
pub font_size_conversations: f32,
|
||||
pub hud_active: bool,
|
||||
pub third_person: bool,
|
||||
pub key_togglehud: KeyCode,
|
||||
pub key_exit: KeyCode,
|
||||
pub key_restart: KeyCode,
|
||||
|
@ -24,6 +26,7 @@ pub struct Settings {
|
|||
pub key_stop: KeyCode,
|
||||
pub key_interact: KeyCode,
|
||||
pub key_vehicle: KeyCode,
|
||||
pub key_camera: KeyCode,
|
||||
pub key_reply1: KeyCode,
|
||||
pub key_reply2: KeyCode,
|
||||
pub key_reply3: KeyCode,
|
||||
|
@ -53,9 +56,11 @@ impl Default for Settings {
|
|||
mute_music: default_mute_music,
|
||||
volume_sfx: 100,
|
||||
volume_music: 100,
|
||||
mouse_sensitivity: 0.5,
|
||||
font_size_hud: 32.0,
|
||||
font_size_conversations: 32.0,
|
||||
hud_active: false,
|
||||
third_person: false,
|
||||
key_togglehud: KeyCode::Tab,
|
||||
key_exit: KeyCode::Escape,
|
||||
key_restart: KeyCode::F12,
|
||||
|
@ -70,6 +75,7 @@ impl Default for Settings {
|
|||
key_stop: KeyCode::Space,
|
||||
key_interact: KeyCode::KeyE,
|
||||
key_vehicle: KeyCode::KeyQ,
|
||||
key_camera: KeyCode::KeyF,
|
||||
key_reply1: KeyCode::Digit1,
|
||||
key_reply2: KeyCode::Digit2,
|
||||
key_reply3: KeyCode::Digit3,
|
||||
|
|
199
src/world.rs
199
src/world.rs
|
@ -1,12 +1,12 @@
|
|||
extern crate regex;
|
||||
use crate::{actor, camera, nature};
|
||||
use crate::{actor, nature};
|
||||
use regex::Regex;
|
||||
use bevy::prelude::*;
|
||||
//use bevy::core_pipeline::Skybox;
|
||||
//use bevy::asset::LoadState;
|
||||
//use bevy::render::render_resource::{TextureViewDescriptor, TextureViewDimension};
|
||||
use bevy::pbr::CascadeShadowConfigBuilder;
|
||||
use bevy::core_pipeline::bloom::{BloomCompositeMode, BloomSettings};
|
||||
use bevy_xpbd_3d::prelude::*;
|
||||
use std::f32::consts::PI;
|
||||
|
||||
const ASTEROID_SIZE: f32 = 100.0;
|
||||
|
@ -40,7 +40,10 @@ impl Plugin for WorldPlugin {
|
|||
app.add_systems(Startup, (setup, load_defs));
|
||||
//app.add_systems(Update, asset_loaded.after(load_cubemap_asset));
|
||||
//app.add_systems(Update, swap_world_on_ar_toggle);
|
||||
app.add_plugins(PhysicsPlugins::default());
|
||||
//app.add_plugins(PhysicsDebugPlugin::default());
|
||||
app.insert_resource(ClearColor(Color::rgb(0.0, 0.0, 0.0)));
|
||||
app.insert_resource(Gravity(Vec3::splat(0.0)));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -78,43 +81,6 @@ pub fn setup(
|
|||
// cubemap_ar_handle: asset_server.load(ASSET_CUBEMAP_AR),
|
||||
// });
|
||||
|
||||
// Add player
|
||||
commands.spawn((
|
||||
actor::Player,
|
||||
actor::Actor {
|
||||
angular_momentum: Quat::IDENTITY,
|
||||
..default()
|
||||
},
|
||||
actor::LifeForm::default(),
|
||||
actor::Suit {
|
||||
oxygen: nature::OXY_H,
|
||||
integrity: 0.3,
|
||||
..default()
|
||||
},
|
||||
actor::Engine {
|
||||
thrust_forward: 1.2,
|
||||
..default()
|
||||
},
|
||||
Visibility::Visible,
|
||||
Camera3dBundle {
|
||||
camera: Camera {
|
||||
hdr: true, // HDR is required for bloom
|
||||
..default()
|
||||
},
|
||||
transform: Transform::from_xyz(0.0, 0.0, 8.0).looking_at(Vec3::ZERO, Vec3::Y),
|
||||
..default()
|
||||
},
|
||||
camera::CameraController::default(),
|
||||
// Skybox {
|
||||
// image: cubemap_handle,
|
||||
// brightness: SKYBOX_BRIGHTNESS,
|
||||
// },
|
||||
BloomSettings {
|
||||
composite_mode: BloomCompositeMode::EnergyConserving,
|
||||
..default()
|
||||
},
|
||||
));
|
||||
|
||||
// Generate a bunch of asteriods
|
||||
let maxdist = 10;
|
||||
for i in -maxdist..maxdist {
|
||||
|
@ -238,6 +204,7 @@ struct ParserState {
|
|||
rotation: Quat,
|
||||
angular_momentum: Quat,
|
||||
pronoun: String,
|
||||
is_player: bool,
|
||||
is_lifeform: bool,
|
||||
is_alive: bool,
|
||||
is_suited: bool,
|
||||
|
@ -249,6 +216,9 @@ struct ParserState {
|
|||
warmup_seconds: f32,
|
||||
engine_type: actor::EngineType,
|
||||
oxygen: f32,
|
||||
mass: f32,
|
||||
collider: Collider,
|
||||
camdistance: f32,
|
||||
|
||||
// Chat fields
|
||||
delay: f64,
|
||||
|
@ -278,6 +248,7 @@ impl Default for ParserState {
|
|||
rotation: Quat::IDENTITY,
|
||||
angular_momentum: default_actor.angular_momentum,
|
||||
pronoun: "they/them".to_string(),
|
||||
is_player: false,
|
||||
is_lifeform: false,
|
||||
is_alive: false,
|
||||
is_suited: false,
|
||||
|
@ -289,6 +260,9 @@ impl Default for ParserState {
|
|||
warmup_seconds: default_engine.warmup_seconds,
|
||||
engine_type: default_engine.engine_type,
|
||||
oxygen: nature::OXY_D,
|
||||
mass: 1.0,
|
||||
collider: Collider::sphere(1.0),
|
||||
camdistance: default_actor.camdistance,
|
||||
|
||||
delay: 0.0,
|
||||
text: "".to_string(),
|
||||
|
@ -345,32 +319,14 @@ impl ParserState {
|
|||
self.reset_message();
|
||||
}
|
||||
fn spawn_actor(&mut self, commands: &mut Commands, asset_server: &Res<AssetServer>) {
|
||||
let component_actor = actor::Actor {
|
||||
let mut actor = commands.spawn_empty();
|
||||
actor.insert(actor::Actor {
|
||||
angular_momentum: self.angular_momentum,
|
||||
id: self.id.clone(),
|
||||
camdistance: self.camdistance,
|
||||
..default()
|
||||
};
|
||||
let component_lifeform = actor::LifeForm::default();
|
||||
let component_talker = actor::Talker {
|
||||
conv_id: self.chat.clone(),
|
||||
..default()
|
||||
};
|
||||
let component_vehicle = actor::Vehicle;
|
||||
let component_engine = actor::Engine {
|
||||
thrust_forward: self.thrust_forward,
|
||||
thrust_back: self.thrust_back,
|
||||
thrust_sideways: self.thrust_sideways,
|
||||
reaction_wheels: self.reaction_wheels,
|
||||
warmup_seconds: self.warmup_seconds,
|
||||
engine_type: self.engine_type,
|
||||
..default()
|
||||
};
|
||||
let component_suit = actor::Suit {
|
||||
oxygen: self.oxygen,
|
||||
oxygen_max: nature::OXY_D,
|
||||
..default()
|
||||
};
|
||||
let component_model = SceneBundle {
|
||||
});
|
||||
actor.insert(SceneBundle {
|
||||
transform: Transform {
|
||||
translation: self.pos,
|
||||
scale: Vec3::splat(self.model_scale),
|
||||
|
@ -378,55 +334,50 @@ impl ParserState {
|
|||
},
|
||||
scene: asset_server.load(asset_name_to_path(self.model.as_str())),
|
||||
..default()
|
||||
};
|
||||
});
|
||||
|
||||
// TODO: is there a more dynamic way to construct this...?
|
||||
info!("Spawning actor {} with model {} at {}/{}/{}",
|
||||
self.name, self.model, self.pos.x, self.pos.y, self.pos.z);
|
||||
// Physics Parameters
|
||||
let fix_scale = 1.0 / self.model_scale.powf(3.0);
|
||||
actor.insert(RigidBody::Dynamic);
|
||||
actor.insert(self.collider.clone());
|
||||
actor.insert(ColliderDensity(self.mass * fix_scale));
|
||||
|
||||
// Optional Components
|
||||
if self.is_player {
|
||||
actor.insert(actor::Player);
|
||||
actor.insert(actor::PlayerCamera);
|
||||
}
|
||||
if self.is_lifeform {
|
||||
actor.insert(actor::LifeForm::default());
|
||||
actor.insert(actor::Suit {
|
||||
oxygen: self.oxygen,
|
||||
oxygen_max: nature::OXY_D,
|
||||
..default()
|
||||
});
|
||||
}
|
||||
if !self.chat.is_empty() {
|
||||
commands.spawn((
|
||||
component_actor,
|
||||
component_lifeform,
|
||||
component_suit,
|
||||
component_talker,
|
||||
component_model,
|
||||
));
|
||||
actor.insert(actor::Talker {
|
||||
conv_id: self.chat.clone(),
|
||||
..default()
|
||||
});
|
||||
}
|
||||
else {
|
||||
commands.spawn((
|
||||
component_actor,
|
||||
component_lifeform,
|
||||
component_suit,
|
||||
component_model,
|
||||
));
|
||||
}
|
||||
}
|
||||
else {
|
||||
if !self.chat.is_empty() {
|
||||
commands.spawn((
|
||||
component_actor,
|
||||
component_talker,
|
||||
component_model,
|
||||
));
|
||||
}
|
||||
else {
|
||||
if self.is_vehicle {
|
||||
commands.spawn((
|
||||
component_actor,
|
||||
component_model,
|
||||
component_vehicle,
|
||||
component_engine,
|
||||
));
|
||||
}
|
||||
else {
|
||||
commands.spawn((
|
||||
component_actor,
|
||||
component_model,
|
||||
));
|
||||
}
|
||||
actor.insert(actor::Vehicle);
|
||||
}
|
||||
if self.is_vehicle || self.is_suited {
|
||||
actor.insert(actor::Engine {
|
||||
thrust_forward: self.thrust_forward,
|
||||
thrust_back: self.thrust_back,
|
||||
thrust_sideways: self.thrust_sideways,
|
||||
reaction_wheels: self.reaction_wheels,
|
||||
warmup_seconds: self.warmup_seconds,
|
||||
engine_type: self.engine_type,
|
||||
..default()
|
||||
});
|
||||
}
|
||||
|
||||
//info!("Spawning actor {} with model {} at {}/{}/{}",
|
||||
// self.name, self.model, self.pos.x, self.pos.y, self.pos.z);
|
||||
self.reset();
|
||||
}
|
||||
fn spawn_entities(&mut self, commands: &mut Commands, asset_server: &Res<AssetServer>) {
|
||||
|
@ -580,6 +531,46 @@ pub fn load_defs(
|
|||
["engine", "ion"] => {
|
||||
state.engine_type = actor::EngineType::Ion;
|
||||
}
|
||||
["mass", value] => {
|
||||
if let Ok(value_float) = value.parse::<f32>() {
|
||||
state.mass = value_float;
|
||||
}
|
||||
else {
|
||||
error!("Can't parse float: {line}");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
["collider", "sphere", radius] => {
|
||||
if let Ok(radius_float) = radius.parse::<f32>() {
|
||||
state.collider = Collider::sphere(radius_float);
|
||||
}
|
||||
else {
|
||||
error!("Can't parse float: {line}");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
["collider", "capsule", height, radius] => {
|
||||
if let (Ok(height_float), Ok(radius_float)) = (height.parse::<f32>(), radius.parse::<f32>()) {
|
||||
state.collider = Collider::capsule(height_float, radius_float);
|
||||
}
|
||||
else {
|
||||
error!("Can't parse float: {line}");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
["player", "yes"] => {
|
||||
state.is_player = true;
|
||||
state.is_alive = true;
|
||||
}
|
||||
["camdistance", value] => {
|
||||
if let Ok(value_float) = value.parse::<f32>() {
|
||||
state.camdistance = value_float;
|
||||
}
|
||||
else {
|
||||
error!("Can't parse float: {line}");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Parsing chats
|
||||
["chat", chat_name] => {
|
||||
|
|
Loading…
Reference in a new issue