From d66a26d63cf368a8829c068dc33e089d1a8ba05b Mon Sep 17 00:00:00 2001 From: Joe Ardent Date: Mon, 22 Jul 2024 15:33:14 -0700 Subject: [PATCH] fix PID params for lean; fix camera wobble; add torque arrow gizmo --- Cargo.lock | 530 ++++++++++++++++++++++++++++++++++++++++++++++++- Cargo.toml | 1 + src/bike.rs | 58 ++++++ src/camera.rs | 98 +++++++++ src/main.rs | 176 +--------------- src/physics.rs | 166 ++++++++++++++++ 6 files changed, 863 insertions(+), 166 deletions(-) create mode 100644 src/bike.rs create mode 100644 src/camera.rs create mode 100644 src/physics.rs diff --git a/Cargo.lock b/Cargo.lock index 9e7e4a9..1c8f05d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -180,6 +180,24 @@ dependencies = [ "num-traits", ] +[[package]] +name = "arboard" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fb4009533e8ff8f1450a5bcbc30f4242a1d34442221f72314bea1f5dc9c7f89" +dependencies = [ + "clipboard-win", + "core-graphics", + "image 0.25.2", + "log", + "objc2", + "objc2-app-kit", + "objc2-foundation", + "parking_lot", + "windows-sys 0.48.0", + "x11rb", +] + [[package]] name = "arrayref" version = "0.3.8" @@ -333,6 +351,50 @@ dependencies = [ "bevy_internal", ] +[[package]] +name = "bevy-inspector-egui" +version = "0.25.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8d77dbe53c8840aa74b66ea19dac6675d0a1752c989610cbded909d03967bec" +dependencies = [ + "bevy-inspector-egui-derive", + "bevy_app", + "bevy_asset", + "bevy_color", + "bevy_core", + "bevy_core_pipeline", + "bevy_ecs", + "bevy_egui", + "bevy_hierarchy", + "bevy_log", + "bevy_math", + "bevy_pbr", + "bevy_reflect", + "bevy_render", + "bevy_state", + "bevy_time", + "bevy_utils", + "bevy_window", + "bytemuck", + "egui", + "fuzzy-matcher", + "image 0.24.9", + "once_cell", + "pretty-type-name", + "smallvec", +] + +[[package]] +name = "bevy-inspector-egui-derive" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "161d93f4b3a9246a87485e30ccf4cc927f204a14f26df42da977e383f0a0ec5d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.71", +] + [[package]] name = "bevy_a11y" version = "0.14.0" @@ -598,6 +660,28 @@ dependencies = [ "syn 2.0.71", ] +[[package]] +name = "bevy_egui" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e4a90f30f2849a07d91e393b10c0cc05df09b5773c010ddde57dd8b583be230" +dependencies = [ + "arboard", + "bevy", + "bytemuck", + "console_log", + "crossbeam-channel", + "egui", + "js-sys", + "log", + "thread_local", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "webbrowser", + "winit", +] + [[package]] name = "bevy_encase_derive" version = "0.14.0" @@ -907,7 +991,7 @@ dependencies = [ "encase", "futures-lite", "hexasphere", - "image", + "image 0.25.2", "js-sys", "ktx2", "naga", @@ -1320,6 +1404,18 @@ dependencies = [ "thiserror", ] +[[package]] +name = "calloop-wayland-source" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95a66a987056935f7efce4ab5668920b5d0dac4a7c99991a67395f13702ddd20" +dependencies = [ + "calloop", + "rustix", + "wayland-backend", + "wayland-client", +] + [[package]] name = "cc" version = "1.1.6" @@ -1374,6 +1470,15 @@ dependencies = [ "libloading 0.8.5", ] +[[package]] +name = "clipboard-win" +version = "5.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15efe7a882b08f34e38556b14f2fb3daa98769d06c7f0c1b076dfd0d983bc892" +dependencies = [ + "error-code", +] + [[package]] name = "codespan-reporting" version = "0.11.1" @@ -1384,6 +1489,12 @@ dependencies = [ "unicode-width", ] +[[package]] +name = "color_quant" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" + [[package]] name = "com" version = "0.6.0" @@ -1444,6 +1555,16 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "console_log" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be8aed40e4edbf4d3b4431ab260b63fdc40f5780a4766824329ea0f1eefe3c0f" +dependencies = [ + "log", + "web-sys", +] + [[package]] name = "const-fnv1a-hash" version = "1.1.0" @@ -1687,12 +1808,43 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f25c0e292a7ca6d6498557ff1df68f32c99850012b6ea401cf8daf771f22ff53" +[[package]] +name = "ecolor" +version = "0.28.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e6b451ff1143f6de0f33fc7f1b68fecfd2c7de06e104de96c4514de3f5396f8" +dependencies = [ + "bytemuck", + "emath", +] + +[[package]] +name = "egui" +version = "0.28.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20c97e70a2768de630f161bb5392cbd3874fcf72868f14df0e002e82e06cb798" +dependencies = [ + "ahash", + "emath", + "epaint", + "nohash-hasher", +] + [[package]] name = "either" version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" +[[package]] +name = "emath" +version = "0.28.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a6a21708405ea88f63d8309650b4d77431f4bc28fb9d8e6f77d3963b51249e6" +dependencies = [ + "bytemuck", +] + [[package]] name = "encase" version = "0.8.0" @@ -1725,6 +1877,21 @@ dependencies = [ "syn 2.0.71", ] +[[package]] +name = "epaint" +version = "0.28.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f0dcc0a0771e7500e94cd1cb797bd13c9f23b9409bdc3c824e2cbc562b7fa01" +dependencies = [ + "ab_glyph", + "ahash", + "bytemuck", + "ecolor", + "emath", + "nohash-hasher", + "parking_lot", +] + [[package]] name = "equivalent" version = "1.0.1" @@ -1751,6 +1918,12 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "error-code" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0474425d51df81997e2f90a21591180b38eccf27292d755f3e30750225c175b" + [[package]] name = "euclid" version = "0.22.10" @@ -1857,6 +2030,15 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b" +[[package]] +name = "form_urlencoded" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +dependencies = [ + "percent-encoding", +] + [[package]] name = "futures-core" version = "0.3.30" @@ -1882,6 +2064,15 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "fuzzy-matcher" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54614a3312934d066701a80f20f15fa3b56d67ac7722b39eea5b4c9dd1d66c94" +dependencies = [ + "thread_local", +] + [[package]] name = "fxhash" version = "0.2.1" @@ -2160,6 +2351,37 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dfa686283ad6dd069f105e5ab091b04c62850d3e4cf5d67debad1933f55023df" +[[package]] +name = "home" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "idna" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "image" +version = "0.24.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5690139d2f55868e080017335e4b94cb7414274c74f1669c84fb5feba2c9f69d" +dependencies = [ + "bytemuck", + "byteorder", + "color_quant", + "num-traits", +] + [[package]] name = "image" version = "0.25.2" @@ -2170,6 +2392,7 @@ dependencies = [ "byteorder-lite", "num-traits", "png", + "tiff", ] [[package]] @@ -2282,6 +2505,12 @@ dependencies = [ "libc", ] +[[package]] +name = "jpeg-decoder" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5d4a7da358eff58addd2877a45865158f0d78c911d43a5784ceb7bbf52833b0" + [[package]] name = "js-sys" version = "0.3.69" @@ -2464,6 +2693,15 @@ version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +[[package]] +name = "memmap2" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe751422e4a8caa417e13c3ea66452215d7d63e19e604f4980461212f3ae1322" +dependencies = [ + "libc", +] + [[package]] name = "metal" version = "0.28.0" @@ -2630,6 +2868,12 @@ dependencies = [ "libc", ] +[[package]] +name = "nohash-hasher" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bf50223579dc7cdcfb3bfcacf7069ff68243f8c363f62ffa99cf000a6b9c451" + [[package]] name = "nom" version = "7.1.3" @@ -3114,6 +3358,7 @@ version = "0.1.0" dependencies = [ "avian3d", "bevy", + "bevy-inspector-egui", ] [[package]] @@ -3202,6 +3447,12 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8cf8e6a8aa66ce33f63993ffc4ea4271eb5b0530a9002db8455ea6050c77bfa" +[[package]] +name = "pretty-type-name" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f73cdaf19b52e6143685c3606206e114a4dfa969d6b14ec3894c88eb38bd4b" + [[package]] name = "proc-macro-crate" version = "3.1.0" @@ -3226,6 +3477,15 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "43d84d1d7a6ac92673717f9f6d1518374ef257669c24ebc5ac25d5033828be58" +[[package]] +name = "quick-xml" +version = "0.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f24d770aeca0eacb81ac29dfbc55ebcc09312fdd1f8bbecdc7e4a84e000e3b4" +dependencies = [ + "memchr", +] + [[package]] name = "quote" version = "1.0.36" @@ -3459,12 +3719,31 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "scoped-tls" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" + [[package]] name = "scopeguard" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "sctk-adwaita" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6277f0217056f77f1d8f49f2950ac6c278c0d607c45f5ee99328d792ede24ec" +dependencies = [ + "ab_glyph", + "log", + "memmap2", + "smithay-client-toolkit", + "tiny-skia", +] + [[package]] name = "semver" version = "1.0.23" @@ -3566,6 +3845,31 @@ version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" +[[package]] +name = "smithay-client-toolkit" +version = "0.19.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3457dea1f0eb631b4034d61d4d8c32074caa6cd1ab2d59f2327bd8461e2c0016" +dependencies = [ + "bitflags 2.6.0", + "calloop", + "calloop-wayland-source", + "cursor-icon", + "libc", + "log", + "memmap2", + "rustix", + "thiserror", + "wayland-backend", + "wayland-client", + "wayland-csd-frame", + "wayland-cursor", + "wayland-protocols", + "wayland-protocols-wlr", + "wayland-scanner", + "xkeysym", +] + [[package]] name = "smol_str" version = "0.2.2" @@ -3602,6 +3906,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" +[[package]] +name = "strict-num" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6637bab7722d379c8b41ba849228d680cc12d0a45ba1fa2b48f2a30577a06731" + [[package]] name = "svg_fmt" version = "0.4.3" @@ -3696,6 +4006,42 @@ dependencies = [ "once_cell", ] +[[package]] +name = "tiff" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba1310fcea54c6a9a4fd1aad794ecc02c31682f6bfbecdf460bf19533eed1e3e" +dependencies = [ + "flate2", + "jpeg-decoder", + "weezl", +] + +[[package]] +name = "tiny-skia" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83d13394d44dae3207b52a326c0c85a8bf87f1541f23b0d143811088497b09ab" +dependencies = [ + "arrayref", + "arrayvec", + "bytemuck", + "cfg-if", + "log", + "tiny-skia-path", +] + +[[package]] +name = "tiny-skia-path" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c9e7fc0c2e86a30b117d0462aa261b72b7a99b7ebd7deb3a14ceda95c5bdc93" +dependencies = [ + "arrayref", + "bytemuck", + "strict-num", +] + [[package]] name = "tinyvec" version = "1.8.0" @@ -3839,12 +4185,27 @@ version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" +[[package]] +name = "unicode-bidi" +version = "0.3.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" + [[package]] name = "unicode-ident" version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +[[package]] +name = "unicode-normalization" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" +dependencies = [ + "tinyvec", +] + [[package]] name = "unicode-segmentation" version = "1.11.0" @@ -3863,6 +4224,17 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" +[[package]] +name = "url" +version = "2.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] + [[package]] name = "uuid" version = "1.10.0" @@ -3973,6 +4345,115 @@ version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" +[[package]] +name = "wayland-backend" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f90e11ce2ca99c97b940ee83edbae9da2d56a08f9ea8158550fd77fa31722993" +dependencies = [ + "cc", + "downcast-rs", + "rustix", + "scoped-tls", + "smallvec", + "wayland-sys", +] + +[[package]] +name = "wayland-client" +version = "0.31.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e321577a0a165911bdcfb39cf029302479d7527b517ee58ab0f6ad09edf0943" +dependencies = [ + "bitflags 2.6.0", + "rustix", + "wayland-backend", + "wayland-scanner", +] + +[[package]] +name = "wayland-csd-frame" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "625c5029dbd43d25e6aa9615e88b829a5cad13b2819c4ae129fdbb7c31ab4c7e" +dependencies = [ + "bitflags 2.6.0", + "cursor-icon", + "wayland-backend", +] + +[[package]] +name = "wayland-cursor" +version = "0.31.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ef9489a8df197ebf3a8ce8a7a7f0a2320035c3743f3c1bd0bdbccf07ce64f95" +dependencies = [ + "rustix", + "wayland-client", + "xcursor", +] + +[[package]] +name = "wayland-protocols" +version = "0.32.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62989625a776e827cc0f15d41444a3cea5205b963c3a25be48ae1b52d6b4daaa" +dependencies = [ + "bitflags 2.6.0", + "wayland-backend", + "wayland-client", + "wayland-scanner", +] + +[[package]] +name = "wayland-protocols-plasma" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f79f2d57c7fcc6ab4d602adba364bf59a5c24de57bd194486bf9b8360e06bfc4" +dependencies = [ + "bitflags 2.6.0", + "wayland-backend", + "wayland-client", + "wayland-protocols", + "wayland-scanner", +] + +[[package]] +name = "wayland-protocols-wlr" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd993de54a40a40fbe5601d9f1fbcaef0aebcc5fda447d7dc8f6dcbaae4f8953" +dependencies = [ + "bitflags 2.6.0", + "wayland-backend", + "wayland-client", + "wayland-protocols", + "wayland-scanner", +] + +[[package]] +name = "wayland-scanner" +version = "0.31.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7b56f89937f1cf2ee1f1259cf2936a17a1f45d8f0aa1019fae6d470d304cfa6" +dependencies = [ + "proc-macro2", + "quick-xml", + "quote", +] + +[[package]] +name = "wayland-sys" +version = "0.31.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43676fe2daf68754ecf1d72026e4e6c15483198b5d24e888b74d3f22f887a148" +dependencies = [ + "dlib", + "log", + "once_cell", + "pkg-config", +] + [[package]] name = "web-sys" version = "0.3.69" @@ -3993,6 +4474,30 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "webbrowser" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "425ba64c1e13b1c6e8c5d2541c8fac10022ca584f33da781db01b5756aef1f4e" +dependencies = [ + "block2", + "core-foundation", + "home", + "jni", + "log", + "ndk-context", + "objc2", + "objc2-foundation", + "url", + "web-sys", +] + +[[package]] +name = "weezl" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53a85b86a771b1c87058196170769dd264f66c0782acf1ae6cc51bfd64b39082" + [[package]] name = "wgpu" version = "0.20.1" @@ -4294,6 +4799,15 @@ dependencies = [ "windows-targets 0.42.2", ] +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", +] + [[package]] name = "windows-sys" version = "0.52.0" @@ -4487,6 +5001,7 @@ version = "0.30.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4225ddd8ab67b8b59a2fee4b34889ebf13c0460c1c3fa297c58e21eb87801b33" dependencies = [ + "ahash", "android-activity", "atomic-waker", "bitflags 2.6.0", @@ -4501,6 +5016,7 @@ dependencies = [ "dpi", "js-sys", "libc", + "memmap2", "ndk 0.9.0", "objc2", "objc2-app-kit", @@ -4512,11 +5028,17 @@ dependencies = [ "raw-window-handle", "redox_syscall 0.4.1", "rustix", + "sctk-adwaita", + "smithay-client-toolkit", "smol_str", "tracing", "unicode-segmentation", "wasm-bindgen", "wasm-bindgen-futures", + "wayland-backend", + "wayland-client", + "wayland-protocols", + "wayland-protocols-plasma", "web-sys", "web-time", "windows-sys 0.52.0", @@ -4575,6 +5097,12 @@ version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec107c4503ea0b4a98ef47356329af139c0a4f7750e621cf2973cd3385ebcb3d" +[[package]] +name = "xcursor" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d491ee231a51ae64a5b762114c3ac2104b967aadba1de45c86ca42cf051513b7" + [[package]] name = "xi-unicode" version = "0.3.0" diff --git a/Cargo.toml b/Cargo.toml index ea6ff76..0bcffb8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,6 +6,7 @@ edition = "2021" [dependencies] avian3d = "0.1.1" bevy = { version = "0.14.0", features = ["bevy_dev_tools"] } +bevy-inspector-egui = "0.25.1" [features] no-mesh = [] diff --git a/src/bike.rs b/src/bike.rs new file mode 100644 index 0000000..5cce4d3 --- /dev/null +++ b/src/bike.rs @@ -0,0 +1,58 @@ +use std::f32::consts::FRAC_PI_2; + +use avian3d::prelude::*; +use bevy::prelude::*; + +use crate::physics::CatControllerState; + +#[derive(Component)] +pub struct CyberBikeBody; + +fn spawn_bike( + mut commands: Commands, + mut meshes: ResMut>, + mut materials: ResMut>, +) { + let xform = Transform::from_xyz(0.0, 4.0, 0.0); + let body_collider = + Collider::capsule_endpoints(0.5, Vec3::new(0.0, 0.0, -0.65), Vec3::new(0.0, 0.0, 0.8)); + + let _bike = commands + .spawn(SpatialBundle::from_transform(xform)) + .insert(( + RigidBody::Dynamic, + body_collider, + CollisionLayers::from_bits(1, 1), + SleepingDisabled, + CyberBikeBody, + CatControllerState::default(), + ColliderDensity(0.12), + LinearDamping(0.1), + AngularDamping(2.0), + LinearVelocity::ZERO, + AngularVelocity::ZERO, + ExternalForce::ZERO.with_persistence(false), + ExternalTorque::ZERO.with_persistence(false), + )) + .with_children(|builder| { + let color = Color::srgb(0.7, 0.05, 0.7); + let mut rotation = Transform::default(); // Transform::from_rotation(Quat::from_rotation_y(FRAC_PI_2)); + rotation.rotate_x(FRAC_PI_2); + let pbr_bundle = PbrBundle { + mesh: meshes.add(Capsule3d::new(0.5, 1.45)), + transform: rotation, + material: materials.add(color), + ..Default::default() + }; + builder.spawn(pbr_bundle); + }) + .id(); +} + +pub struct CyberBikePlugin; + +impl Plugin for CyberBikePlugin { + fn build(&self, app: &mut App) { + app.add_systems(Startup, spawn_bike); + } +} diff --git a/src/camera.rs b/src/camera.rs new file mode 100644 index 0000000..da0e3b9 --- /dev/null +++ b/src/camera.rs @@ -0,0 +1,98 @@ +use bevy::{prelude::*, utils::HashSet}; + +use crate::bike::CyberBikeBody; + +#[derive(Component)] +pub struct CyberCameras; + +#[derive(Debug, Resource)] +pub struct DebugCamOffset { + pub rot: f32, + pub dist: f32, + pub alt: f32, +} + +impl Default for DebugCamOffset { + fn default() -> Self { + DebugCamOffset { + rot: 60.0, + dist: 10.0, + alt: 4.0, + } + } +} + +fn spawn_camera(mut commands: Commands) { + commands + .spawn(Camera3dBundle::default()) + .insert(CyberCameras); +} + +fn update_camera_pos(mut offset: ResMut, mut keys: ResMut>) { + let keyset: HashSet<_> = keys.get_pressed().collect(); + let shifted = keyset.contains(&KeyCode::ShiftLeft) || keyset.contains(&KeyCode::ShiftRight); + + for key in keyset { + match key { + KeyCode::ArrowLeft => offset.rot -= 5.0, + KeyCode::ArrowRight => offset.rot += 5.0, + KeyCode::ArrowUp => { + if shifted { + bevy::log::info!("up, shifted"); + offset.alt += 0.5; + } else { + bevy::log::info!("up"); + offset.dist -= 0.5; + } + } + KeyCode::ArrowDown => { + if shifted { + bevy::log::info!("down, shifted"); + offset.alt -= 0.5; + } else { + bevy::log::info!("down"); + offset.dist += 0.5; + } + } + _ => continue, + } + } + + let just_released: HashSet<_> = keys.get_just_released().cloned().collect(); + if !just_released.is_empty() { + let released_shift = just_released.contains(&KeyCode::ShiftLeft) + || just_released.contains(&KeyCode::ShiftRight); + keys.reset_all(); + if !released_shift && shifted { + keys.press(KeyCode::ShiftLeft); + } + } +} + +fn follow_bike( + mut camera: Query<&mut Transform, (With, Without)>, + bike: Query<&Transform, (With, Without)>, + offset: Res, +) { + let bike_xform = *bike.single(); + let up = Vec3::Y; + + let mut ncx = Transform::from_translation(bike_xform.translation); + ncx.rotate(Quat::from_axis_angle(up, offset.rot.to_radians())); + ncx.translation += ncx.forward() * offset.dist; + ncx.translation += ncx.up() * offset.alt; + ncx.look_at(bike_xform.translation, up); + + let mut cam_xform = camera.single_mut(); + *cam_xform = ncx; +} + +pub struct CamPlug; + +impl Plugin for CamPlug { + fn build(&self, app: &mut App) { + app.insert_resource(DebugCamOffset::default()) + .add_systems(Startup, spawn_camera) + .add_systems(Update, (follow_bike, update_camera_pos)); + } +} diff --git a/src/main.rs b/src/main.rs index aaf0a87..c2f0489 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,16 +1,23 @@ use avian3d::prelude::*; use bevy::{self, color::palettes::css::SILVER, prelude::*}; +use bevy_inspector_egui::quick::WorldInspectorPlugin; + +mod bike; +mod camera; +mod physics; + use bike::CyberBikePlugin; use camera::CamPlug; +use physics::CyberPhysicsPlugin; fn main() { let mut app = App::new(); app.add_plugins(( DefaultPlugins, - PhysicsPlugins::default(), - PhysicsDebugPlugin::default(), CamPlug, CyberBikePlugin, + CyberPhysicsPlugin, + WorldInspectorPlugin::new(), )) .insert_gizmo_config( PhysicsGizmos { @@ -19,7 +26,7 @@ fn main() { joint_separation_color: Some(Srgba::RED.into()), #[cfg(feature = "no-mesh")] hide_meshes: true, - //axis_lengths: Some(Vec3::ZERO), + axis_lengths: Some(Vec3::new(2.0, 2.0, 4.0)), ..Default::default() }, GizmoConfig::default(), @@ -40,7 +47,7 @@ fn ground_and_light( PbrBundle { mesh: meshes.add(Plane3d::default().mesh().size(50.0, 50.0)), material: materials.add(Color::from(SILVER)), - transform: Transform::from_xyz(0.0, 0.5, 0.0), + transform: Transform::from_xyz(0.0, -3., 0.0), ..default() }, )); @@ -72,164 +79,3 @@ fn close_on_esc( } } } - -mod bike { - use std::f32::consts::FRAC_PI_2; - - use avian3d::prelude::*; - use bevy::prelude::*; - - #[derive(Component)] - pub struct CyberBikeBody; - - fn spawn_bike( - mut commands: Commands, - mut meshes: ResMut>, - mut materials: ResMut>, - ) { - let xform = Transform::from_xyz(0.0, 4.0, 0.0); - let body_collider = - Collider::capsule_endpoints(0.5, Vec3::new(0.0, 0.0, -0.65), Vec3::new(0.0, 0.0, 0.8)); - - let _bike = commands - .spawn(SpatialBundle::from_transform(xform)) - .insert(( - RigidBody::Dynamic, - body_collider, - SleepingDisabled, - CyberBikeBody, - //CatControllerState::default(), - ColliderDensity(0.06), - LinearDamping(0.1), - AngularDamping(2.0), - LinearVelocity::ZERO, - AngularVelocity::ZERO, - ExternalForce::ZERO.with_persistence(false), - ExternalTorque::ZERO.with_persistence(false), - )) - .with_children(|builder| { - let color = Color::srgb(0.7, 0.05, 0.7); - let mut rotation = Transform::from_rotation(Quat::from_rotation_y(FRAC_PI_2)); - rotation.rotate_x(FRAC_PI_2); - let pbr_bundle = PbrBundle { - mesh: meshes.add(Capsule3d::new(0.5, 1.45)), - transform: rotation, - material: materials.add(color), - ..Default::default() - }; - builder.spawn(pbr_bundle); - }); - } - - pub struct CyberBikePlugin; - - impl Plugin for CyberBikePlugin { - fn build(&self, app: &mut App) { - app.add_systems(Startup, spawn_bike); - } - } -} - -mod camera { - use bevy::{prelude::*, utils::HashSet}; - - use crate::bike::CyberBikeBody; - - #[derive(Component)] - pub struct CyberCameras; - - #[derive(Debug, Resource)] - pub struct DebugCamOffset { - pub rot: f32, - pub dist: f32, - pub alt: f32, - } - - impl Default for DebugCamOffset { - fn default() -> Self { - DebugCamOffset { - rot: 60.0, - dist: 10.0, - alt: 4.0, - } - } - } - - fn spawn_camera(mut commands: Commands) { - commands - .spawn(Camera3dBundle::default()) - .insert(CyberCameras); - } - - fn update_camera_pos( - mut offset: ResMut, - mut keys: ResMut>, - ) { - let keyset: HashSet<_> = keys.get_pressed().collect(); - let shifted = keyset.contains(&KeyCode::ShiftLeft) || keyset.contains(&KeyCode::ShiftRight); - - for key in keyset { - match key { - KeyCode::ArrowLeft => offset.rot -= 5.0, - KeyCode::ArrowRight => offset.rot += 5.0, - KeyCode::ArrowUp => { - if shifted { - bevy::log::info!("up, shifted"); - offset.alt += 0.5; - } else { - bevy::log::info!("up"); - offset.dist -= 0.5; - } - } - KeyCode::ArrowDown => { - if shifted { - bevy::log::info!("down, shifted"); - offset.alt -= 0.5; - } else { - bevy::log::info!("down"); - offset.dist += 0.5; - } - } - _ => continue, - } - } - - let just_released: HashSet<_> = keys.get_just_released().cloned().collect(); - if !just_released.is_empty() { - let released_shift = just_released.contains(&KeyCode::ShiftLeft) - || just_released.contains(&KeyCode::ShiftRight); - keys.reset_all(); - if !released_shift && shifted { - keys.press(KeyCode::ShiftLeft); - } - } - } - - fn follow_bike( - mut camera: Query<&mut Transform, (With, Without)>, - bike: Query<&Transform, (With, Without)>, - offset: Res, - ) { - let bike_xform = *bike.single(); - let up = Vec3::Y; - - let mut ncx = bike_xform; - ncx.rotate(Quat::from_axis_angle(up, offset.rot.to_radians())); - ncx.translation += ncx.forward() * offset.dist; - ncx.translation += ncx.up() * offset.alt; - ncx.look_at(bike_xform.translation, up); - - let mut cam_xform = camera.single_mut(); - *cam_xform = ncx; - } - - pub struct CamPlug; - - impl Plugin for CamPlug { - fn build(&self, app: &mut App) { - app.insert_resource(DebugCamOffset::default()) - .add_systems(Startup, spawn_camera) - .add_systems(Update, (follow_bike, update_camera_pos)); - } - } -} diff --git a/src/physics.rs b/src/physics.rs new file mode 100644 index 0000000..044153c --- /dev/null +++ b/src/physics.rs @@ -0,0 +1,166 @@ +use avian3d::prelude::*; +use bevy::prelude::*; + +use crate::CyberBikePlugin; + +#[derive(Resource, Default, Debug, Reflect)] +#[reflect(Resource)] +struct CyberLean { + pub lean: f32, +} + +#[derive(Debug, Resource, Reflect)] +#[reflect(Resource)] +pub struct CatControllerSettings { + pub kp: f32, + pub kd: f32, + pub ki: f32, +} + +impl Default for CatControllerSettings { + fn default() -> Self { + Self { + kp: 10.0, + kd: 1.0, + ki: 0.1, + } + } +} + +#[derive(Component, Debug, Clone, Copy)] +pub struct CatControllerState { + pub roll_integral: f32, + pub roll_prev: f32, + decay_factor: f32, + roll_limit: f32, +} + +impl Default for CatControllerState { + fn default() -> Self { + Self { + roll_integral: Default::default(), + roll_prev: Default::default(), + decay_factor: 0.99, + roll_limit: 1.5, + } + } +} + +impl CatControllerState { + pub fn decay(&mut self) { + if self.roll_integral.abs() > 0.001 { + self.roll_integral *= self.decay_factor; + } + } + + pub fn update_roll(&mut self, error: f32, dt: f32) -> (f32, f32) { + let lim = self.roll_limit; + self.roll_integral = (self.roll_integral + (error * dt)).min(lim).max(-lim); + let derivative = (error - self.roll_prev) / dt; + self.roll_prev = error; + (derivative, self.roll_integral) + } + + pub fn set_integral_limits(&mut self, roll: f32) { + self.roll_limit = roll; + } +} + +mod systems { + use std::f32::consts::{FRAC_PI_3, FRAC_PI_4}; + + use avian3d::prelude::*; + use bevy::prelude::*; + + use super::{CatControllerSettings, CatControllerState, CyberLean}; + use crate::bike::CyberBikeBody; + + fn _yaw_to_angle(yaw: f32) -> f32 { + let v = yaw.powi(5) * FRAC_PI_4; + if v.is_normal() { + v + } else { + 0.0 + } + } + + fn rotate_point(pt: &Vec3, rot: &Quat) -> Vec3 { + // thanks to https://danceswithcode.net/engineeringnotes/quaternions/quaternions.html + let [x, y, z] = pt.normalize().to_array(); + let qpt = Quat::from_xyzw(x, y, z, 0.0); + // p' = rot^-1 * qpt * rot + let rot_qpt = rot.inverse() * qpt * *rot; + + // why does this need to be inverted??? + -Vec3::from_array([rot_qpt.x, rot_qpt.y, rot_qpt.z]) + } + + pub(super) fn calculate_lean( + bike_state: Query<(&LinearVelocity, &Transform), With>, + mut lean: ResMut, + ) { + let (velocity, xform) = bike_state.single(); + let vel = velocity.dot(*xform.forward()); + let v_squared = vel.powi(2); + let wheel_base = 1.145f32; + let radius = wheel_base; + let gravity = -9.8f32; + let v2_r = v_squared / radius; + let tan_theta = (v2_r / gravity).clamp(-FRAC_PI_3, FRAC_PI_3); + + if tan_theta.is_finite() && !tan_theta.is_subnormal() { + lean.lean = tan_theta.atan().clamp(-FRAC_PI_3, FRAC_PI_3); + } else { + lean.lean = 0.0; + } + } + + pub(super) fn apply_lean( + mut bike_query: Query<(&Transform, &mut ExternalTorque, &mut CatControllerState)>, + time: Res