Compare commits
53 commits
6d12033e23
...
838b8b7fd6
Author | SHA1 | Date | |
---|---|---|---|
yuni | 838b8b7fd6 | ||
yuni | 44e4c5493a | ||
yuni | 115cd1b46d | ||
yuni | 0d9bf25f52 | ||
yuni | c79320d072 | ||
yuni | 973506d335 | ||
yuni | 2c44d89c53 | ||
yuni | 7e56f1f07b | ||
yuni | e6ca1c5b50 | ||
yuni | dba6c4183a | ||
yuni | e8eb7a77a1 | ||
yuni | 61986d2f43 | ||
yuni | d0acc6988f | ||
yuni | 1d220c79cc | ||
yuni | d8722a4f98 | ||
yuni | 8e04cddda5 | ||
yuni | d2744d7f16 | ||
yuni | f1a7781fa2 | ||
yuni | 8c3eb72994 | ||
yuni | f9ac1c0275 | ||
yuni | cf71a23aec | ||
yuni | 6a1dadfd3a | ||
yuni | 00d042b56c | ||
yuni | 917d130cf8 | ||
yuni | 965c7ef652 | ||
yuni | 42a3577c57 | ||
yuni | ed1ef1bb1f | ||
yuni | 5c29681ee3 | ||
yuni | e3ff386011 | ||
yuni | 1d73cf8367 | ||
yuni | bf3c8d5b44 | ||
yuni | 0044f50e68 | ||
yuni | ed6187d996 | ||
yuni | 513e3d89ef | ||
yuni | 7d85a93449 | ||
yuni | 8c0af0e467 | ||
yuni | 70a602de5c | ||
yuni | 7d063209fa | ||
yuni | ea26711806 | ||
yuni | fca8251f27 | ||
yuni | 0c2c295f6b | ||
yuni | 8cd970a930 | ||
yuni | 321fccb9c4 | ||
yuni | 336527c4c0 | ||
yuni | a14e295007 | ||
yuni | 463745eabb | ||
yuni | f169ceac8f | ||
yuni | 5d89043ef2 | ||
yuni | 81b09d183a | ||
yuni | a6e6dac3d8 | ||
yuni | 919b801832 | ||
yuni | c9e271184c | ||
yuni | 1b0209f38b |
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -3,4 +3,4 @@ assets/tmp
|
||||||
assets/external
|
assets/external
|
||||||
*.blend1
|
*.blend1
|
||||||
extra
|
extra
|
||||||
outfly_*.zip
|
outfly_v*
|
||||||
|
|
118
Cargo.lock
generated
118
Cargo.lock
generated
|
@ -72,12 +72,6 @@ dependencies = [
|
||||||
"winit",
|
"winit",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "adler"
|
|
||||||
version = "1.0.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ahash"
|
name = "ahash"
|
||||||
version = "0.8.11"
|
version = "0.8.11"
|
||||||
|
@ -1488,15 +1482,6 @@ dependencies = [
|
||||||
"windows 0.54.0",
|
"windows 0.54.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "crc32fast"
|
|
||||||
version = "1.4.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "b3855a8a784b474f333699ef2bbca9db2c4a1f6d9088a90a2d25b1eb53111eaa"
|
|
||||||
dependencies = [
|
|
||||||
"cfg-if",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "crossbeam-channel"
|
name = "crossbeam-channel"
|
||||||
version = "0.5.12"
|
version = "0.5.12"
|
||||||
|
@ -1600,6 +1585,19 @@ version = "1.10.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a"
|
checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "embed-resource"
|
||||||
|
version = "1.8.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e62abb876c07e4754fae5c14cafa77937841f01740637e17d78dc04352f32a5e"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"rustc_version",
|
||||||
|
"toml",
|
||||||
|
"vswhom",
|
||||||
|
"winreg",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "encase"
|
name = "encase"
|
||||||
version = "0.7.0"
|
version = "0.7.0"
|
||||||
|
@ -1720,15 +1718,6 @@ version = "2.0.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "658bd65b1cf4c852a3cc96f18a8ce7b5640f6b703f905c7d74532294c2a63984"
|
checksum = "658bd65b1cf4c852a3cc96f18a8ce7b5640f6b703f905c7d74532294c2a63984"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "fdeflate"
|
|
||||||
version = "0.3.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "4f9bfee30e4dedf0ab8b422f03af778d9612b63f502710fc500a334ebe2de645"
|
|
||||||
dependencies = [
|
|
||||||
"simd-adler32",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "file-id"
|
name = "file-id"
|
||||||
version = "0.2.1"
|
version = "0.2.1"
|
||||||
|
@ -1756,16 +1745,6 @@ version = "0.4.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80"
|
checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "flate2"
|
|
||||||
version = "1.0.28"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "46303f565772937ffe1d394a4fac6f411c6013172fadde9dcdb1e147a086940e"
|
|
||||||
dependencies = [
|
|
||||||
"crc32fast",
|
|
||||||
"miniz_oxide",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "foreign-types"
|
name = "foreign-types"
|
||||||
version = "0.5.0"
|
version = "0.5.0"
|
||||||
|
@ -2086,7 +2065,6 @@ dependencies = [
|
||||||
"color_quant",
|
"color_quant",
|
||||||
"jpeg-decoder",
|
"jpeg-decoder",
|
||||||
"num-traits",
|
"num-traits",
|
||||||
"png",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -2393,16 +2371,6 @@ version = "0.2.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
|
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "miniz_oxide"
|
|
||||||
version = "0.7.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7"
|
|
||||||
dependencies = [
|
|
||||||
"adler",
|
|
||||||
"simd-adler32",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "mio"
|
name = "mio"
|
||||||
version = "0.8.11"
|
version = "0.8.11"
|
||||||
|
@ -2769,11 +2737,12 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "outfly"
|
name = "outfly"
|
||||||
version = "0.7.1"
|
version = "0.7.3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bevy",
|
"bevy",
|
||||||
"bevy_embedded_assets",
|
"bevy_embedded_assets",
|
||||||
"bevy_xpbd_3d",
|
"bevy_xpbd_3d",
|
||||||
|
"embed-resource",
|
||||||
"fastrand",
|
"fastrand",
|
||||||
"regex",
|
"regex",
|
||||||
"serde",
|
"serde",
|
||||||
|
@ -2913,19 +2882,6 @@ version = "0.3.30"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec"
|
checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "png"
|
|
||||||
version = "0.17.13"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "06e4b0d3d1312775e782c86c91a111aa1f910cbb65e1337f9975b5f9a554b5e1"
|
|
||||||
dependencies = [
|
|
||||||
"bitflags 1.3.2",
|
|
||||||
"crc32fast",
|
|
||||||
"fdeflate",
|
|
||||||
"flate2",
|
|
||||||
"miniz_oxide",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "polling"
|
name = "polling"
|
||||||
version = "3.5.0"
|
version = "3.5.0"
|
||||||
|
@ -3309,12 +3265,6 @@ dependencies = [
|
||||||
"wide",
|
"wide",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "simd-adler32"
|
|
||||||
version = "0.3.7"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "slab"
|
name = "slab"
|
||||||
version = "0.4.9"
|
version = "0.4.9"
|
||||||
|
@ -3542,6 +3492,15 @@ version = "0.1.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
|
checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "toml"
|
||||||
|
version = "0.5.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234"
|
||||||
|
dependencies = [
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "toml_datetime"
|
name = "toml_datetime"
|
||||||
version = "0.6.5"
|
version = "0.6.5"
|
||||||
|
@ -3716,6 +3675,26 @@ version = "0.9.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "vswhom"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "be979b7f07507105799e854203b470ff7c78a1639e330a58f183b5fea574608b"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"vswhom-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "vswhom-sys"
|
||||||
|
version = "0.1.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d3b17ae1f6c8a2b28506cd96d412eebf83b4a0ff2cbefeeb952f2f9dfa44ba18"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "walkdir"
|
name = "walkdir"
|
||||||
version = "2.5.0"
|
version = "2.5.0"
|
||||||
|
@ -4416,6 +4395,15 @@ dependencies = [
|
||||||
"memchr",
|
"memchr",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winreg"
|
||||||
|
version = "0.10.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d"
|
||||||
|
dependencies = [
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "x11-dl"
|
name = "x11-dl"
|
||||||
version = "2.21.0"
|
version = "2.21.0"
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "outfly"
|
name = "outfly"
|
||||||
version = "0.7.1"
|
version = "0.7.3"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
homepage = "https://codeberg.org/hut/outfly"
|
homepage = "https://codeberg.org/hut/outfly"
|
||||||
repository = "https://codeberg.org/hut/outfly"
|
repository = "https://codeberg.org/hut/outfly"
|
||||||
|
@ -8,16 +8,20 @@ categories = ["game", "aerospace", "simulation"]
|
||||||
keywords = ["game", "space", "3d"]
|
keywords = ["game", "space", "3d"]
|
||||||
license = "GPL-3.0-only"
|
license = "GPL-3.0-only"
|
||||||
rust-version = "1.76.0"
|
rust-version = "1.76.0"
|
||||||
|
build = "build/build.rs"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
regex = "1"
|
regex = "1"
|
||||||
bevy = { version = "0.13.2", 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", "tonemapping_luts", "vorbis"]}
|
bevy = { version = "0.13.2", 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", "tonemapping_luts", "vorbis"]}
|
||||||
bevy_xpbd_3d = { version = "0.4.2", default-features = false, features = ["3d", "f64", "parry-f64", "parallel", "async-collider"] }
|
bevy_xpbd_3d = { version = "0.4.2", default-features = false, features = ["3d", "f64", "parry-f64", "parallel", "async-collider"] }
|
||||||
bevy_embedded_assets = "0.10.2"
|
bevy_embedded_assets = "0.10.2"
|
||||||
fastrand = "2.0"
|
fastrand = "2.0"
|
||||||
serde = "1.0"
|
serde = "1.0"
|
||||||
serde_yaml = "0.9"
|
serde_yaml = "0.9"
|
||||||
|
|
||||||
|
[build-dependencies]
|
||||||
|
embed-resource = "1.6.3" # embedding of .exe metadata
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["x11"]
|
default = ["x11"]
|
||||||
dev = ["bevy/dynamic_linking", "bevy/file_watcher"]
|
dev = ["bevy/dynamic_linking", "bevy/file_watcher"]
|
||||||
|
|
10
README.md
10
README.md
|
@ -21,6 +21,7 @@ Links:
|
||||||
|
|
||||||
- [Source code](https://codeberg.org/hut/outfly)
|
- [Source code](https://codeberg.org/hut/outfly)
|
||||||
- [itch.io page](https://wholesomevacuum.itch.io/outfly)
|
- [itch.io page](https://wholesomevacuum.itch.io/outfly)
|
||||||
|
- [Game updates on Mastodon](https://mastodon.gamedev.place/@outfly)
|
||||||
- [Chatroom](https://matrix.to/#/#outfly:pub.solar)
|
- [Chatroom](https://matrix.to/#/#outfly:pub.solar)
|
||||||
|
|
||||||
![screenshot](doc/images/screenshot2.jpg)
|
![screenshot](doc/images/screenshot2.jpg)
|
||||||
|
@ -42,9 +43,10 @@ Links:
|
||||||
- Tab: Toggle HUD/AR
|
- Tab: Toggle HUD/AR
|
||||||
- F11: Toggle fullscreen
|
- F11: Toggle fullscreen
|
||||||
- F: Toggle 3rd person view
|
- F: Toggle 3rd person view
|
||||||
|
- M: Toggle map
|
||||||
- Y: Toggle rotation stabilizer
|
- Y: Toggle rotation stabilizer
|
||||||
- T: Toggle music
|
- F4: Toggle music
|
||||||
- M: Toggle sound effects
|
- F3: Toggle sound effects
|
||||||
- Cheats
|
- Cheats
|
||||||
- G: Toggle god mode / cheats
|
- G: Toggle god mode / cheats
|
||||||
- V/B: Impossible acceleration forward/backward
|
- V/B: Impossible acceleration forward/backward
|
||||||
|
@ -155,6 +157,10 @@ python -m http.server -d wasm
|
||||||
|
|
||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
- v0.7.3: Implement map. You can now zoom out ALL THE WAY
|
||||||
|
- v0.7.2:
|
||||||
|
- Implement colliders based on object shape
|
||||||
|
- Add "The Whale" vehicle around bus station Metis Prime
|
||||||
- v0.7.1: Much nicer HUD
|
- v0.7.1: Much nicer HUD
|
||||||
- v0.7.0:
|
- v0.7.0:
|
||||||
- Overhaul conversation system, now defined in YAML files
|
- Overhaul conversation system, now defined in YAML files
|
||||||
|
|
BIN
assets/models/orbitring.glb
Normal file
BIN
assets/models/orbitring.glb
Normal file
Binary file not shown.
7
build/build.rs
Normal file
7
build/build.rs
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
fn main() {
|
||||||
|
let target = std::env::var("TARGET").unwrap();
|
||||||
|
if target.contains("windows") {
|
||||||
|
println!("cargo:warning=Embedding Windows Icon");
|
||||||
|
embed_resource::compile("build/windows/icon.rc");
|
||||||
|
}
|
||||||
|
}
|
|
@ -31,55 +31,85 @@ PATH = "extra/hygdata_v41.csv"
|
||||||
# Meissa (orion's head, 8th brightest star in orion) = 3.33
|
# Meissa (orion's head, 8th brightest star in orion) = 3.33
|
||||||
MAX_APPARENT_MAGNITUDE = 7.0
|
MAX_APPARENT_MAGNITUDE = 7.0
|
||||||
|
|
||||||
|
SOL_ABSMAG = 4.83
|
||||||
|
SOL_RADIUS = 696.3e6
|
||||||
|
SOL_LUMINOSITY = 3.828e26
|
||||||
|
STEFAN_BOLTZMANN_CONSTANT = 5.670374419e-8
|
||||||
|
|
||||||
print("// This file was autogenerated by \"genrate_starchart.py\" using data from the")
|
print("// This file was autogenerated by \"genrate_starchart.py\" using data from the")
|
||||||
print("// HYG database: https://github.com/astronexus/HYG-Database/tree/main/hyg")
|
print("// HYG database: https://github.com/astronexus/HYG-Database/tree/main/hyg")
|
||||||
print("// License: CC BY-SA 4.0: https://creativecommons.org/licenses/by-sa/4.0/")
|
print("// License: CC BY-SA 4.0: https://creativecommons.org/licenses/by-sa/4.0/")
|
||||||
print("// Each star's values: (x, y, z, magnitude, color index, distance, name)")
|
print("// Each star's values: (x, y, z, magnitude, absolute magnitude, color index, name)")
|
||||||
print("[")
|
print("[")
|
||||||
|
|
||||||
|
|
||||||
def render(ra, dec, mag, ci, dist, name):
|
def render(i, x, y, z, ra, dec, mag, absmag, ci, dist, name):
|
||||||
# Takes ra/deg in degrees
|
# Takes ra/deg in degrees
|
||||||
ra = float(ra)
|
ra = float(ra)
|
||||||
dec = float(dec)
|
dec = float(dec)
|
||||||
mag = float(mag)
|
mag = float(mag)
|
||||||
|
x, y, z = float(x), float(y), float(z)
|
||||||
name = re.sub(r'\s+', ' ', name)
|
name = re.sub(r'\s+', ' ', name)
|
||||||
|
if name == 'Sol':
|
||||||
|
return
|
||||||
|
|
||||||
distance = 1.0
|
#radius = star_radius(float(ci), float(absmag))
|
||||||
ra_radians = math.radians(ra * 15) # ra is in [0, 24], multiplying by 15 gives degrees in [0, 360]
|
|
||||||
dec_radians = math.radians(dec)
|
|
||||||
#print(f"ra_radians={ra_radians}, dec_radians={dec_radians}, dec={dec}, ra={ra}", file=sys.stderr)
|
|
||||||
x = distance * math.cos(dec_radians) * math.cos(-ra_radians)
|
|
||||||
y = distance * math.cos(dec_radians) * math.sin(-ra_radians)
|
|
||||||
z = distance * math.sin(dec_radians)
|
|
||||||
|
|
||||||
# Correct for differences in coordinate system axes
|
# distance = 1.0
|
||||||
x, y, z = x, z, y
|
# ra_radians = math.radians(ra * 15) # ra is in [0, 24], multiplying by 15 gives degrees in [0, 360]
|
||||||
|
# dec_radians = math.radians(dec)
|
||||||
|
# #print(f"ra_radians={ra_radians}, dec_radians={dec_radians}, dec={dec}, ra={ra}", file=sys.stderr)
|
||||||
|
# x = distance * math.cos(dec_radians) * math.cos(-ra_radians)
|
||||||
|
# y = distance * math.cos(dec_radians) * math.sin(-ra_radians)
|
||||||
|
# z = distance * math.sin(dec_radians)
|
||||||
|
#
|
||||||
|
# # Correct for differences in coordinate system axes
|
||||||
|
# x, y, z = x, z, y
|
||||||
|
|
||||||
#brightness = 2.512 ** (0 - mag)
|
#brightness = 2.512 ** (0 - mag)
|
||||||
|
|
||||||
print(f'({x:.04},{y:.04},{z:.04},{mag:.04},{ci},{dist},"{name}"),')
|
print(f'({x:.04},{y:.04},{z:.04},{mag:.04},{absmag:.04},{ci},"{name}"),')
|
||||||
|
|
||||||
|
|
||||||
def clean_name(string):
|
def clean_name(string):
|
||||||
return "".join([c for c in string if c.isalnum() or c in ' -_'])
|
return "".join([c for c in string if c.isalnum() or c in ' -_'])
|
||||||
|
|
||||||
|
|
||||||
|
def star_radius(color_index, absolute_magnitude):
|
||||||
|
# Convert color index to temperature (using Ballesteros' formula approximation for B-V)
|
||||||
|
temp = 4600 * ((1 / (0.92 * color_index + 1.7)) + (1 / (0.92 * color_index + 0.62)))
|
||||||
|
|
||||||
|
# Convert absolute magnitude to luminosity (in solar luminosities)
|
||||||
|
lum = 10 ** (0.4 * (SOL_ABSMAG - absolute_magnitude))
|
||||||
|
|
||||||
|
# Calculate the radius using Stefan-Boltzmann law (output should be in meters)
|
||||||
|
radius = math.sqrt(lum * SOL_LUMINOSITY / (4 * math.pi * STEFAN_BOLTZMANN_CONSTANT * temp ** 4)) # Luminosity in watts for the Sun ~ 3.828e26
|
||||||
|
|
||||||
|
# Convert radius from meters to solar radii (1 solar radius ≈ 6.96e8 meters)
|
||||||
|
radius_solar = radius / SOL_RADIUS
|
||||||
|
|
||||||
|
return radius_solar
|
||||||
|
|
||||||
|
|
||||||
total = 0
|
total = 0
|
||||||
count = 0
|
count = 0
|
||||||
count_extra = 0
|
count_extra = 0
|
||||||
entries = []
|
entries = []
|
||||||
with open(PATH, "r", encoding="utf-8") as f:
|
with open(PATH, "r", encoding="utf-8") as f:
|
||||||
for entry in csv.DictReader(f):
|
for index, entry in enumerate(csv.DictReader(f)):
|
||||||
entries.append(entry)
|
entries.append((index, entry))
|
||||||
|
|
||||||
entries.sort(key=lambda entry: float(entry['mag']))
|
entries.sort(key=lambda entry: float(entry[1]['mag']))
|
||||||
|
|
||||||
for entry in entries:
|
for index, entry in entries:
|
||||||
total += 1
|
total += 1
|
||||||
ra = entry['ra']
|
ra = entry['ra']
|
||||||
dec = entry['dec']
|
dec = entry['dec']
|
||||||
|
x = entry['x']
|
||||||
|
y = entry['y']
|
||||||
|
z = entry['z']
|
||||||
mag = entry['mag']
|
mag = entry['mag']
|
||||||
|
absmag = entry['absmag']
|
||||||
ci = entry['ci']
|
ci = entry['ci']
|
||||||
dist = entry['dist']
|
dist = entry['dist']
|
||||||
name = clean_name(entry['proper'])
|
name = clean_name(entry['proper'])
|
||||||
|
@ -92,7 +122,7 @@ for entry in entries:
|
||||||
continue
|
continue
|
||||||
if float(mag) > MAX_APPARENT_MAGNITUDE:
|
if float(mag) > MAX_APPARENT_MAGNITUDE:
|
||||||
continue
|
continue
|
||||||
render(ra, dec, mag, ci, dist, name)
|
render(index, x, y, z, ra, dec, mag, absmag, ci, dist, name)
|
||||||
count += 1
|
count += 1
|
||||||
#for entry in CUSTOM_ENTRIES:
|
#for entry in CUSTOM_ENTRIES:
|
||||||
# render(entry[0], entry[1], entry[2], entry[3], entry[4])
|
# render(entry[0], entry[1], entry[2], entry[3], entry[4])
|
7
build/linux/install.sh
Executable file
7
build/linux/install.sh
Executable file
|
@ -0,0 +1,7 @@
|
||||||
|
#!/bin/sh
|
||||||
|
# usage: run this script from the project root, like this: build/install.sh [rootdir]
|
||||||
|
|
||||||
|
rootdir="${1:-}"
|
||||||
|
install -Dm755 "target/release/outfly" "$rootdir/usr/bin/outfly"
|
||||||
|
install -Dm644 "build/linux/outfly.png" "$rootdir/usr/share/pixmaps/outfly.png"
|
||||||
|
install -Dm644 "build/linux/outfly.desktop" "$rootdir/usr/share/applications/outfly.desktop"
|
9
build/linux/outfly.desktop
Normal file
9
build/linux/outfly.desktop
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
[Desktop Entry]
|
||||||
|
Type=Application
|
||||||
|
Name=OutFly
|
||||||
|
GenericName=Space Game
|
||||||
|
Comment=A breathtaking 3D space game in the rings of Jupiter
|
||||||
|
Icon=outfly
|
||||||
|
Categories=Game;Simulation;
|
||||||
|
Exec=outfly
|
||||||
|
Terminal=false
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 10 KiB |
|
@ -21,10 +21,10 @@ SRCPATH="outfly_v$VERSION"
|
||||||
mkdir "$SRCPATH"
|
mkdir "$SRCPATH"
|
||||||
|
|
||||||
cp ../README.md "$SRCPATH"
|
cp ../README.md "$SRCPATH"
|
||||||
cp ../target/x86_64-pc-windows-gnu/release/outfly.exe "$SRCPATH"
|
cp ../target/x86_64-pc-windows-gnu/release/outfly.exe "$SRCPATH"/OutFly.exe
|
||||||
zip -v -r -9 ../"outfly_v${VERSION}_windows.zip" "$SRCPATH"
|
zip -v -r -9 ../"outfly_v${VERSION}_windows.zip" "$SRCPATH"
|
||||||
|
|
||||||
rm "$SRCPATH"/outfly.exe
|
rm "$SRCPATH"/OutFly.exe
|
||||||
cp ../target/x86_64-unknown-linux-gnu/release/outfly "$SRCPATH"
|
cp ../target/x86_64-unknown-linux-gnu/release/outfly "$SRCPATH"
|
||||||
zip -v -r -9 ../"outfly_v${VERSION}_linux.zip" "$SRCPATH"
|
zip -v -r -9 ../"outfly_v${VERSION}_linux.zip" "$SRCPATH"
|
||||||
|
|
1
build/windows/icon.rc
Normal file
1
build/windows/icon.rc
Normal file
|
@ -0,0 +1 @@
|
||||||
|
app_icon ICON "outfly.ico"
|
BIN
build/windows/outfly.ico
Normal file
BIN
build/windows/outfly.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 27 KiB |
21
src/actor.rs
21
src/actor.rs
|
@ -3,10 +3,11 @@ use bevy_xpbd_3d::prelude::*;
|
||||||
use bevy::scene::SceneInstance;
|
use bevy::scene::SceneInstance;
|
||||||
use bevy::math::DVec3;
|
use bevy::math::DVec3;
|
||||||
use crate::{actor, audio, camera, chat, commands, effects, hud, nature, var, world};
|
use crate::{actor, audio, camera, chat, commands, effects, hud, nature, var, world};
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
pub const ENGINE_SPEED_FACTOR: f32 = 30.0;
|
pub const ENGINE_SPEED_FACTOR: f32 = 30.0;
|
||||||
const MAX_TRANSMISSION_DISTANCE: f32 = 100.0;
|
const MAX_TRANSMISSION_DISTANCE: f32 = 100.0;
|
||||||
const MAX_INTERACT_DISTANCE: f32 = 40.0;
|
const MAX_INTERACT_DISTANCE: f32 = 50.0;
|
||||||
|
|
||||||
pub struct ActorPlugin;
|
pub struct ActorPlugin;
|
||||||
impl Plugin for ActorPlugin {
|
impl Plugin for ActorPlugin {
|
||||||
|
@ -27,9 +28,11 @@ impl Plugin for ActorPlugin {
|
||||||
));
|
));
|
||||||
app.add_systems(PostUpdate, (
|
app.add_systems(PostUpdate, (
|
||||||
handle_vehicle_enter_exit,
|
handle_vehicle_enter_exit,
|
||||||
|
update_id2pos,
|
||||||
));
|
));
|
||||||
app.add_event::<VehicleEnterExitEvent>();
|
app.add_event::<VehicleEnterExitEvent>();
|
||||||
app.add_event::<PlayerDiesEvent>();
|
app.add_event::<PlayerDiesEvent>();
|
||||||
|
app.insert_resource(Id2Pos(HashMap::new()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -110,10 +113,13 @@ impl Default for ExperiencesGForce { fn default() -> Self { Self {
|
||||||
#[derive(Component)] pub struct Player; // Attached to the suit of the player
|
#[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 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 PlayerCamera; // Attached to the actor to use as point of view
|
||||||
|
#[derive(Component)] pub struct JustNowEnteredVehicle;
|
||||||
#[derive(Component)] pub struct ActorEnteringVehicle;
|
#[derive(Component)] pub struct ActorEnteringVehicle;
|
||||||
#[derive(Component)] pub struct ActorVehicleBeingEntered;
|
#[derive(Component)] pub struct ActorVehicleBeingEntered;
|
||||||
#[derive(Component)] pub struct WantsMaxRotation(pub f64);
|
#[derive(Component)] pub struct WantsMaxRotation(pub f64);
|
||||||
#[derive(Component)] pub struct WantsMaxVelocity(pub f64);
|
#[derive(Component)] pub struct WantsMaxVelocity(pub f64);
|
||||||
|
#[derive(Component)] pub struct Identifier(pub String);
|
||||||
|
#[derive(Resource)] pub struct Id2Pos(pub HashMap<String, DVec3>);
|
||||||
|
|
||||||
#[derive(Component)]
|
#[derive(Component)]
|
||||||
pub struct LifeForm {
|
pub struct LifeForm {
|
||||||
|
@ -326,6 +332,7 @@ pub fn handle_vehicle_enter_exit(
|
||||||
ew_sfx.send(audio::PlaySfxEvent(audio::Sfx::EnterVehicle));
|
ew_sfx.send(audio::PlaySfxEvent(audio::Sfx::EnterVehicle));
|
||||||
commands.entity(driver).remove::<PlayerCamera>();
|
commands.entity(driver).remove::<PlayerCamera>();
|
||||||
commands.entity(driver).remove::<Collider>();
|
commands.entity(driver).remove::<Collider>();
|
||||||
|
commands.entity(driver).insert(JustNowEnteredVehicle);
|
||||||
commands.entity(vehicle).insert(PlayerCamera);
|
commands.entity(vehicle).insert(PlayerCamera);
|
||||||
commands.entity(vehicle).insert(PlayerDrivesThis);
|
commands.entity(vehicle).insert(PlayerDrivesThis);
|
||||||
}
|
}
|
||||||
|
@ -421,6 +428,7 @@ fn handle_player_death(
|
||||||
q_noscenes: Query<Entity, (With<world::DespawnOnPlayerDeath>, Without<SceneInstance>)>,
|
q_noscenes: Query<Entity, (With<world::DespawnOnPlayerDeath>, Without<SceneInstance>)>,
|
||||||
ew_spawn: EventWriter<commands::SpawnEvent>,
|
ew_spawn: EventWriter<commands::SpawnEvent>,
|
||||||
mut scene_spawner: ResMut<SceneSpawner>,
|
mut scene_spawner: ResMut<SceneSpawner>,
|
||||||
|
mut active_asteroids: ResMut<world::ActiveAsteroids>,
|
||||||
mut ew_sfx: EventWriter<audio::PlaySfxEvent>,
|
mut ew_sfx: EventWriter<audio::PlaySfxEvent>,
|
||||||
mut ew_effect: EventWriter<effects::SpawnEffectEvent>,
|
mut ew_effect: EventWriter<effects::SpawnEffectEvent>,
|
||||||
mut log: ResMut<hud::Log>,
|
mut log: ResMut<hud::Log>,
|
||||||
|
@ -431,6 +439,7 @@ fn handle_player_death(
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
settings.reset_player_settings();
|
settings.reset_player_settings();
|
||||||
|
active_asteroids.0.clear();
|
||||||
for entity in &q_noscenes {
|
for entity in &q_noscenes {
|
||||||
cmd.entity(entity).despawn();
|
cmd.entity(entity).despawn();
|
||||||
}
|
}
|
||||||
|
@ -519,3 +528,13 @@ fn handle_gforce(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn update_id2pos(
|
||||||
|
mut id2pos: ResMut<Id2Pos>,
|
||||||
|
q_id: Query<(&Position, &Identifier)>,
|
||||||
|
) {
|
||||||
|
id2pos.0.clear();
|
||||||
|
for (pos, id) in &q_id {
|
||||||
|
id2pos.0.insert(id.0.clone(), pos.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -137,12 +137,12 @@ pub fn toggle_bgm(
|
||||||
mut evwriter_sfx: EventWriter<PlaySfxEvent>,
|
mut evwriter_sfx: EventWriter<PlaySfxEvent>,
|
||||||
mut settings: ResMut<var::Settings>,
|
mut settings: ResMut<var::Settings>,
|
||||||
) {
|
) {
|
||||||
if keyboard_input.just_pressed(KeyCode::KeyT) {
|
if keyboard_input.just_pressed(settings.key_toggle_music) {
|
||||||
settings.mute_music ^= true;
|
settings.mute_music ^= true;
|
||||||
evwriter_sfx.send(PlaySfxEvent(Sfx::Click));
|
evwriter_sfx.send(PlaySfxEvent(Sfx::Click));
|
||||||
evwriter_toggle.send(ToggleMusicEvent());
|
evwriter_toggle.send(ToggleMusicEvent());
|
||||||
}
|
}
|
||||||
if keyboard_input.just_pressed(KeyCode::KeyM) {
|
if keyboard_input.just_pressed(settings.key_toggle_sfx) {
|
||||||
settings.mute_sfx ^= true;
|
settings.mute_sfx ^= true;
|
||||||
evwriter_sfx.send(PlaySfxEvent(Sfx::Click));
|
evwriter_sfx.send(PlaySfxEvent(Sfx::Click));
|
||||||
evwriter_toggle.send(ToggleMusicEvent());
|
evwriter_toggle.send(ToggleMusicEvent());
|
||||||
|
|
196
src/camera.rs
196
src/camera.rs
|
@ -1,5 +1,5 @@
|
||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
use bevy::input::mouse::MouseMotion;
|
use bevy::input::mouse::{MouseMotion, MouseWheel};
|
||||||
use bevy::window::PrimaryWindow;
|
use bevy::window::PrimaryWindow;
|
||||||
use bevy::core_pipeline::bloom::{BloomCompositeMode, BloomSettings};
|
use bevy::core_pipeline::bloom::{BloomCompositeMode, BloomSettings};
|
||||||
use bevy::core_pipeline::tonemapping::Tonemapping;
|
use bevy::core_pipeline::tonemapping::Tonemapping;
|
||||||
|
@ -8,6 +8,7 @@ use bevy::transform::TransformSystem;
|
||||||
use bevy::math::{DVec3, DQuat};
|
use bevy::math::{DVec3, DQuat};
|
||||||
use bevy_xpbd_3d::prelude::*;
|
use bevy_xpbd_3d::prelude::*;
|
||||||
use std::f32::consts::PI;
|
use std::f32::consts::PI;
|
||||||
|
use std::f64::consts::PI as PI64;
|
||||||
use crate::{actor, audio, hud, var};
|
use crate::{actor, audio, hud, var};
|
||||||
|
|
||||||
pub struct CameraPlugin;
|
pub struct CameraPlugin;
|
||||||
|
@ -16,15 +17,50 @@ impl Plugin for CameraPlugin {
|
||||||
fn build(&self, app: &mut App) {
|
fn build(&self, app: &mut App) {
|
||||||
app.add_systems(Startup, setup_camera);
|
app.add_systems(Startup, setup_camera);
|
||||||
app.add_systems(Update, handle_input);
|
app.add_systems(Update, handle_input);
|
||||||
|
app.add_systems(Update, update_map_only_object_visibility);
|
||||||
app.add_systems(Update, manage_player_actor.after(handle_input));
|
app.add_systems(Update, manage_player_actor.after(handle_input));
|
||||||
app.add_systems(PostUpdate, sync_camera_to_player
|
app.add_systems(PostUpdate, sync_camera_to_player
|
||||||
.after(PhysicsSet::Sync)
|
.after(PhysicsSet::Sync)
|
||||||
.after(apply_input_to_player)
|
.after(apply_input_to_player)
|
||||||
.before(TransformSystem::TransformPropagate));
|
.before(TransformSystem::TransformPropagate));
|
||||||
|
app.add_systems(Update, update_map_camera);
|
||||||
app.add_systems(Update, update_fov);
|
app.add_systems(Update, update_fov);
|
||||||
app.add_systems(PostUpdate, apply_input_to_player
|
app.add_systems(PostUpdate, apply_input_to_player
|
||||||
.after(PhysicsSet::Sync)
|
.after(PhysicsSet::Sync)
|
||||||
.before(TransformSystem::TransformPropagate));
|
.before(TransformSystem::TransformPropagate));
|
||||||
|
app.insert_resource(MapCam::default());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Component)]
|
||||||
|
pub struct ShowOnlyInMap {
|
||||||
|
pub min_distance: f64,
|
||||||
|
pub distance_to_id: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Resource)]
|
||||||
|
pub struct MapCam {
|
||||||
|
pub initialized: bool,
|
||||||
|
pub zoom_level: f64,
|
||||||
|
pub target_zoom_level: f64,
|
||||||
|
pub pitch: f64,
|
||||||
|
pub yaw: f64,
|
||||||
|
pub offset_x: f64,
|
||||||
|
pub offset_z: f64,
|
||||||
|
pub center: DVec3,
|
||||||
|
}
|
||||||
|
impl Default for MapCam {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
initialized: false,
|
||||||
|
zoom_level: 2.0,
|
||||||
|
target_zoom_level: 10.0,
|
||||||
|
pitch: PI64 * 0.3,
|
||||||
|
yaw: 0.0,
|
||||||
|
offset_x: 0.0,
|
||||||
|
offset_z: 0.0,
|
||||||
|
center: DVec3::new(0.0, 0.0, 0.0),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -72,7 +108,7 @@ pub fn sync_camera_to_player(
|
||||||
mut q_camera: Query<&mut Transform, (With<Camera>, Without<actor::PlayerCamera>)>,
|
mut q_camera: Query<&mut Transform, (With<Camera>, Without<actor::PlayerCamera>)>,
|
||||||
q_playercam: Query<(&actor::Actor, &Transform), (With<actor::PlayerCamera>, Without<Camera>)>,
|
q_playercam: Query<(&actor::Actor, &Transform), (With<actor::PlayerCamera>, Without<Camera>)>,
|
||||||
) {
|
) {
|
||||||
if q_camera.is_empty() || q_playercam.is_empty() {
|
if settings.map_active || q_camera.is_empty() || q_playercam.is_empty() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let mut camera_transform = q_camera.get_single_mut().unwrap();
|
let mut camera_transform = q_camera.get_single_mut().unwrap();
|
||||||
|
@ -90,6 +126,105 @@ pub fn sync_camera_to_player(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn update_map_camera(
|
||||||
|
settings: Res<var::Settings>,
|
||||||
|
mut mapcam: ResMut<MapCam>,
|
||||||
|
mut q_camera: Query<&mut Transform, (With<Camera>, Without<actor::PlayerCamera>)>,
|
||||||
|
q_playercam: Query<&Transform, (With<actor::PlayerCamera>, Without<Camera>)>,
|
||||||
|
q_target: Query<&Transform, (With<hud::IsTargeted>, Without<Camera>, Without<actor::PlayerCamera>)>,
|
||||||
|
q_target_changed: Query<(), Changed<hud::IsTargeted>>,
|
||||||
|
mut mouse_events: EventReader<MouseMotion>,
|
||||||
|
mut er_mousewheel: EventReader<MouseWheel>,
|
||||||
|
keyboard_input: Res<ButtonInput<KeyCode>>,
|
||||||
|
) {
|
||||||
|
if !settings.map_active || q_camera.is_empty() || q_playercam.is_empty() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let mut camera_transform = q_camera.get_single_mut().unwrap();
|
||||||
|
let player_transform = q_playercam.get_single().unwrap();
|
||||||
|
let target = if let Ok(target) = q_target.get_single() {
|
||||||
|
target
|
||||||
|
} else {
|
||||||
|
player_transform
|
||||||
|
};
|
||||||
|
|
||||||
|
// Get mouse movement
|
||||||
|
let mut mouse_delta = Vec2::ZERO;
|
||||||
|
for mouse_event in mouse_events.read() {
|
||||||
|
mouse_delta += mouse_event.delta;
|
||||||
|
}
|
||||||
|
// NOTE: we need to subtract a bit from PI/2, otherwise the "up"
|
||||||
|
// direction parameter for the Transform.look_at function is ambiguous
|
||||||
|
// at the extreme values and the orientation will flicker back/forth.
|
||||||
|
let epsilon = 0.001;
|
||||||
|
let min_zoom: f64 = target.scale.x as f64 * 2.0;
|
||||||
|
let max_zoom: f64 = 17e18; // at this point, camera starts glitching
|
||||||
|
mapcam.pitch = (mapcam.pitch + mouse_delta.y as f64 / 180.0 * settings.mouse_sensitivity as f64).clamp(-PI64 / 2.0 + epsilon, PI64 / 2.0 - epsilon);
|
||||||
|
mapcam.yaw += mouse_delta.x as f64 / 180.0 * settings.mouse_sensitivity as f64;
|
||||||
|
|
||||||
|
// Reset movement offset if target changes
|
||||||
|
if !q_target_changed.is_empty() {
|
||||||
|
mapcam.offset_x = 0.0;
|
||||||
|
mapcam.offset_z = 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get keyboard movement
|
||||||
|
let mut offset_x: f64 = 0.0;
|
||||||
|
let mut offset_z: f64 = 0.0;
|
||||||
|
if keyboard_input.pressed(settings.key_forward) {
|
||||||
|
offset_x -= 1.0;
|
||||||
|
}
|
||||||
|
if keyboard_input.pressed(settings.key_back) {
|
||||||
|
offset_x += 1.0;
|
||||||
|
}
|
||||||
|
if keyboard_input.pressed(settings.key_right) {
|
||||||
|
offset_z -= 1.0;
|
||||||
|
}
|
||||||
|
if keyboard_input.pressed(settings.key_left) {
|
||||||
|
offset_z += 1.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update zoom level
|
||||||
|
if !mapcam.initialized {
|
||||||
|
let factor: f64 = if target == player_transform { 7.0 } else { 1.0 };
|
||||||
|
mapcam.target_zoom_level *= target.scale.x as f64 * factor;
|
||||||
|
mapcam.zoom_level *= target.scale.x as f64 * factor;
|
||||||
|
mapcam.initialized = true;
|
||||||
|
}
|
||||||
|
let mut change_zoom: f64 = 0.0;
|
||||||
|
if keyboard_input.pressed(settings.key_map_zoom_out) {
|
||||||
|
change_zoom += 0.5;
|
||||||
|
}
|
||||||
|
if keyboard_input.pressed(settings.key_map_zoom_in) {
|
||||||
|
change_zoom -= 0.5;
|
||||||
|
}
|
||||||
|
for wheel_event in er_mousewheel.read() {
|
||||||
|
change_zoom -= wheel_event.y as f64 * 3.0;
|
||||||
|
}
|
||||||
|
mapcam.target_zoom_level = (mapcam.target_zoom_level * 1.1f64.powf(change_zoom)).clamp(min_zoom, max_zoom);
|
||||||
|
let zoom_speed = 0.05; // should be between 0.0001 (slow) and 1.0 (instant)
|
||||||
|
mapcam.zoom_level = (zoom_speed * mapcam.target_zoom_level + (1.0 - zoom_speed) * mapcam.zoom_level).clamp(min_zoom, max_zoom);
|
||||||
|
|
||||||
|
// Update point of view
|
||||||
|
let pov_rotation = DQuat::from_euler(EulerRot::XYZ, 0.0, mapcam.yaw as f64, mapcam.pitch as f64);
|
||||||
|
let offset = DVec3::new(mapcam.offset_x, 0.0, mapcam.offset_z);
|
||||||
|
let point_of_view = offset + pov_rotation * (mapcam.zoom_level as f64 * DVec3::new(1.0, 0.0, 0.0));
|
||||||
|
|
||||||
|
// Update movement offset
|
||||||
|
let mut direction = pov_rotation * DVec3::new(offset_x, 0.0, offset_z);
|
||||||
|
let speed = direction.length();
|
||||||
|
direction.y = 0.0;
|
||||||
|
let direction = speed * direction.normalize_or_zero();
|
||||||
|
|
||||||
|
mapcam.offset_x += 0.01 * (direction.x * mapcam.zoom_level);
|
||||||
|
mapcam.offset_z += 0.01 * (direction.z * mapcam.zoom_level);
|
||||||
|
|
||||||
|
// Apply updates to camera
|
||||||
|
mapcam.center = target.translation.as_dvec3() + offset;
|
||||||
|
camera_transform.translation = target.translation + point_of_view.as_vec3();
|
||||||
|
camera_transform.look_at(mapcam.center.as_vec3(), Vec3::Y);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn update_fov(
|
pub fn update_fov(
|
||||||
q_player: Query<&actor::ExperiencesGForce, With<actor::Player>>,
|
q_player: Query<&actor::ExperiencesGForce, With<actor::Player>>,
|
||||||
mouse_input: Res<ButtonInput<MouseButton>>,
|
mouse_input: Res<ButtonInput<MouseButton>>,
|
||||||
|
@ -117,11 +252,16 @@ pub fn update_fov(
|
||||||
pub fn handle_input(
|
pub fn handle_input(
|
||||||
keyboard_input: Res<ButtonInput<KeyCode>>,
|
keyboard_input: Res<ButtonInput<KeyCode>>,
|
||||||
mut settings: ResMut<var::Settings>,
|
mut settings: ResMut<var::Settings>,
|
||||||
|
mut mapcam: ResMut<MapCam>,
|
||||||
mut ew_sfx: EventWriter<audio::PlaySfxEvent>,
|
mut ew_sfx: EventWriter<audio::PlaySfxEvent>,
|
||||||
) {
|
) {
|
||||||
if keyboard_input.just_pressed(settings.key_camera) {
|
if keyboard_input.just_pressed(settings.key_camera) {
|
||||||
settings.third_person ^= true;
|
settings.third_person ^= true;
|
||||||
}
|
}
|
||||||
|
if keyboard_input.just_pressed(settings.key_map) {
|
||||||
|
settings.map_active ^= true;
|
||||||
|
*mapcam = MapCam::default();
|
||||||
|
}
|
||||||
if keyboard_input.just_pressed(settings.key_rotation_stabilizer) {
|
if keyboard_input.just_pressed(settings.key_rotation_stabilizer) {
|
||||||
ew_sfx.send(audio::PlaySfxEvent(audio::Sfx::Click));
|
ew_sfx.send(audio::PlaySfxEvent(audio::Sfx::Click));
|
||||||
settings.rotation_stabilizer_active ^= true;
|
settings.rotation_stabilizer_active ^= true;
|
||||||
|
@ -129,20 +269,21 @@ pub fn handle_input(
|
||||||
}
|
}
|
||||||
|
|
||||||
fn manage_player_actor(
|
fn manage_player_actor(
|
||||||
|
mut commands: Commands,
|
||||||
settings: Res<var::Settings>,
|
settings: Res<var::Settings>,
|
||||||
mut q_playercam: Query<&mut Visibility, With<actor::PlayerCamera>>,
|
mut q_playercam: Query<&mut Visibility, With<actor::PlayerCamera>>,
|
||||||
mut q_hiddenplayer: Query<(&mut Visibility, &mut Position, &mut Rotation, &mut LinearVelocity, &mut AngularVelocity), (With<actor::Player>, Without<actor::PlayerCamera>)>,
|
mut q_hiddenplayer: Query<(Entity, &mut Visibility, &mut Position, &mut Rotation, &mut LinearVelocity, &mut AngularVelocity, Option<&mut actor::ExperiencesGForce>, Option<&actor::JustNowEnteredVehicle>), (With<actor::Player>, Without<actor::PlayerCamera>)>,
|
||||||
q_ride: Query<(&Transform, &Position, &Rotation, &LinearVelocity, &AngularVelocity), (With<actor::PlayerDrivesThis>, Without<actor::Player>)>,
|
q_ride: Query<(&Transform, &Position, &Rotation, &LinearVelocity, &AngularVelocity), (With<actor::PlayerDrivesThis>, Without<actor::Player>)>,
|
||||||
) {
|
) {
|
||||||
for mut vis in &mut q_playercam {
|
for mut vis in &mut q_playercam {
|
||||||
if settings.third_person {
|
if settings.third_person || settings.map_active {
|
||||||
*vis = Visibility::Inherited;
|
*vis = Visibility::Inherited;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
*vis = Visibility::Hidden;
|
*vis = Visibility::Hidden;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (mut vis, mut pos, mut rot, mut v, mut angv) in &mut q_hiddenplayer {
|
for (entity, mut vis, mut pos, mut rot, mut v, mut angv, mut gforce, entering) in &mut q_hiddenplayer {
|
||||||
// If we are riding a vehicle, place the player at the position where
|
// If we are riding a vehicle, place the player at the position where
|
||||||
// it would be after exiting the vehicle.
|
// it would be after exiting the vehicle.
|
||||||
// I would rather place it in the center of the vehicle, but at the time
|
// I would rather place it in the center of the vehicle, but at the time
|
||||||
|
@ -154,6 +295,13 @@ fn manage_player_actor(
|
||||||
rot.0 = ride_rot.0 * DQuat::from_array([-1.0, 0.0, 0.0, 0.0]);
|
rot.0 = ride_rot.0 * DQuat::from_array([-1.0, 0.0, 0.0, 0.0]);
|
||||||
*v = ride_v.clone();
|
*v = ride_v.clone();
|
||||||
*angv = ride_angv.clone();
|
*angv = ride_angv.clone();
|
||||||
|
|
||||||
|
// I really don't want people to die from the g-forces of entering
|
||||||
|
// vehicles at high relative speed, even though they probably should.
|
||||||
|
if let (Some(gforce), Some(_)) = (&mut gforce, entering) {
|
||||||
|
gforce.last_linear_velocity = v.0;
|
||||||
|
commands.entity(entity).remove::<actor::JustNowEnteredVehicle>();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -179,6 +327,9 @@ pub fn apply_input_to_player(
|
||||||
Option<&actor::PlayerDrivesThis>,
|
Option<&actor::PlayerDrivesThis>,
|
||||||
), (With<actor::PlayerCamera>, Without<Camera>)>,
|
), (With<actor::PlayerCamera>, Without<Camera>)>,
|
||||||
) {
|
) {
|
||||||
|
if settings.map_active {
|
||||||
|
return;
|
||||||
|
}
|
||||||
let dt = time.delta_seconds();
|
let dt = time.delta_seconds();
|
||||||
let mut play_thruster_sound = false;
|
let mut play_thruster_sound = false;
|
||||||
let mut axis_input: DVec3 = DVec3::ZERO;
|
let mut axis_input: DVec3 = DVec3::ZERO;
|
||||||
|
@ -389,6 +540,39 @@ pub fn apply_input_to_player(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn update_map_only_object_visibility(
|
||||||
|
settings: Res<var::Settings>,
|
||||||
|
q_camera: Query<&Transform, With<Camera>>,
|
||||||
|
q_player: Query<&Position, With<actor::PlayerCamera>>,
|
||||||
|
mut q_onlyinmap: Query<(&mut Visibility, &ShowOnlyInMap), Without<Camera>>,
|
||||||
|
id2pos: Res<actor::Id2Pos>,
|
||||||
|
) {
|
||||||
|
if q_camera.is_empty() || q_player.is_empty() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let cam: &Transform = q_camera.get_single().unwrap();
|
||||||
|
let player_pos: &Position = q_player.get_single().unwrap();
|
||||||
|
let cam_pos: Vec3 = cam.translation + player_pos.as_vec3();
|
||||||
|
for (mut vis, onlyinmap) in &mut q_onlyinmap {
|
||||||
|
if settings.map_active && settings.hud_active {
|
||||||
|
if let Some(pos) = id2pos.0.get(&onlyinmap.distance_to_id) {
|
||||||
|
let dist = cam_pos.distance(pos.as_vec3());
|
||||||
|
if dist >= onlyinmap.min_distance as f32 {
|
||||||
|
*vis = Visibility::Inherited;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
*vis = Visibility::Hidden;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
error!("Failed get position of actor ID '{}'", &onlyinmap.distance_to_id);
|
||||||
|
*vis = Visibility::Hidden;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
*vis = Visibility::Hidden;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Find the closest world object that the player is looking at
|
// Find the closest world object that the player is looking at
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn find_closest_target<TargetSpecifier>(
|
pub fn find_closest_target<TargetSpecifier>(
|
||||||
|
@ -406,10 +590,10 @@ pub fn find_closest_target<TargetSpecifier>(
|
||||||
// not on the player mesh but on the camera, which doesn't have a position.
|
// not on the player mesh but on the camera, which doesn't have a position.
|
||||||
let (angular_diameter, angle, distance) = calc_angular_diameter_known_target_vector(
|
let (angular_diameter, angle, distance) = calc_angular_diameter_known_target_vector(
|
||||||
trans, camera_transform, &target_vector);
|
trans, camera_transform, &target_vector);
|
||||||
let distance_to_surface = distance - trans.scale.x;
|
|
||||||
if angle <= angular_diameter.clamp(0.001, PI) {
|
if angle <= angular_diameter.clamp(0.001, PI) {
|
||||||
// It's in the field of view!
|
// It's in the field of view!
|
||||||
//commands.entity(entity).insert(IsTargeted);
|
//commands.entity(entity).insert(IsTargeted);
|
||||||
|
let distance_to_surface = distance - trans.scale.x;
|
||||||
if distance_to_surface < closest_distance {
|
if distance_to_surface < closest_distance {
|
||||||
closest_distance = distance_to_surface;
|
closest_distance = distance_to_surface;
|
||||||
closest_entity = Some(entity);
|
closest_entity = Some(entity);
|
||||||
|
|
24
src/chat.rs
24
src/chat.rs
|
@ -778,6 +778,7 @@ pub fn handle_chat_scripts(
|
||||||
mut q_playercam: Query<(&mut Position, &mut LinearVelocity), With<actor::PlayerCamera>>,
|
mut q_playercam: Query<(&mut Position, &mut LinearVelocity), With<actor::PlayerCamera>>,
|
||||||
mut ew_sfx: EventWriter<audio::PlaySfxEvent>,
|
mut ew_sfx: EventWriter<audio::PlaySfxEvent>,
|
||||||
mut ew_effect: EventWriter<effects::SpawnEffectEvent>,
|
mut ew_effect: EventWriter<effects::SpawnEffectEvent>,
|
||||||
|
id2pos: Res<actor::Id2Pos>,
|
||||||
) {
|
) {
|
||||||
for script in er_chatscript.read() {
|
for script in er_chatscript.read() {
|
||||||
// Parse the script string
|
// Parse the script string
|
||||||
|
@ -834,19 +835,20 @@ pub fn handle_chat_scripts(
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if let Ok((mut pos, mut v)) = q_playercam.get_single_mut() {
|
if let Ok((mut pos, mut v)) = q_playercam.get_single_mut() {
|
||||||
if param1 == "oscillation".to_string() {
|
let busstop = match param1 {
|
||||||
*pos = Position(DVec3::new(-184968e3, 149410e3, -134273e3));
|
"serenity" => Some("busstop"),
|
||||||
|
"oscillation" => Some("busstop2"),
|
||||||
|
"metisprime" => Some("busstop3"),
|
||||||
|
_ => None
|
||||||
|
};
|
||||||
|
if let Some(station) = busstop {
|
||||||
|
if let Some(target) = id2pos.0.get(&station.to_string()) {
|
||||||
|
pos.0 = *target + DVec3::new(0.0, -1000.0, 0.0);
|
||||||
v.0 = DVec3::ZERO;
|
v.0 = DVec3::ZERO;
|
||||||
|
} else {
|
||||||
|
error!("Could not determine position of actor with ID: '{}'", station);
|
||||||
}
|
}
|
||||||
else if param1 == "metisprime".to_string() {
|
} else {
|
||||||
*pos = Position(DVec3::new(27643e3, -47e3, -124434e3));
|
|
||||||
v.0 = DVec3::ZERO;
|
|
||||||
}
|
|
||||||
else if param1 == "serenity".to_string() {
|
|
||||||
*pos = Position(DVec3::new(-121095e3, 582e3, -190816e3));
|
|
||||||
v.0 = DVec3::ZERO;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
error!("Invalid destination for cryotrip chat script: '{}'", param1);
|
error!("Invalid destination for cryotrip chat script: '{}'", param1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
138
src/commands.rs
138
src/commands.rs
|
@ -3,11 +3,10 @@ extern crate regex;
|
||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
use bevy_xpbd_3d::prelude::*;
|
use bevy_xpbd_3d::prelude::*;
|
||||||
use bevy::math::DVec3;
|
use bevy::math::DVec3;
|
||||||
use crate::{actor, chat, hud, nature, world};
|
use crate::{actor, camera, chat, hud, nature, shading, world};
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use std::f32::consts::PI;
|
use std::f32::consts::PI;
|
||||||
use std::f64::consts::PI as PI64;
|
use std::f64::consts::PI as PI64;
|
||||||
use std::collections::HashMap;
|
|
||||||
|
|
||||||
pub struct CommandsPlugin;
|
pub struct CommandsPlugin;
|
||||||
impl Plugin for CommandsPlugin {
|
impl Plugin for CommandsPlugin {
|
||||||
|
@ -39,12 +38,13 @@ struct ParserState {
|
||||||
// Actor fields
|
// Actor fields
|
||||||
id: String,
|
id: String,
|
||||||
pos: DVec3,
|
pos: DVec3,
|
||||||
model: String,
|
relative_to: Option<String>,
|
||||||
|
model: Option<String>,
|
||||||
model_scale: f32,
|
model_scale: f32,
|
||||||
rotation: Quat,
|
rotation: Quat,
|
||||||
velocity: DVec3,
|
velocity: DVec3,
|
||||||
angular_momentum: DVec3,
|
angular_momentum: DVec3,
|
||||||
pronoun: String,
|
pronoun: Option<String>,
|
||||||
is_sphere: bool,
|
is_sphere: bool,
|
||||||
is_player: bool,
|
is_player: bool,
|
||||||
is_lifeform: bool,
|
is_lifeform: bool,
|
||||||
|
@ -53,7 +53,9 @@ struct ParserState {
|
||||||
is_vehicle: bool,
|
is_vehicle: bool,
|
||||||
is_clickable: bool,
|
is_clickable: bool,
|
||||||
is_targeted_on_startup: bool,
|
is_targeted_on_startup: bool,
|
||||||
|
is_sun: bool,
|
||||||
has_physics: bool,
|
has_physics: bool,
|
||||||
|
has_ring: bool,
|
||||||
wants_maxrotation: Option<f64>,
|
wants_maxrotation: Option<f64>,
|
||||||
wants_maxvelocity: Option<f64>,
|
wants_maxvelocity: Option<f64>,
|
||||||
collider_is_mesh: bool,
|
collider_is_mesh: bool,
|
||||||
|
@ -72,6 +74,7 @@ struct ParserState {
|
||||||
light_brightness: f32,
|
light_brightness: f32,
|
||||||
light_color: Option<Color>,
|
light_color: Option<Color>,
|
||||||
ar_model: Option<String>,
|
ar_model: Option<String>,
|
||||||
|
show_only_in_map_at_distance: Option<(f64, String)>,
|
||||||
}
|
}
|
||||||
impl Default for ParserState {
|
impl Default for ParserState {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
|
@ -84,12 +87,13 @@ impl Default for ParserState {
|
||||||
|
|
||||||
id: "".to_string(),
|
id: "".to_string(),
|
||||||
pos: DVec3::new(0.0, 0.0, 0.0),
|
pos: DVec3::new(0.0, 0.0, 0.0),
|
||||||
model: "".to_string(),
|
relative_to: None,
|
||||||
|
model: None,
|
||||||
model_scale: 1.0,
|
model_scale: 1.0,
|
||||||
rotation: Quat::IDENTITY,
|
rotation: Quat::IDENTITY,
|
||||||
velocity: DVec3::splat(0.0),
|
velocity: DVec3::splat(0.0),
|
||||||
angular_momentum: DVec3::new(0.03, 0.3, 0.09),
|
angular_momentum: DVec3::new(0.03, 0.3, 0.09),
|
||||||
pronoun: "they/them".to_string(),
|
pronoun: None,
|
||||||
is_sphere: false,
|
is_sphere: false,
|
||||||
is_player: false,
|
is_player: false,
|
||||||
is_lifeform: false,
|
is_lifeform: false,
|
||||||
|
@ -98,7 +102,9 @@ impl Default for ParserState {
|
||||||
is_vehicle: false,
|
is_vehicle: false,
|
||||||
is_clickable: true,
|
is_clickable: true,
|
||||||
is_targeted_on_startup: false,
|
is_targeted_on_startup: false,
|
||||||
|
is_sun: false,
|
||||||
has_physics: true,
|
has_physics: true,
|
||||||
|
has_ring: false,
|
||||||
wants_maxrotation: None,
|
wants_maxrotation: None,
|
||||||
wants_maxvelocity: None,
|
wants_maxvelocity: None,
|
||||||
collider_is_mesh: false,
|
collider_is_mesh: false,
|
||||||
|
@ -117,6 +123,7 @@ impl Default for ParserState {
|
||||||
light_brightness: 0.0,
|
light_brightness: 0.0,
|
||||||
light_color: None,
|
light_color: None,
|
||||||
ar_model: None,
|
ar_model: None,
|
||||||
|
show_only_in_map_at_distance: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -131,7 +138,6 @@ pub fn load_defs(
|
||||||
let mut state = ParserState::default();
|
let mut state = ParserState::default();
|
||||||
let mut command;
|
let mut command;
|
||||||
let mut parameters;
|
let mut parameters;
|
||||||
let mut id2pos: HashMap<String, DVec3> = HashMap::new();
|
|
||||||
|
|
||||||
let mut line_nr = -1;
|
let mut line_nr = -1;
|
||||||
while let Some(line) = lines.next() {
|
while let Some(line) = lines.next() {
|
||||||
|
@ -177,7 +183,21 @@ pub fn load_defs(
|
||||||
ew_spawn.send(SpawnEvent(state));
|
ew_spawn.send(SpawnEvent(state));
|
||||||
state = ParserState::default();
|
state = ParserState::default();
|
||||||
state.class = DefClass::Actor;
|
state.class = DefClass::Actor;
|
||||||
state.model = model.to_string();
|
state.model = Some(model.to_string());
|
||||||
|
if let (Ok(x_float), Ok(y_float), Ok(z_float)) =
|
||||||
|
(x.parse::<f64>(), y.parse::<f64>(), z.parse::<f64>()) {
|
||||||
|
state.pos = DVec3::new(x_float, y_float, z_float);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
error!("Can't parse coordinates as floats in def: {line}");
|
||||||
|
state = ParserState::default();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
["actor", x, y, z] => {
|
||||||
|
ew_spawn.send(SpawnEvent(state));
|
||||||
|
state = ParserState::default();
|
||||||
|
state.class = DefClass::Actor;
|
||||||
if let (Ok(x_float), Ok(y_float), Ok(z_float)) =
|
if let (Ok(x_float), Ok(y_float), Ok(z_float)) =
|
||||||
(x.parse::<f64>(), y.parse::<f64>(), z.parse::<f64>()) {
|
(x.parse::<f64>(), y.parse::<f64>(), z.parse::<f64>()) {
|
||||||
state.pos = DVec3::new(x_float, y_float, z_float);
|
state.pos = DVec3::new(x_float, y_float, z_float);
|
||||||
|
@ -189,18 +209,7 @@ pub fn load_defs(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
["relativeto", id] => {
|
["relativeto", id] => {
|
||||||
// NOTE: call this command before "id", otherwise actors that
|
state.relative_to = Some(id.to_string());
|
||||||
// set their position relative to this actor will get the wrong offset
|
|
||||||
// TODO: fix the above
|
|
||||||
match id2pos.get(&id.to_string()) {
|
|
||||||
Some(pos) => {
|
|
||||||
state.pos += *pos;
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
error!("Specified `relativeto` command but could not find id `{id}`");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
["orbit", radius_str, phase_str] => {
|
["orbit", radius_str, phase_str] => {
|
||||||
if let (Ok(r), Ok(phase)) = (radius_str.parse::<f64>(), phase_str.parse::<f64>()) {
|
if let (Ok(r), Ok(phase)) = (radius_str.parse::<f64>(), phase_str.parse::<f64>()) {
|
||||||
|
@ -221,7 +230,6 @@ pub fn load_defs(
|
||||||
}
|
}
|
||||||
["id", id] => {
|
["id", id] => {
|
||||||
state.id = id.to_string();
|
state.id = id.to_string();
|
||||||
id2pos.insert(state.id.clone(), state.pos.clone());
|
|
||||||
}
|
}
|
||||||
["alive", "yes"] => {
|
["alive", "yes"] => {
|
||||||
state.is_alive = true;
|
state.is_alive = true;
|
||||||
|
@ -237,6 +245,13 @@ pub fn load_defs(
|
||||||
["moon", "yes"] => {
|
["moon", "yes"] => {
|
||||||
state.model_scale *= 3.0;
|
state.model_scale *= 3.0;
|
||||||
}
|
}
|
||||||
|
["sun", "yes"] => {
|
||||||
|
state.is_sun = true;
|
||||||
|
state.model_scale *= 5.0;
|
||||||
|
}
|
||||||
|
["ring", "yes"] => {
|
||||||
|
state.has_ring = true;
|
||||||
|
}
|
||||||
["oxygen", amount] => {
|
["oxygen", amount] => {
|
||||||
if let Ok(amount) = amount.parse::<f32>() {
|
if let Ok(amount) = amount.parse::<f32>() {
|
||||||
state.is_lifeform = true;
|
state.is_lifeform = true;
|
||||||
|
@ -249,7 +264,7 @@ pub fn load_defs(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
["pronoun", pronoun] => {
|
["pronoun", pronoun] => {
|
||||||
state.pronoun = pronoun.to_string();
|
state.pronoun = Some(pronoun.to_string());
|
||||||
}
|
}
|
||||||
["chatid", chat] => {
|
["chatid", chat] => {
|
||||||
state.chat = chat.to_string();
|
state.chat = chat.to_string();
|
||||||
|
@ -428,6 +443,15 @@ pub fn load_defs(
|
||||||
["targeted", "yes"] => {
|
["targeted", "yes"] => {
|
||||||
state.is_targeted_on_startup = true;
|
state.is_targeted_on_startup = true;
|
||||||
}
|
}
|
||||||
|
["only_in_map_at_dist", value, id] => {
|
||||||
|
if let Ok(value_float) = value.parse::<f64>() {
|
||||||
|
state.show_only_in_map_at_distance = Some((value_float, id.to_string()));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
error!("Can't parse float: {line}");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
_ => {
|
_ => {
|
||||||
error!("No match for [{}]", parts.join(","));
|
error!("No match for [{}]", parts.join(","));
|
||||||
}
|
}
|
||||||
|
@ -442,10 +466,26 @@ fn spawn_entities(
|
||||||
asset_server: Res<AssetServer>,
|
asset_server: Res<AssetServer>,
|
||||||
mut meshes: ResMut<Assets<Mesh>>,
|
mut meshes: ResMut<Assets<Mesh>>,
|
||||||
mut materials: ResMut<Assets<StandardMaterial>>,
|
mut materials: ResMut<Assets<StandardMaterial>>,
|
||||||
|
mut materials_jupiter: ResMut<Assets<shading::JupitersRing>>,
|
||||||
|
mut id2pos: ResMut<actor::Id2Pos>,
|
||||||
) {
|
) {
|
||||||
for state_wrapper in er_spawn.read() {
|
for state_wrapper in er_spawn.read() {
|
||||||
let state = &state_wrapper.0;
|
let state = &state_wrapper.0;
|
||||||
if state.class == DefClass::Actor {
|
if state.class == DefClass::Actor {
|
||||||
|
let relative_pos = if let Some(id) = &state.relative_to {
|
||||||
|
match id2pos.0.get(&id.to_string()) {
|
||||||
|
Some(pos) => {
|
||||||
|
state.pos + *pos
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
error!("Specified `relativeto` command but could not find id `{id}`");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
state.pos
|
||||||
|
};
|
||||||
|
|
||||||
let actor_entity;
|
let actor_entity;
|
||||||
{
|
{
|
||||||
let mut actor = commands.spawn_empty();
|
let mut actor = commands.spawn_empty();
|
||||||
|
@ -458,13 +498,17 @@ fn spawn_entities(
|
||||||
actor.insert(SleepingDisabled);
|
actor.insert(SleepingDisabled);
|
||||||
actor.insert(world::DespawnOnPlayerDeath);
|
actor.insert(world::DespawnOnPlayerDeath);
|
||||||
actor.insert(actor::HitPoints::default());
|
actor.insert(actor::HitPoints::default());
|
||||||
actor.insert(Position::from(state.pos));
|
actor.insert(Position::from(relative_pos));
|
||||||
actor.insert(Rotation::from(state.rotation));
|
actor.insert(Rotation::from(state.rotation));
|
||||||
if state.is_sphere {
|
if state.is_sphere {
|
||||||
let sphere_texture_handle: Handle<Image> = asset_server.load(format!("textures/{}.jpg", state.model));
|
let sphere_texture_handle = if let Some(model) = &state.model {
|
||||||
|
Some(asset_server.load(format!("textures/{}.jpg", model)))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
let sphere_handle = meshes.add(Sphere::new(1.0).mesh().uv(128, 128));
|
let sphere_handle = meshes.add(Sphere::new(1.0).mesh().uv(128, 128));
|
||||||
let sphere_material_handle = materials.add(StandardMaterial {
|
let sphere_material_handle = materials.add(StandardMaterial {
|
||||||
base_color_texture: Some(sphere_texture_handle.clone()),
|
base_color_texture: sphere_texture_handle,
|
||||||
perceptual_roughness: 1.0,
|
perceptual_roughness: 1.0,
|
||||||
metallic: 0.0,
|
metallic: 0.0,
|
||||||
..default()
|
..default()
|
||||||
|
@ -478,13 +522,13 @@ fn spawn_entities(
|
||||||
},
|
},
|
||||||
..default()
|
..default()
|
||||||
});
|
});
|
||||||
} else {
|
} else if let Some(model) = &state.model {
|
||||||
actor.insert(SceneBundle {
|
actor.insert(SceneBundle {
|
||||||
transform: Transform {
|
transform: Transform {
|
||||||
scale: Vec3::splat(state.model_scale),
|
scale: Vec3::splat(state.model_scale),
|
||||||
..default()
|
..default()
|
||||||
},
|
},
|
||||||
scene: asset_server.load(world::asset_name_to_path(state.model.as_str())),
|
scene: asset_server.load(world::asset_name_to_path(model.as_str())),
|
||||||
..default()
|
..default()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -524,9 +568,23 @@ fn spawn_entities(
|
||||||
actor.insert(actor::Player);
|
actor.insert(actor::Player);
|
||||||
actor.insert(actor::PlayerCamera);
|
actor.insert(actor::PlayerCamera);
|
||||||
}
|
}
|
||||||
|
if state.is_sun {
|
||||||
|
let (r, g, b) = nature::star_color_index_to_rgb(0.656);
|
||||||
|
actor.insert(materials.add(StandardMaterial {
|
||||||
|
base_color: Color::rgb(r, g, b) * 13.0,
|
||||||
|
unlit: true,
|
||||||
|
..default()
|
||||||
|
}));
|
||||||
|
}
|
||||||
if state.is_targeted_on_startup {
|
if state.is_targeted_on_startup {
|
||||||
actor.insert(hud::IsTargeted);
|
actor.insert(hud::IsTargeted);
|
||||||
}
|
}
|
||||||
|
if let Some((mindist, id)) = &state.show_only_in_map_at_distance {
|
||||||
|
actor.insert(camera::ShowOnlyInMap {
|
||||||
|
min_distance: *mindist,
|
||||||
|
distance_to_id: id.clone()
|
||||||
|
});
|
||||||
|
}
|
||||||
if state.is_player || state.is_vehicle {
|
if state.is_player || state.is_vehicle {
|
||||||
// used to apply mouse movement to actor rotation
|
// used to apply mouse movement to actor rotation
|
||||||
actor.insert(ExternalTorque::ZERO.with_persistence(false));
|
actor.insert(ExternalTorque::ZERO.with_persistence(false));
|
||||||
|
@ -544,6 +602,7 @@ fn spawn_entities(
|
||||||
if state.is_clickable {
|
if state.is_clickable {
|
||||||
actor.insert(hud::IsClickable {
|
actor.insert(hud::IsClickable {
|
||||||
name: state.name.clone(),
|
name: state.name.clone(),
|
||||||
|
pronoun: state.pronoun.clone(),
|
||||||
..default()
|
..default()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -565,12 +624,16 @@ fn spawn_entities(
|
||||||
..default()
|
..default()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
if !state.id.is_empty() {
|
||||||
|
actor.insert(actor::Identifier(state.id.clone()));
|
||||||
|
id2pos.0.insert(state.id.clone(), relative_pos);
|
||||||
|
}
|
||||||
if !state.chat.is_empty() {
|
if !state.chat.is_empty() {
|
||||||
actor.insert(chat::Talker {
|
actor.insert(chat::Talker {
|
||||||
actor_id: state.id.clone(),
|
actor_id: state.id.clone(),
|
||||||
chat_name: state.chat.clone(),
|
chat_name: state.chat.clone(),
|
||||||
name: state.name.clone(),
|
name: state.name.clone(),
|
||||||
pronoun: Some(state.pronoun.clone()),
|
pronoun: state.pronoun.clone(),
|
||||||
talking_speed: 1.0,
|
talking_speed: 1.0,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -612,6 +675,25 @@ fn spawn_entities(
|
||||||
},
|
},
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if state.has_ring {
|
||||||
|
commands.spawn((
|
||||||
|
world::DespawnOnPlayerDeath,
|
||||||
|
MaterialMeshBundle {
|
||||||
|
mesh: meshes.add(Mesh::from(Cylinder::new(nature::JUPITER_RING_RADIUS as f32, 1.0))),
|
||||||
|
material: materials_jupiter.add(shading::JupitersRing {
|
||||||
|
alpha_mode: AlphaMode::Blend,
|
||||||
|
ring_radius: nature::JUPITER_RING_RADIUS as f32,
|
||||||
|
jupiter_radius: nature::JUPITER_RADIUS as f32,
|
||||||
|
}),
|
||||||
|
transform: Transform::from_translation(relative_pos.as_vec3()),
|
||||||
|
..default()
|
||||||
|
},
|
||||||
|
Position::new(relative_pos),
|
||||||
|
Rotation::from(Quat::IDENTITY),
|
||||||
|
//Rotation::from(Quat::from_rotation_x(-0.3f32.to_radians())),
|
||||||
|
));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,10 +3,11 @@ C: Impossibly instant stopping [CHEAT]
|
||||||
Shift+V/B: Same as V/B, but a thousand times faster [CHEAT]
|
Shift+V/B: Same as V/B, but a thousand times faster [CHEAT]
|
||||||
V/B: Impossible acceleration forward/backward [CHEAT]
|
V/B: Impossible acceleration forward/backward [CHEAT]
|
||||||
G: Toggle god mode / cheats [CHEAT]
|
G: Toggle god mode / cheats [CHEAT]
|
||||||
M: Toggle sound effects
|
M: Toggle map
|
||||||
T: Toggle music
|
|
||||||
Y: Toggle rotation stabilizer
|
Y: Toggle rotation stabilizer
|
||||||
F: Toggle 3rd person view
|
F: Toggle 3rd person view
|
||||||
|
F3: Toggle sound effects
|
||||||
|
F4: Toggle music
|
||||||
F11: Toggle fullscreen
|
F11: Toggle fullscreen
|
||||||
Tab: Toggle HUD + Augmented Reality
|
Tab: Toggle HUD + Augmented Reality
|
||||||
Right click: Zoom [AUGMENTED REALITY ONLY]
|
Right click: Zoom [AUGMENTED REALITY ONLY]
|
||||||
|
|
31089
src/data/stars.in
31089
src/data/stars.in
File diff suppressed because it is too large
Load diff
159
src/defs.txt
159
src/defs.txt
|
@ -1,16 +1,128 @@
|
||||||
|
actor 0 0 0
|
||||||
|
id sol
|
||||||
|
name Sol
|
||||||
|
scale 696300e3
|
||||||
|
sphere yes
|
||||||
|
sun yes
|
||||||
|
physics off
|
||||||
|
actor 0 0 0 orbitring
|
||||||
|
scale 57.91e9
|
||||||
|
rotationz 0.0353
|
||||||
|
only_in_map_at_dist 1e10 jupiter
|
||||||
|
clickable no
|
||||||
|
physics off
|
||||||
|
actor 0 0 0 orbitring
|
||||||
|
scale 108.21e9
|
||||||
|
rotationz 0.0119
|
||||||
|
only_in_map_at_dist 1e10 jupiter
|
||||||
|
clickable no
|
||||||
|
physics off
|
||||||
|
actor 0 0 0 orbitring
|
||||||
|
scale 149.598023e9
|
||||||
|
rotationz 0.0088
|
||||||
|
only_in_map_at_dist 1e10 jupiter
|
||||||
|
clickable no
|
||||||
|
physics off
|
||||||
|
actor 0 0 0 orbitring
|
||||||
|
scale 227.939366e9
|
||||||
|
rotationz 0.0091
|
||||||
|
only_in_map_at_dist 1e10 jupiter
|
||||||
|
clickable no
|
||||||
|
physics off
|
||||||
|
actor 0 0 0 orbitring
|
||||||
|
scale 778.479e9
|
||||||
|
only_in_map_at_dist 1e10 jupiter
|
||||||
|
clickable no
|
||||||
|
physics off
|
||||||
|
actor 0 0 0 orbitring
|
||||||
|
scale 1433.53e9
|
||||||
|
rotationz 0.0052
|
||||||
|
only_in_map_at_dist 1e10 jupiter
|
||||||
|
clickable no
|
||||||
|
physics off
|
||||||
|
actor 0 0 0 orbitring
|
||||||
|
scale 2870.972e9
|
||||||
|
rotationz 0.0055
|
||||||
|
only_in_map_at_dist 1e10 jupiter
|
||||||
|
clickable no
|
||||||
|
physics off
|
||||||
|
actor 0 0 0 orbitring
|
||||||
|
scale 4500e9
|
||||||
|
rotationz 0.0041
|
||||||
|
only_in_map_at_dist 1e10 jupiter
|
||||||
|
clickable no
|
||||||
|
physics off
|
||||||
|
actor 0 0 0 orbitring
|
||||||
|
scale 5906.38e9
|
||||||
|
rotationz 0.0953
|
||||||
|
only_in_map_at_dist 1e10 jupiter
|
||||||
|
clickable no
|
||||||
|
physics off
|
||||||
|
|
||||||
actor 0 0 0 jupiter
|
actor 0 0 0 jupiter
|
||||||
|
relativeto sol
|
||||||
|
orbit 778479000e3 0.5
|
||||||
id jupiter
|
id jupiter
|
||||||
name Jupiter
|
name Jupiter
|
||||||
scale 71492e3
|
scale 71492e3
|
||||||
sphere yes
|
sphere yes
|
||||||
|
ring yes
|
||||||
physics off
|
physics off
|
||||||
rotationx -0.50
|
rotationx -0.50
|
||||||
rotationz -0.28
|
rotationz -0.28
|
||||||
angularmomentum 30 30 30
|
angularmomentum 30 30 30
|
||||||
|
actor 0 0 0 orbitring
|
||||||
|
relativeto jupiter
|
||||||
|
scale 128000e3
|
||||||
|
only_in_map_at_dist 1e7 metis
|
||||||
|
clickable no
|
||||||
|
physics off
|
||||||
|
actor 0 0 0 orbitring
|
||||||
|
relativeto jupiter
|
||||||
|
scale 129000e3
|
||||||
|
only_in_map_at_dist 1e7 adrastea
|
||||||
|
clickable no
|
||||||
|
physics off
|
||||||
|
actor 0 0 0 orbitring
|
||||||
|
relativeto jupiter
|
||||||
|
scale 181365.84e3
|
||||||
|
only_in_map_at_dist 1e7 amalthea
|
||||||
|
clickable no
|
||||||
|
physics off
|
||||||
|
actor 0 0 0 orbitring
|
||||||
|
relativeto jupiter
|
||||||
|
scale 221900e3
|
||||||
|
only_in_map_at_dist 1e7 thebe
|
||||||
|
clickable no
|
||||||
|
physics off
|
||||||
|
actor 0 0 0 orbitring
|
||||||
|
relativeto jupiter
|
||||||
|
scale 421700e3
|
||||||
|
only_in_map_at_dist 1e8 io
|
||||||
|
clickable no
|
||||||
|
physics off
|
||||||
|
actor 0 0 0 orbitring
|
||||||
|
relativeto jupiter
|
||||||
|
scale 670900e3
|
||||||
|
only_in_map_at_dist 1e8 europa
|
||||||
|
clickable no
|
||||||
|
physics off
|
||||||
|
actor 0 0 0 orbitring
|
||||||
|
relativeto jupiter
|
||||||
|
scale 1070400e3
|
||||||
|
only_in_map_at_dist 1e8 ganymede
|
||||||
|
clickable no
|
||||||
|
physics off
|
||||||
|
actor 0 0 0 orbitring
|
||||||
|
relativeto jupiter
|
||||||
|
scale 1882700e3
|
||||||
|
only_in_map_at_dist 1e8 callisto
|
||||||
|
clickable no
|
||||||
|
physics off
|
||||||
|
|
||||||
actor 0 593051 0 suit
|
actor 0 593051 0 suit
|
||||||
relativeto jupiter
|
relativeto jupiter
|
||||||
orbit 226000e3 0.66
|
orbit 224000e3 0.66
|
||||||
player yes
|
player yes
|
||||||
id player
|
id player
|
||||||
scale 2
|
scale 2
|
||||||
|
@ -37,10 +149,12 @@ actor 10 -30 20 MeteorAceGT
|
||||||
|
|
||||||
actor 0 0 0 io
|
actor 0 0 0 io
|
||||||
name Io
|
name Io
|
||||||
|
id io
|
||||||
relativeto jupiter
|
relativeto jupiter
|
||||||
orbit 421700e3 0.65
|
orbit 421700e3 0.65
|
||||||
scale 1822e3
|
scale 1822e3
|
||||||
rotationy -0.40
|
rotationy -0.40
|
||||||
|
rotationx -0.50
|
||||||
angularmomentum 0 0.0001 0
|
angularmomentum 0 0.0001 0
|
||||||
sphere yes
|
sphere yes
|
||||||
moon yes
|
moon yes
|
||||||
|
@ -48,10 +162,12 @@ actor 0 0 0 io
|
||||||
|
|
||||||
actor 0 0 0 europa
|
actor 0 0 0 europa
|
||||||
name Europa
|
name Europa
|
||||||
|
id europa
|
||||||
relativeto jupiter
|
relativeto jupiter
|
||||||
orbit 670900e3 0.35
|
orbit 670900e3 0.35
|
||||||
scale 1561e3
|
scale 1561e3
|
||||||
rotationy 0.20
|
rotationy 0.20
|
||||||
|
rotationx -0.50
|
||||||
angularmomentum 0 0.0001 0
|
angularmomentum 0 0.0001 0
|
||||||
sphere yes
|
sphere yes
|
||||||
moon yes
|
moon yes
|
||||||
|
@ -59,10 +175,12 @@ actor 0 0 0 europa
|
||||||
|
|
||||||
actor 0 0 0 ganymede
|
actor 0 0 0 ganymede
|
||||||
name Ganymede
|
name Ganymede
|
||||||
|
id ganymede
|
||||||
relativeto jupiter
|
relativeto jupiter
|
||||||
orbit 1070400e3 0.93
|
orbit 1070400e3 0.93
|
||||||
scale 2634e3
|
scale 2634e3
|
||||||
rotationy -0.40
|
rotationy -0.40
|
||||||
|
rotationx -0.50
|
||||||
angularmomentum 0 0.0001 0
|
angularmomentum 0 0.0001 0
|
||||||
sphere yes
|
sphere yes
|
||||||
moon yes
|
moon yes
|
||||||
|
@ -70,10 +188,12 @@ actor 0 0 0 ganymede
|
||||||
|
|
||||||
actor 0 0 0 callisto
|
actor 0 0 0 callisto
|
||||||
name Callisto
|
name Callisto
|
||||||
|
id callisto
|
||||||
relativeto jupiter
|
relativeto jupiter
|
||||||
orbit 1882700e3 0.45
|
orbit 1882700e3 0.45
|
||||||
scale 2410e3
|
scale 2410e3
|
||||||
rotationy -0.40
|
rotationy -0.40
|
||||||
|
rotationx -0.50
|
||||||
angularmomentum 0 0.0001 0
|
angularmomentum 0 0.0001 0
|
||||||
sphere yes
|
sphere yes
|
||||||
moon yes
|
moon yes
|
||||||
|
@ -87,6 +207,30 @@ actor 0 0 0 moonlet
|
||||||
scale 50e3
|
scale 50e3
|
||||||
angularmomentum 0 0.025 0
|
angularmomentum 0 0.025 0
|
||||||
|
|
||||||
|
actor 0 0 0 moonlet
|
||||||
|
name Metis
|
||||||
|
relativeto jupiter
|
||||||
|
id metis
|
||||||
|
orbit 128000e3 0.8
|
||||||
|
scale 21.5e3
|
||||||
|
angularmomentum 0 0.025 0
|
||||||
|
|
||||||
|
actor 0 0 0 moonlet
|
||||||
|
name Adrastea
|
||||||
|
relativeto jupiter
|
||||||
|
id adrastea
|
||||||
|
orbit 129000e3 0.5
|
||||||
|
scale 8.2e3
|
||||||
|
angularmomentum 0 0.025 0
|
||||||
|
|
||||||
|
actor 0 0 0 moonlet
|
||||||
|
name Amalthea
|
||||||
|
relativeto jupiter
|
||||||
|
id amalthea
|
||||||
|
orbit 181365.84e3 0.2
|
||||||
|
scale 83.5e3
|
||||||
|
angularmomentum 0 0.025 0
|
||||||
|
|
||||||
actor 3000 0 0 moonlet
|
actor 3000 0 0 moonlet
|
||||||
name Moonlet
|
name Moonlet
|
||||||
collider mesh
|
collider mesh
|
||||||
|
@ -95,15 +239,16 @@ actor 3000 0 0 moonlet
|
||||||
scale 500
|
scale 500
|
||||||
angularmomentum 0 0.015 0
|
angularmomentum 0 0.015 0
|
||||||
|
|
||||||
actor 220 -2400 410 asteroid_lum
|
actor -8200 -4400 -8100 asteroid_lum
|
||||||
relativeto player
|
relativeto player
|
||||||
name Lum
|
name Lum
|
||||||
id Lum
|
id Lum
|
||||||
collider mesh
|
collider mesh
|
||||||
density 10000000000
|
density 10000000000
|
||||||
scale 300
|
scale 300
|
||||||
|
rotationy 0.82
|
||||||
angularmomentum 0 0.015 0
|
angularmomentum 0 0.015 0
|
||||||
actor -80 0 0 lightorb
|
actor 70 30 30 lightorb
|
||||||
relativeto Lum
|
relativeto Lum
|
||||||
name "Light Orb"
|
name "Light Orb"
|
||||||
scale 0.3
|
scale 0.3
|
||||||
|
@ -198,6 +343,7 @@ actor -3300 10 0 pizzeria
|
||||||
rotationy -0.7
|
rotationy -0.7
|
||||||
scale 3
|
scale 3
|
||||||
chatid SubduedClippy
|
chatid SubduedClippy
|
||||||
|
pronoun it
|
||||||
|
|
||||||
actor -45 -4 -4 suit
|
actor -45 -4 -4 suit
|
||||||
relativeto pizzeria
|
relativeto pizzeria
|
||||||
|
@ -233,11 +379,12 @@ actor 60 -15 -40 suit
|
||||||
actor -300 0 40 suit
|
actor -300 0 40 suit
|
||||||
relativeto player
|
relativeto player
|
||||||
id Drifter
|
id Drifter
|
||||||
name "Drifter"
|
name "梓涵"
|
||||||
chatid Drifter
|
chatid Drifter
|
||||||
oxygen 0.08
|
oxygen 0.08
|
||||||
scale 2
|
scale 2
|
||||||
collider handcrafted
|
collider handcrafted
|
||||||
|
pronoun she
|
||||||
|
|
||||||
actor 100 -18000 2000 "orb_busstop"
|
actor 100 -18000 2000 "orb_busstop"
|
||||||
relativeto player
|
relativeto player
|
||||||
|
@ -258,6 +405,7 @@ actor 100 -18000 2000 "orb_busstop"
|
||||||
rotationy -0.5
|
rotationy -0.5
|
||||||
scale 3
|
scale 3
|
||||||
chatid ClippyTransSerenity
|
chatid ClippyTransSerenity
|
||||||
|
pronoun it
|
||||||
actor 40 10 40 "orb_busstop"
|
actor 40 10 40 "orb_busstop"
|
||||||
name "Light Orb"
|
name "Light Orb"
|
||||||
relativeto busstopclippy
|
relativeto busstopclippy
|
||||||
|
@ -283,6 +431,7 @@ actor 100 -18000 2000 "orb_busstop"
|
||||||
scale 2
|
scale 2
|
||||||
collider capsule 1 0.5
|
collider capsule 1 0.5
|
||||||
chatid NPCinCryoStasis
|
chatid NPCinCryoStasis
|
||||||
|
pronoun he
|
||||||
|
|
||||||
actor -184971e3 149410e3 -134273e3 "orb_busstop"
|
actor -184971e3 149410e3 -134273e3 "orb_busstop"
|
||||||
relativeto jupiter
|
relativeto jupiter
|
||||||
|
@ -303,6 +452,7 @@ actor -184971e3 149410e3 -134273e3 "orb_busstop"
|
||||||
rotationy -0.5
|
rotationy -0.5
|
||||||
scale 3
|
scale 3
|
||||||
chatid ClippyTransOscillation
|
chatid ClippyTransOscillation
|
||||||
|
pronoun it
|
||||||
actor 40 10 40 "orb_busstop"
|
actor 40 10 40 "orb_busstop"
|
||||||
name "Light Orb"
|
name "Light Orb"
|
||||||
relativeto busstopclippy2
|
relativeto busstopclippy2
|
||||||
|
@ -339,6 +489,7 @@ actor 27643e3 -44e3 -124434e3 "orb_busstop"
|
||||||
rotationy -0.5
|
rotationy -0.5
|
||||||
scale 3
|
scale 3
|
||||||
chatid ClippyTransMetis
|
chatid ClippyTransMetis
|
||||||
|
pronoun it
|
||||||
actor 40 10 40 "orb_busstop"
|
actor 40 10 40 "orb_busstop"
|
||||||
name "Light Orb"
|
name "Light Orb"
|
||||||
relativeto busstopclippy3
|
relativeto busstopclippy3
|
||||||
|
|
18
src/hud.rs
18
src/hud.rs
|
@ -25,11 +25,13 @@ impl Plugin for HudPlugin {
|
||||||
app.add_systems(Startup, setup);
|
app.add_systems(Startup, setup);
|
||||||
app.add_systems(Update, (
|
app.add_systems(Update, (
|
||||||
update_hud,
|
update_hud,
|
||||||
update_ar_overlays,
|
|
||||||
handle_input,
|
handle_input,
|
||||||
handle_target_event,
|
handle_target_event,
|
||||||
));
|
));
|
||||||
app.add_systems(PostUpdate, (
|
app.add_systems(PostUpdate, (
|
||||||
|
update_ar_overlays
|
||||||
|
.after(world::position_to_transform)
|
||||||
|
.in_set(sync::SyncSet::PositionToTransform),
|
||||||
update_target_selectagon
|
update_target_selectagon
|
||||||
.after(PhysicsSet::Sync)
|
.after(PhysicsSet::Sync)
|
||||||
.after(camera::apply_input_to_player)
|
.after(camera::apply_input_to_player)
|
||||||
|
@ -109,10 +111,12 @@ impl Message {
|
||||||
#[derive(Component)]
|
#[derive(Component)]
|
||||||
pub struct IsClickable {
|
pub struct IsClickable {
|
||||||
pub name: Option<String>,
|
pub name: Option<String>,
|
||||||
|
pub pronoun: Option<String>,
|
||||||
pub distance: Option<f64>,
|
pub distance: Option<f64>,
|
||||||
}
|
}
|
||||||
impl Default for IsClickable { fn default() -> Self { Self {
|
impl Default for IsClickable { fn default() -> Self { Self {
|
||||||
name: None,
|
name: None,
|
||||||
|
pronoun: None,
|
||||||
distance: None,
|
distance: None,
|
||||||
}}}
|
}}}
|
||||||
|
|
||||||
|
@ -204,9 +208,10 @@ fn setup(
|
||||||
};
|
};
|
||||||
|
|
||||||
// Add Statistics HUD
|
// Add Statistics HUD
|
||||||
|
let version = &settings.version;
|
||||||
let mut bundle_fps = TextBundle::from_sections([
|
let mut bundle_fps = TextBundle::from_sections([
|
||||||
TextSection::new("", style.clone()),
|
TextSection::new("", style.clone()),
|
||||||
TextSection::new(" ⚡ ", style.clone()),
|
TextSection::new(format!(" OutFlyOS v{version} ⚡ "), style.clone()),
|
||||||
TextSection::new("", style.clone()),
|
TextSection::new("", style.clone()),
|
||||||
TextSection::new(" ☣ ", style.clone()),
|
TextSection::new(" ☣ ", style.clone()),
|
||||||
TextSection::new("", style.clone()),
|
TextSection::new("", style.clone()),
|
||||||
|
@ -486,7 +491,12 @@ fn update_hud(
|
||||||
};
|
};
|
||||||
let speed_readable = nature::readable_distance(speed);
|
let speed_readable = nature::readable_distance(speed);
|
||||||
let target_name = clickable.name.clone().unwrap_or("Unnamed".to_string());
|
let target_name = clickable.name.clone().unwrap_or("Unnamed".to_string());
|
||||||
text.sections[15].value = format!("\n\nTarget: {target_name}\nDistance: {distance}\nΔv {speed_readable}/s");
|
let pronoun = if let Some(pronoun) = &clickable.pronoun {
|
||||||
|
format!("Pronoun: {pronoun}\n")
|
||||||
|
} else {
|
||||||
|
"".to_string()
|
||||||
|
};
|
||||||
|
text.sections[15].value = format!("\n\nTarget: {target_name}\n{pronoun}Distance: {distance}\nΔv {speed_readable}/s");
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
text.sections[15].value = "".to_string();
|
text.sections[15].value = "".to_string();
|
||||||
|
@ -706,7 +716,7 @@ fn update_target_selectagon(
|
||||||
}
|
}
|
||||||
selectagon_trans.translation = target_trans.translation;
|
selectagon_trans.translation = target_trans.translation;
|
||||||
selectagon_trans.scale = target_trans.scale;
|
selectagon_trans.scale = target_trans.scale;
|
||||||
selectagon_trans.rotation = Quat::from_rotation_arc(Vec3::Z, (-selectagon_trans.translation).normalize());
|
selectagon_trans.look_at(camera_trans.translation, Vec3::X);
|
||||||
|
|
||||||
// Enlarge Selectagon to a minimum angular diameter
|
// Enlarge Selectagon to a minimum angular diameter
|
||||||
let (angular_diameter, _, _) = camera::calc_angular_diameter(
|
let (angular_diameter, _, _) = camera::calc_angular_diameter(
|
||||||
|
|
|
@ -12,6 +12,10 @@ pub const PARSEC2METER: f64 = 3.0857e16;
|
||||||
pub const DIST_JUPTER_SUN: f64 = 778479.0e6;
|
pub const DIST_JUPTER_SUN: f64 = 778479.0e6;
|
||||||
pub const EARTH_GRAVITY: f32 = 9.81;
|
pub const EARTH_GRAVITY: f32 = 9.81;
|
||||||
|
|
||||||
|
pub const SOL_RADIUS: f64 = 696_300_000.0;
|
||||||
|
pub const JUPITER_RADIUS: f64 = 71_492_000.0;
|
||||||
|
pub const JUPITER_RING_RADIUS: f64 = 229_000_000.0;
|
||||||
|
|
||||||
// Each star's values: (x, y, z, magnitude, color index, distance, name)
|
// Each star's values: (x, y, z, magnitude, color index, distance, name)
|
||||||
pub const STARS: &[(f32, f32, f32, f32, f32, f32, &str)] = &include!("data/stars.in");
|
pub const STARS: &[(f32, f32, f32, f32, f32, f32, &str)] = &include!("data/stars.in");
|
||||||
|
|
||||||
|
|
25
src/var.rs
25
src/var.rs
|
@ -18,6 +18,7 @@ pub const DEFAULT_CHAT_SPEED: f32 = 10.0;
|
||||||
pub struct Settings {
|
pub struct Settings {
|
||||||
pub dev_mode: bool,
|
pub dev_mode: bool,
|
||||||
pub god_mode: bool,
|
pub god_mode: bool,
|
||||||
|
pub version: String,
|
||||||
pub mute_sfx: bool,
|
pub mute_sfx: bool,
|
||||||
pub mute_music: bool,
|
pub mute_music: bool,
|
||||||
pub volume_sfx: u8,
|
pub volume_sfx: u8,
|
||||||
|
@ -40,11 +41,17 @@ pub struct Settings {
|
||||||
pub hud_color_choices: Color,
|
pub hud_color_choices: Color,
|
||||||
pub chat_speed: f32,
|
pub chat_speed: f32,
|
||||||
pub hud_active: bool,
|
pub hud_active: bool,
|
||||||
|
pub map_active: bool,
|
||||||
pub is_zooming: bool,
|
pub is_zooming: bool,
|
||||||
pub third_person: bool,
|
pub third_person: bool,
|
||||||
pub rotation_stabilizer_active: bool,
|
pub rotation_stabilizer_active: bool,
|
||||||
pub key_selectobject: MouseButton,
|
pub key_selectobject: MouseButton,
|
||||||
pub key_zoom: MouseButton,
|
pub key_zoom: MouseButton,
|
||||||
|
pub key_map: KeyCode,
|
||||||
|
pub key_map_zoom_out: KeyCode,
|
||||||
|
pub key_map_zoom_in: KeyCode,
|
||||||
|
//pub key_map_zoom_out_wheel: MouseButton,
|
||||||
|
//pub key_map_zoom_in_wheel: MouseButton,
|
||||||
pub key_togglehud: KeyCode,
|
pub key_togglehud: KeyCode,
|
||||||
pub key_exit: KeyCode,
|
pub key_exit: KeyCode,
|
||||||
pub key_restart: KeyCode,
|
pub key_restart: KeyCode,
|
||||||
|
@ -69,6 +76,8 @@ pub struct Settings {
|
||||||
pub key_mouseright: KeyCode,
|
pub key_mouseright: KeyCode,
|
||||||
pub key_rotateleft: KeyCode,
|
pub key_rotateleft: KeyCode,
|
||||||
pub key_rotateright: KeyCode,
|
pub key_rotateright: KeyCode,
|
||||||
|
pub key_toggle_sfx: KeyCode,
|
||||||
|
pub key_toggle_music: KeyCode,
|
||||||
pub key_reply1: KeyCode,
|
pub key_reply1: KeyCode,
|
||||||
pub key_reply2: KeyCode,
|
pub key_reply2: KeyCode,
|
||||||
pub key_reply3: KeyCode,
|
pub key_reply3: KeyCode,
|
||||||
|
@ -110,15 +119,21 @@ impl Default for Settings {
|
||||||
default_mute_music = false;
|
default_mute_music = false;
|
||||||
dev_mode = false;
|
dev_mode = false;
|
||||||
}
|
}
|
||||||
|
let version = if let Some(version) = option_env!("CARGO_PKG_VERSION") {
|
||||||
|
version.to_string()
|
||||||
|
} else {
|
||||||
|
"13.37".to_string()
|
||||||
|
};
|
||||||
|
|
||||||
Settings {
|
Settings {
|
||||||
dev_mode,
|
dev_mode,
|
||||||
god_mode: false,
|
god_mode: false,
|
||||||
|
version,
|
||||||
mute_sfx: default_mute_sfx,
|
mute_sfx: default_mute_sfx,
|
||||||
mute_music: default_mute_music,
|
mute_music: default_mute_music,
|
||||||
volume_sfx: 100,
|
volume_sfx: 100,
|
||||||
volume_music: 100,
|
volume_music: 100,
|
||||||
mouse_sensitivity: 0.7,
|
mouse_sensitivity: 0.4,
|
||||||
fov: 50.0,
|
fov: 50.0,
|
||||||
fov_highspeed: 25.0,
|
fov_highspeed: 25.0,
|
||||||
zoom_fov: 15.0,
|
zoom_fov: 15.0,
|
||||||
|
@ -136,11 +151,17 @@ impl Default for Settings {
|
||||||
hud_color_choices: Color::rgb(0.45, 0.45, 0.45),
|
hud_color_choices: Color::rgb(0.45, 0.45, 0.45),
|
||||||
chat_speed: DEFAULT_CHAT_SPEED * if dev_mode { 2.5 } else { 1.0 },
|
chat_speed: DEFAULT_CHAT_SPEED * if dev_mode { 2.5 } else { 1.0 },
|
||||||
hud_active: false,
|
hud_active: false,
|
||||||
|
map_active: false,
|
||||||
is_zooming: false,
|
is_zooming: false,
|
||||||
third_person: false,
|
third_person: false,
|
||||||
rotation_stabilizer_active: true,
|
rotation_stabilizer_active: true,
|
||||||
key_selectobject: MouseButton::Left,
|
key_selectobject: MouseButton::Left,
|
||||||
key_zoom: MouseButton::Right,
|
key_zoom: MouseButton::Right,
|
||||||
|
key_map: KeyCode::KeyM,
|
||||||
|
key_map_zoom_out: KeyCode::ShiftLeft,
|
||||||
|
key_map_zoom_in: KeyCode::ControlLeft,
|
||||||
|
//key_map_zoom_out_wheel: KeyCode::Shift,
|
||||||
|
//key_map_zoom_in_wheel: KeyCode::Shift,
|
||||||
key_togglehud: KeyCode::Tab,
|
key_togglehud: KeyCode::Tab,
|
||||||
key_exit: KeyCode::Escape,
|
key_exit: KeyCode::Escape,
|
||||||
key_restart: KeyCode::F7,
|
key_restart: KeyCode::F7,
|
||||||
|
@ -165,6 +186,8 @@ impl Default for Settings {
|
||||||
key_mouseright: KeyCode::KeyL,
|
key_mouseright: KeyCode::KeyL,
|
||||||
key_rotateleft: KeyCode::KeyU,
|
key_rotateleft: KeyCode::KeyU,
|
||||||
key_rotateright: KeyCode::KeyO,
|
key_rotateright: KeyCode::KeyO,
|
||||||
|
key_toggle_sfx: KeyCode::F3,
|
||||||
|
key_toggle_music: KeyCode::F4,
|
||||||
key_reply1: KeyCode::Digit1,
|
key_reply1: KeyCode::Digit1,
|
||||||
key_reply2: KeyCode::Digit2,
|
key_reply2: KeyCode::Digit2,
|
||||||
key_reply3: KeyCode::Digit3,
|
key_reply3: KeyCode::Digit3,
|
||||||
|
|
146
src/world.rs
146
src/world.rs
|
@ -15,6 +15,7 @@ const RING_THICKNESS: f64 = 8.0e6;
|
||||||
const STARS_MAX_MAGNITUDE: f32 = 5.5; // max 7.0, see generate_starchart.py
|
const STARS_MAX_MAGNITUDE: f32 = 5.5; // max 7.0, see generate_starchart.py
|
||||||
|
|
||||||
const CENTER_WORLD_ON_PLAYER: bool = true;
|
const CENTER_WORLD_ON_PLAYER: bool = true;
|
||||||
|
const SKYBOX: bool = false;
|
||||||
|
|
||||||
const ASTEROID_SPAWN_STEP: f64 = 500.0;
|
const ASTEROID_SPAWN_STEP: f64 = 500.0;
|
||||||
const ASTEROID_VIEW_RADIUS: f64 = 3000.0;
|
const ASTEROID_VIEW_RADIUS: f64 = 3000.0;
|
||||||
|
@ -38,6 +39,7 @@ pub fn asset_name_to_path(name: &str) -> &'static str {
|
||||||
"pizzeria" => "models/pizzeria2.glb#Scene0",
|
"pizzeria" => "models/pizzeria2.glb#Scene0",
|
||||||
"pizzasign" => "models/pizzasign.glb#Scene0",
|
"pizzasign" => "models/pizzasign.glb#Scene0",
|
||||||
"selectagon" => "models/selectagon.glb#Scene0",
|
"selectagon" => "models/selectagon.glb#Scene0",
|
||||||
|
"orbitring" => "models/orbitring.glb#Scene0",
|
||||||
"clippy" => "models/clippy.glb#Scene0",
|
"clippy" => "models/clippy.glb#Scene0",
|
||||||
"clippy_ar" => "models/clippy_ar.glb#Scene0",
|
"clippy_ar" => "models/clippy_ar.glb#Scene0",
|
||||||
"whale" => "models/whale.glb#Scene0",
|
"whale" => "models/whale.glb#Scene0",
|
||||||
|
@ -57,7 +59,6 @@ impl Plugin for WorldPlugin {
|
||||||
app.insert_resource(Gravity(DVec3::splat(0.0)));
|
app.insert_resource(Gravity(DVec3::splat(0.0)));
|
||||||
app.insert_resource(AsteroidUpdateTimer(
|
app.insert_resource(AsteroidUpdateTimer(
|
||||||
Timer::from_seconds(ASTEROID_UPDATE_INTERVAL, TimerMode::Repeating)));
|
Timer::from_seconds(ASTEROID_UPDATE_INTERVAL, TimerMode::Repeating)));
|
||||||
app.insert_resource(AsteroidDatabase(Vec::new()));
|
|
||||||
app.insert_resource(ActiveAsteroids(HashMap::new()));
|
app.insert_resource(ActiveAsteroids(HashMap::new()));
|
||||||
app.add_event::<DespawnEvent>();
|
app.add_event::<DespawnEvent>();
|
||||||
|
|
||||||
|
@ -76,15 +77,14 @@ impl Plugin for WorldPlugin {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Resource)] struct AsteroidUpdateTimer(Timer);
|
#[derive(Resource)] struct AsteroidUpdateTimer(Timer);
|
||||||
#[derive(Resource)] struct AsteroidDatabase(Vec<AsteroidData>);
|
#[derive(Resource)] pub struct ActiveAsteroids(pub HashMap<I64Vec3, AsteroidData>);
|
||||||
#[derive(Resource)] struct ActiveAsteroids(HashMap<I64Vec3, AsteroidData>);
|
|
||||||
#[derive(Resource)] struct AsteroidModel1(Handle<Scene>);
|
#[derive(Resource)] struct AsteroidModel1(Handle<Scene>);
|
||||||
#[derive(Resource)] struct AsteroidModel2(Handle<Scene>);
|
#[derive(Resource)] struct AsteroidModel2(Handle<Scene>);
|
||||||
|
|
||||||
#[derive(Component)] struct Asteroid;
|
#[derive(Component)] struct Asteroid;
|
||||||
#[derive(Component)] pub struct DespawnOnPlayerDeath;
|
#[derive(Component)] pub struct DespawnOnPlayerDeath;
|
||||||
|
|
||||||
struct AsteroidData {
|
pub struct AsteroidData {
|
||||||
entity: Entity,
|
entity: Entity,
|
||||||
//viewdistance: f64,
|
//viewdistance: f64,
|
||||||
}
|
}
|
||||||
|
@ -103,7 +103,6 @@ pub fn setup(
|
||||||
mut commands: Commands,
|
mut commands: Commands,
|
||||||
mut meshes: ResMut<Assets<Mesh>>,
|
mut meshes: ResMut<Assets<Mesh>>,
|
||||||
mut materials: ResMut<Assets<StandardMaterial>>,
|
mut materials: ResMut<Assets<StandardMaterial>>,
|
||||||
mut materials_jupiter: ResMut<Assets<shading::JupitersRing>>,
|
|
||||||
mut materials_skybox: ResMut<Assets<shading::SkyBox>>,
|
mut materials_skybox: ResMut<Assets<shading::SkyBox>>,
|
||||||
asset_server: Res<AssetServer>,
|
asset_server: Res<AssetServer>,
|
||||||
) {
|
) {
|
||||||
|
@ -112,77 +111,75 @@ pub fn setup(
|
||||||
commands.insert_resource(AsteroidModel2(asset_server.load(ASSET_ASTEROID2)));
|
commands.insert_resource(AsteroidModel2(asset_server.load(ASSET_ASTEROID2)));
|
||||||
|
|
||||||
// Generate starmap
|
// Generate starmap
|
||||||
let sphere_handle = meshes.add(Circle::new(1.0));
|
let sphere_handle = meshes.add(Sphere::new(1.0).mesh().uv(16, 16));
|
||||||
let mut starcount = 0;
|
let mut starcount = 0;
|
||||||
for star in nature::STARS {
|
for (index, star) in nature::STARS.iter().enumerate() {
|
||||||
let mag = star.3;
|
let (x, y, z, mag, _absmag, color_index, name) = *star;
|
||||||
if mag > STARS_MAX_MAGNITUDE {
|
if mag > STARS_MAX_MAGNITUDE {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let is_sun = mag < -20.0;
|
|
||||||
let mag = mag.min(6.0);
|
let (r, g, b) = nature::star_color_index_to_rgb(color_index);
|
||||||
let scale_color = {|color: f32|
|
let mut pos = DVec3::new(x as f64, z as f64, -y as f64) * nature::PARSEC2METER;
|
||||||
if is_sun {
|
if pos.length() > 1e21 {
|
||||||
color * 13.0f32
|
pos *= 0.002;
|
||||||
} else {
|
|
||||||
color * (0.0659663 * mag * mag - 1.09862 * mag + 4.3)
|
|
||||||
}
|
}
|
||||||
};
|
let pos_render = pos * 1.0;
|
||||||
|
let scale_factor = 1e-4 * pos_render.length() as f32; // from experimentation
|
||||||
|
|
||||||
|
let mag = mag.min(6.0);
|
||||||
let scale_size = {|mag: f32|
|
let scale_size = {|mag: f32|
|
||||||
if is_sun {
|
scale_factor * (0.230299 * mag * mag - 3.09013 * mag + 15.1782)
|
||||||
40000.0f32
|
|
||||||
} else {
|
|
||||||
1000.0 * (0.230299 * mag * mag - 3.09013 * mag + 15.1782)
|
|
||||||
} * 100.0
|
|
||||||
};
|
};
|
||||||
let (r, g, b) = nature::star_color_index_to_rgb(star.4);
|
let scale = scale_size(mag);
|
||||||
|
|
||||||
|
let scale_color = {|color: f32|
|
||||||
|
1.2 * color * (0.0659663 * mag * mag - 1.09862 * mag + 4.3)
|
||||||
|
};
|
||||||
|
//let scale = translation.length().powf(0.84);
|
||||||
|
//pos_render.length().powf(0.64)
|
||||||
|
//(radius as f64 * nature::SOL_RADIUS).powf(0.02) as f32 *
|
||||||
|
|
||||||
let star_color_handle = materials.add(StandardMaterial {
|
let star_color_handle = materials.add(StandardMaterial {
|
||||||
base_color: Color::rgb(scale_color(r), scale_color(g), scale_color(b)),
|
base_color: Color::rgb(scale_color(r), scale_color(g), scale_color(b)),
|
||||||
unlit: true,
|
unlit: true,
|
||||||
..default()
|
..default()
|
||||||
});
|
});
|
||||||
let mesh_distance = 1e9;
|
let name = if name.is_empty() {
|
||||||
let starchart_distance = if is_sun {
|
format!("Uncharted Star #{index}")
|
||||||
Some(nature::DIST_JUPTER_SUN)
|
} else {
|
||||||
} else if star.5 >= 100000.0 {
|
name.to_string()
|
||||||
|
};
|
||||||
|
let distance = if pos.length() > 1e21 {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
Some(nature::PARSEC2METER * star.5 as f64)
|
Some(pos.length())
|
||||||
};
|
};
|
||||||
let name = if star.6.is_empty() {
|
|
||||||
"Uncharted Star".to_string()
|
|
||||||
} else {
|
|
||||||
star.6.to_string()
|
|
||||||
};
|
|
||||||
let translation = Vec3::new(
|
|
||||||
mesh_distance * star.0,
|
|
||||||
mesh_distance * star.1,
|
|
||||||
mesh_distance * star.2,
|
|
||||||
);
|
|
||||||
let rotation = Quat::from_rotation_arc(Vec3::Z, (-translation).normalize());
|
|
||||||
commands.spawn((
|
commands.spawn((
|
||||||
Star,
|
Star,
|
||||||
hud::IsClickable {
|
hud::IsClickable {
|
||||||
name: Some(name),
|
name: Some(name),
|
||||||
distance: starchart_distance,
|
distance,
|
||||||
|
..default()
|
||||||
},
|
},
|
||||||
PbrBundle {
|
PbrBundle {
|
||||||
mesh: sphere_handle.clone(),
|
mesh: sphere_handle.clone(),
|
||||||
material: star_color_handle,
|
material: star_color_handle,
|
||||||
transform: Transform {
|
transform: Transform {
|
||||||
translation,
|
translation: pos_render.as_vec3(),
|
||||||
rotation,
|
scale: Vec3::splat(scale as f32),
|
||||||
scale: Vec3::splat(scale_size(mag)),
|
..default()
|
||||||
},
|
},
|
||||||
..default()
|
..default()
|
||||||
}
|
},
|
||||||
));
|
));
|
||||||
starcount += 1;
|
starcount += 1;
|
||||||
}
|
}
|
||||||
info!("Generated {starcount} stars");
|
info!("Generated {starcount} stars");
|
||||||
|
|
||||||
// Add shaded skybox
|
// Add shaded skybox
|
||||||
//let mut mesh = Mesh::from(Sphere::new(1e9).mesh().uv(50, 50));
|
if SKYBOX {
|
||||||
let mut mesh = Mesh::from(Sphere::new(1e10).mesh().uv(5, 5));
|
let mut mesh = Mesh::from(Sphere::new(1e10).mesh().uv(5, 5));
|
||||||
//let mut mesh = Mesh::from(Cuboid::from_size(Vec3::splat(2e10)));
|
//let mut mesh = Mesh::from(Cuboid::from_size(Vec3::splat(2e10)));
|
||||||
if let Some(Indices::U32(indices)) = mesh.indices_mut() {
|
if let Some(Indices::U32(indices)) = mesh.indices_mut() {
|
||||||
|
@ -191,34 +188,13 @@ pub fn setup(
|
||||||
slice.reverse();
|
slice.reverse();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
commands.spawn((
|
commands.spawn(MaterialMeshBundle {
|
||||||
MaterialMeshBundle {
|
|
||||||
mesh: meshes.add(mesh),
|
mesh: meshes.add(mesh),
|
||||||
material: materials_skybox.add(shading::SkyBox {}),
|
material: materials_skybox.add(shading::SkyBox {}),
|
||||||
transform: Transform::from_translation(Vec3::new(0.0, 0.0, 0.0)),
|
transform: Transform::from_translation(Vec3::new(0.0, 0.0, 0.0)),
|
||||||
..default()
|
..default()
|
||||||
},
|
});
|
||||||
Position::from_xyz(0.0, 0.0, 0.0),
|
}
|
||||||
Rotation::from(Quat::IDENTITY),
|
|
||||||
));
|
|
||||||
|
|
||||||
// Add shaded ring
|
|
||||||
let ring_radius = 229_000_000.0;
|
|
||||||
let jupiter_radius = 71_492_000.0;
|
|
||||||
commands.spawn((
|
|
||||||
MaterialMeshBundle {
|
|
||||||
mesh: meshes.add(Mesh::from(Cylinder::new(ring_radius, 1.0))),
|
|
||||||
material: materials_jupiter.add(shading::JupitersRing {
|
|
||||||
alpha_mode: AlphaMode::Blend,
|
|
||||||
ring_radius: ring_radius,
|
|
||||||
jupiter_radius: jupiter_radius,
|
|
||||||
}),
|
|
||||||
..default()
|
|
||||||
},
|
|
||||||
Position::from_xyz(0.0, 0.0, 0.0),
|
|
||||||
Rotation::from(Quat::IDENTITY),
|
|
||||||
//Rotation::from(Quat::from_rotation_x(-0.3f32.to_radians())),
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn spawn_despawn_asteroids(
|
fn spawn_despawn_asteroids(
|
||||||
|
@ -232,16 +208,24 @@ fn spawn_despawn_asteroids(
|
||||||
asteroid2_handle: Res<AsteroidModel2>,
|
asteroid2_handle: Res<AsteroidModel2>,
|
||||||
mut q_asteroid: Query<(Entity, &SceneInstance), With<Asteroid>>,
|
mut q_asteroid: Query<(Entity, &SceneInstance), With<Asteroid>>,
|
||||||
mut last_player_cell: Local<I64Vec3>,
|
mut last_player_cell: Local<I64Vec3>,
|
||||||
|
id2pos: Res<actor::Id2Pos>,
|
||||||
) {
|
) {
|
||||||
if !timer.0.tick(time.delta()).just_finished() || q_player.is_empty() {
|
if !timer.0.tick(time.delta()).just_finished() || q_player.is_empty() {
|
||||||
//if q_player.is_empty() {
|
//if q_player.is_empty() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
let jupiter_pos = if let Some(jupiter_pos) = id2pos.0.get(&"jupiter".to_string()) {
|
||||||
|
*jupiter_pos
|
||||||
|
} else {
|
||||||
|
error!("Can't spawn asteroids because Jupiter's position can not be determined");
|
||||||
|
return;
|
||||||
|
};
|
||||||
let player = q_player.get_single().unwrap();
|
let player = q_player.get_single().unwrap();
|
||||||
|
let fromjupiter = player.0 - jupiter_pos;
|
||||||
let player_cell = I64Vec3::new(
|
let player_cell = I64Vec3::new(
|
||||||
(player.x / ASTEROID_SPAWN_STEP).round() as i64,
|
(fromjupiter.x / ASTEROID_SPAWN_STEP).round() as i64,
|
||||||
(player.y / ASTEROID_SPAWN_STEP).round() as i64,
|
(fromjupiter.y / ASTEROID_SPAWN_STEP).round() as i64,
|
||||||
(player.z / ASTEROID_SPAWN_STEP).round() as i64,
|
(fromjupiter.z / ASTEROID_SPAWN_STEP).round() as i64,
|
||||||
);
|
);
|
||||||
if *last_player_cell == player_cell {
|
if *last_player_cell == player_cell {
|
||||||
return;
|
return;
|
||||||
|
@ -285,13 +269,13 @@ fn spawn_despawn_asteroids(
|
||||||
}
|
}
|
||||||
|
|
||||||
// Density based on the radius alone
|
// Density based on the radius alone
|
||||||
let radius_plane = (player.x * player.x + player.z * player.z).sqrt();
|
let radius_plane = (fromjupiter.x * fromjupiter.x + fromjupiter.z * fromjupiter.z).sqrt();
|
||||||
let density_r = nature::ring_density((radius_plane / 1e6) as f32);
|
let density_r = nature::ring_density((radius_plane / 1e6) as f32);
|
||||||
if density_r < 0.001 {
|
if density_r < 0.001 {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Density based on radius and the vertical distance to the ring
|
// Density based on radius and the vertical distance to the ring
|
||||||
let normalized_distance = player.y / (RING_THICKNESS / 2.0);
|
let normalized_distance = fromjupiter.y / (RING_THICKNESS / 2.0);
|
||||||
let density = density_r * (-4.0 * normalized_distance.powf(2.0)).exp() as f32;
|
let density = density_r * (-4.0 * normalized_distance.powf(2.0)).exp() as f32;
|
||||||
if density < 0.001 {
|
if density < 0.001 {
|
||||||
return;
|
return;
|
||||||
|
@ -342,7 +326,7 @@ fn spawn_despawn_asteroids(
|
||||||
|
|
||||||
//let max_viewdist = ASTEROID_VIEW_RADIUS / ASTEROID_SPAWN_STEP;
|
//let max_viewdist = ASTEROID_VIEW_RADIUS / ASTEROID_SPAWN_STEP;
|
||||||
let wobble = ASTEROID_SPAWN_STEP * 0.5;
|
let wobble = ASTEROID_SPAWN_STEP * 0.5;
|
||||||
let pos = DVec3::new(
|
let pos = jupiter_pos + DVec3::new(
|
||||||
origin.x as f64 * ASTEROID_SPAWN_STEP + wobble * rand_x * 2.0 - 1.0,
|
origin.x as f64 * ASTEROID_SPAWN_STEP + wobble * rand_x * 2.0 - 1.0,
|
||||||
origin.y as f64 * ASTEROID_SPAWN_STEP + wobble * rand_y * 2.0 - 1.0,
|
origin.y as f64 * ASTEROID_SPAWN_STEP + wobble * rand_y * 2.0 - 1.0,
|
||||||
origin.z as f64 * ASTEROID_SPAWN_STEP + wobble * rand_z * 2.0 - 1.0,
|
origin.z as f64 * ASTEROID_SPAWN_STEP + wobble * rand_z * 2.0 - 1.0,
|
||||||
|
@ -358,6 +342,7 @@ fn spawn_despawn_asteroids(
|
||||||
Rotation::from(Quat::from_rotation_y(-PI / 3.)),
|
Rotation::from(Quat::from_rotation_y(-PI / 3.)),
|
||||||
Position::new(pos),
|
Position::new(pos),
|
||||||
Asteroid,
|
Asteroid,
|
||||||
|
DespawnOnPlayerDeath,
|
||||||
));
|
));
|
||||||
let model = match class {
|
let model = match class {
|
||||||
0 => asteroid1_handle.0.clone(),
|
0 => asteroid1_handle.0.clone(),
|
||||||
|
@ -400,6 +385,7 @@ fn handle_cheats(
|
||||||
q_target: Query<(&Transform, &Position, &LinearVelocity), (With<hud::IsTargeted>, Without<actor::PlayerCamera>)>,
|
q_target: Query<(&Transform, &Position, &LinearVelocity), (With<hud::IsTargeted>, Without<actor::PlayerCamera>)>,
|
||||||
mut ew_playerdies: EventWriter<actor::PlayerDiesEvent>,
|
mut ew_playerdies: EventWriter<actor::PlayerDiesEvent>,
|
||||||
mut settings: ResMut<var::Settings>,
|
mut settings: ResMut<var::Settings>,
|
||||||
|
id2pos: Res<actor::Id2Pos>,
|
||||||
mut ew_sfx: EventWriter<audio::PlaySfxEvent>,
|
mut ew_sfx: EventWriter<audio::PlaySfxEvent>,
|
||||||
) {
|
) {
|
||||||
if q_player.is_empty() || q_life.is_empty() {
|
if q_player.is_empty() || q_life.is_empty() {
|
||||||
|
@ -447,17 +433,23 @@ fn handle_cheats(
|
||||||
}
|
}
|
||||||
|
|
||||||
if key_input.just_pressed(settings.key_cheat_pizza) {
|
if key_input.just_pressed(settings.key_cheat_pizza) {
|
||||||
pos.0 = DVec3::new(-121100218.0, 593057.0, -190818113.0);
|
if let Some(target) = id2pos.0.get(&"pizzeria".to_string()) {
|
||||||
|
pos.0 = *target + DVec3::new(-60.0, 0.0, 0.0);
|
||||||
gforce.ignore_gforce_seconds = 1.0;
|
gforce.ignore_gforce_seconds = 1.0;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if key_input.just_pressed(settings.key_cheat_farview1) {
|
if key_input.just_pressed(settings.key_cheat_farview1) {
|
||||||
pos.0 = DVec3::new(27643e3, -47e3, -124434e3);
|
if let Some(target) = id2pos.0.get(&"busstop2".to_string()) {
|
||||||
|
pos.0 = *target + DVec3::new(0.0, -1000.0, 0.0);
|
||||||
gforce.ignore_gforce_seconds = 1.0;
|
gforce.ignore_gforce_seconds = 1.0;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if key_input.just_pressed(settings.key_cheat_farview2) {
|
if key_input.just_pressed(settings.key_cheat_farview2) {
|
||||||
pos.0 = DVec3::new(-184968e3, 149410e3, -134273e3);
|
if let Some(target) = id2pos.0.get(&"busstop3".to_string()) {
|
||||||
|
pos.0 = *target + DVec3::new(0.0, -1000.0, 0.0);
|
||||||
gforce.ignore_gforce_seconds = 1.0;
|
gforce.ignore_gforce_seconds = 1.0;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if key_input.pressed(settings.key_cheat_adrenaline_zero) {
|
if key_input.pressed(settings.key_cheat_adrenaline_zero) {
|
||||||
lifeform.adrenaline = 0.0;
|
lifeform.adrenaline = 0.0;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue