Compare commits
33 commits
a26a8c79f7
...
6d12033e23
Author | SHA1 | Date | |
---|---|---|---|
yuni | 6d12033e23 | ||
yuni | f95a69c095 | ||
yuni | 7475b104ba | ||
yuni | 24edac27e5 | ||
yuni | 5373edb02f | ||
yuni | c880a8fb97 | ||
yuni | 8afd150223 | ||
yuni | f56521e49f | ||
yuni | babbef279a | ||
yuni | b186b37ffb | ||
yuni | fc01b68086 | ||
yuni | 8248d43463 | ||
yuni | 3079b17a1b | ||
yuni | fd16d6931e | ||
yuni | 4d4ccb9d9f | ||
yuni | 9d9482dd4a | ||
yuni | 4ac1d020e2 | ||
yuni | 2402fe7b03 | ||
yuni | 23a85807a5 | ||
yuni | efd85e1433 | ||
yuni | 830d371e36 | ||
yuni | cf34ab5a63 | ||
yuni | c7a050e2aa | ||
yuni | 6002688bb4 | ||
yuni | a66660cb44 | ||
yuni | 390e7917ad | ||
yuni | 0b162de00f | ||
yuni | f815e3d62e | ||
yuni | 02dab4b4b7 | ||
yuni | b8a122904a | ||
yuni | 22bfc62acc | ||
yuni | 35d6937793 | ||
yuni | 45fbd4e2b5 |
|
@ -11,7 +11,7 @@ rust-version = "1.76.0"
|
||||||
|
|
||||||
[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", "x11"]}
|
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_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"
|
||||||
|
@ -19,8 +19,10 @@ serde = "1.0"
|
||||||
serde_yaml = "0.9"
|
serde_yaml = "0.9"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
|
default = ["x11"]
|
||||||
dev = ["bevy/dynamic_linking", "bevy/file_watcher"]
|
dev = ["bevy/dynamic_linking", "bevy/file_watcher"]
|
||||||
wasm = ["bevy/webgl2"]
|
wasm = ["bevy/webgl2"]
|
||||||
|
x11 = ["bevy/x11"]
|
||||||
wayland = ["bevy/wayland"]
|
wayland = ["bevy/wayland"]
|
||||||
|
|
||||||
[profile.dev]
|
[profile.dev]
|
||||||
|
|
|
@ -27,6 +27,7 @@ Links:
|
||||||
|
|
||||||
# Key Bindings
|
# Key Bindings
|
||||||
|
|
||||||
|
- F1: Show key bindings
|
||||||
- Space: Slow down (or match velocity)
|
- Space: Slow down (or match velocity)
|
||||||
- AWSD/Shift/Ctrl: Accelerate
|
- AWSD/Shift/Ctrl: Accelerate
|
||||||
- R: Rotate (hold & move mouse)
|
- R: Rotate (hold & move mouse)
|
||||||
|
|
BIN
assets/models/asteroid_lum.glb
Normal file
BIN
assets/models/asteroid_lum.glb
Normal file
Binary file not shown.
BIN
assets/models/suit_with_collider.glb
Normal file
BIN
assets/models/suit_with_collider.glb
Normal file
Binary file not shown.
BIN
assets/models/whale.glb
Normal file
BIN
assets/models/whale.glb
Normal file
Binary file not shown.
77
assets/shaders/material_asteroid.wgsl
Normal file
77
assets/shaders/material_asteroid.wgsl
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
#import bevy_pbr::{
|
||||||
|
mesh_view_bindings::view,
|
||||||
|
pbr_fragment::pbr_input_from_standard_material,
|
||||||
|
pbr_functions::alpha_discard,
|
||||||
|
utils::coords_to_viewport_uv,
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef PREPASS_PIPELINE
|
||||||
|
#import bevy_pbr::{
|
||||||
|
prepass_io::{VertexOutput, FragmentOutput},
|
||||||
|
pbr_deferred_functions::deferred_output,
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#import bevy_pbr::{
|
||||||
|
forward_io::{VertexOutput, FragmentOutput},
|
||||||
|
pbr_functions::{apply_pbr_lighting, main_pass_post_lighting_processing},
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct MyExtendedMaterial {
|
||||||
|
quantize_steps: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
@group(2) @binding(100)
|
||||||
|
var<uniform> my_extended_material: MyExtendedMaterial;
|
||||||
|
|
||||||
|
@fragment
|
||||||
|
fn fragment(
|
||||||
|
in: VertexOutput,
|
||||||
|
@builtin(front_facing) is_front: bool,
|
||||||
|
) -> FragmentOutput {
|
||||||
|
// generate a PbrInput struct from the StandardMaterial bindings
|
||||||
|
var pbr_input = pbr_input_from_standard_material(in, is_front);
|
||||||
|
|
||||||
|
// we can optionally modify the input before lighting and alpha_discard is applied
|
||||||
|
//pbr_input.material.base_color.b = pbr_input.material.base_color.r;
|
||||||
|
|
||||||
|
// alpha discard
|
||||||
|
pbr_input.material.base_color = alpha_discard(pbr_input.material, pbr_input.material.base_color);
|
||||||
|
|
||||||
|
#ifdef PREPASS_PIPELINE
|
||||||
|
// in deferred mode we can't modify anything after that, as lighting is run in a separate fullscreen shader.
|
||||||
|
let out = deferred_output(in, pbr_input);
|
||||||
|
#else
|
||||||
|
var out: FragmentOutput;
|
||||||
|
// apply lighting
|
||||||
|
out.color = apply_pbr_lighting(pbr_input);
|
||||||
|
|
||||||
|
// we can optionally modify the lit color before post-processing is applied
|
||||||
|
//out.color = vec4<f32>(vec4<u32>(out.color * f32(my_extended_material.quantize_steps))) / f32(my_extended_material.quantize_steps);
|
||||||
|
|
||||||
|
// apply in-shader post processing (fog, alpha-premultiply, and also tonemapping, debanding if the camera is non-hdr)
|
||||||
|
// note this does not include fullscreen postprocessing effects like bloom.
|
||||||
|
out.color = main_pass_post_lighting_processing(pbr_input, out.color);
|
||||||
|
|
||||||
|
// we can optionally modify the final result here
|
||||||
|
//out.color = out.color * 2.0;
|
||||||
|
|
||||||
|
//#ifdef VERTEX_UV
|
||||||
|
// out.color = out.color * grain(in.u, in.v);
|
||||||
|
// out.color = vec4<f32>(0.0, 1.0, 0.0, 1.0);
|
||||||
|
//#else
|
||||||
|
// // Why am I not getting in.uv??
|
||||||
|
// let viewport_uv = coords_to_viewport_uv(in.position.xy, view.viewport);
|
||||||
|
// out.color = out.color * grain(viewport_uv);
|
||||||
|
//#endif
|
||||||
|
out.color = out.color * grain(in.position.xyz);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn grain(uv: vec3<f32>) -> f32 {
|
||||||
|
return clamp(sin(uv[0]+uv[2])+cos(uv[1]), 0.0, 1.0);
|
||||||
|
}
|
11
assets/shaders/skybox.wgsl
Normal file
11
assets/shaders/skybox.wgsl
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
#import bevy_pbr::{
|
||||||
|
mesh_view_bindings::globals,
|
||||||
|
forward_io::VertexOutput,
|
||||||
|
}
|
||||||
|
|
||||||
|
@fragment
|
||||||
|
fn fragment(in: VertexOutput) -> @location(0) vec4<f32> {
|
||||||
|
let pos: vec2<f32> = 10 * floor(3500 * in.uv);
|
||||||
|
let brightness: vec3<f32> = vec3(max((fract(dot(sin(pos),pos)) - 0.995) * 90.0, 0.0));
|
||||||
|
return vec4<f32>(0.01 * brightness, 1.0);
|
||||||
|
}
|
|
@ -5,8 +5,8 @@
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
if [ "$1" == "-b" ]; then
|
if [ "$1" == "-b" ]; then
|
||||||
cargo build --release
|
cargo build --release --target=x86_64-unknown-linux-gnu --features "x11 wayland"
|
||||||
cargo build --target=x86_64-pc-windows-gnu --release
|
cargo build --release --target=x86_64-pc-windows-gnu --no-default-features
|
||||||
fi
|
fi
|
||||||
|
|
||||||
VERSION="$(sed -nr 's/^\s*version\s*=\s*"(.*)"\s*$/\1/p' Cargo.toml)"
|
VERSION="$(sed -nr 's/^\s*version\s*=\s*"(.*)"\s*$/\1/p' Cargo.toml)"
|
||||||
|
@ -25,7 +25,7 @@ cp ../target/x86_64-pc-windows-gnu/release/outfly.exe "$SRCPATH"
|
||||||
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/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"
|
||||||
|
|
||||||
cd ..
|
cd ..
|
||||||
|
|
|
@ -264,6 +264,7 @@ pub fn apply_input_to_player(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// TODO: handle mass
|
||||||
v.0 += acceleration_total;
|
v.0 += acceleration_total;
|
||||||
engine.current_warmup = (engine.current_warmup + dt / engine.warmup_seconds).clamp(0.0, 1.0);
|
engine.current_warmup = (engine.current_warmup + dt / engine.warmup_seconds).clamp(0.0, 1.0);
|
||||||
play_thruster_sound = true;
|
play_thruster_sound = true;
|
||||||
|
@ -405,11 +406,12 @@ 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);
|
||||||
if distance < closest_distance {
|
if distance_to_surface < closest_distance {
|
||||||
closest_distance = distance;
|
closest_distance = distance_to_surface;
|
||||||
closest_entity = Some(entity);
|
closest_entity = Some(entity);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -691,6 +691,11 @@ pub fn handle_chat_events(
|
||||||
hud::LogLevel::Warning => {
|
hud::LogLevel::Warning => {
|
||||||
log.warning(message.into());
|
log.warning(message.into());
|
||||||
}
|
}
|
||||||
|
hud::LogLevel::Always => {
|
||||||
|
log.add(message.into(),
|
||||||
|
chat.talker.name.clone().unwrap_or("".to_string()),
|
||||||
|
hud::LogLevel::Always);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
chat.timer = now + ((message.len() as f32).max(CHAT_SPEED_MIN_LEN) * TALKER_SPEED_FACTOR * chat.talker.talking_speed / settings.chat_speed) as f64;
|
chat.timer = now + ((message.len() as f32).max(CHAT_SPEED_MIN_LEN) * TALKER_SPEED_FACTOR * chat.talker.talking_speed / settings.chat_speed) as f64;
|
||||||
|
|
||||||
|
|
|
@ -14,10 +14,13 @@ impl Plugin for CommandsPlugin {
|
||||||
fn build(&self, app: &mut App) {
|
fn build(&self, app: &mut App) {
|
||||||
app.add_systems(Startup, load_defs);
|
app.add_systems(Startup, load_defs);
|
||||||
app.add_systems(Update, spawn_entities);
|
app.add_systems(Update, spawn_entities);
|
||||||
|
app.add_systems(PreUpdate, hide_colliders
|
||||||
|
.run_if(any_with_component::<NeedsSceneColliderRemoved>));
|
||||||
app.add_event::<SpawnEvent>();
|
app.add_event::<SpawnEvent>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Component)] pub struct NeedsSceneColliderRemoved;
|
||||||
#[derive(Event)] pub struct SpawnEvent(ParserState);
|
#[derive(Event)] pub struct SpawnEvent(ParserState);
|
||||||
#[derive(PartialEq, Clone)]
|
#[derive(PartialEq, Clone)]
|
||||||
enum DefClass {
|
enum DefClass {
|
||||||
|
@ -49,10 +52,12 @@ struct ParserState {
|
||||||
is_suited: bool,
|
is_suited: bool,
|
||||||
is_vehicle: bool,
|
is_vehicle: bool,
|
||||||
is_clickable: bool,
|
is_clickable: bool,
|
||||||
|
is_targeted_on_startup: bool,
|
||||||
has_physics: bool,
|
has_physics: 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,
|
||||||
|
collider_is_one_mesh_of_scene: bool,
|
||||||
thrust_forward: f32,
|
thrust_forward: f32,
|
||||||
thrust_sideways: f32,
|
thrust_sideways: f32,
|
||||||
thrust_back: f32,
|
thrust_back: f32,
|
||||||
|
@ -92,10 +97,12 @@ impl Default for ParserState {
|
||||||
is_suited: false,
|
is_suited: false,
|
||||||
is_vehicle: false,
|
is_vehicle: false,
|
||||||
is_clickable: true,
|
is_clickable: true,
|
||||||
|
is_targeted_on_startup: false,
|
||||||
has_physics: true,
|
has_physics: true,
|
||||||
wants_maxrotation: None,
|
wants_maxrotation: None,
|
||||||
wants_maxvelocity: None,
|
wants_maxvelocity: None,
|
||||||
collider_is_mesh: false,
|
collider_is_mesh: false,
|
||||||
|
collider_is_one_mesh_of_scene: false,
|
||||||
thrust_forward: default_engine.thrust_forward,
|
thrust_forward: default_engine.thrust_forward,
|
||||||
thrust_sideways: default_engine.thrust_forward,
|
thrust_sideways: default_engine.thrust_forward,
|
||||||
thrust_back: default_engine.thrust_back,
|
thrust_back: default_engine.thrust_back,
|
||||||
|
@ -184,6 +191,7 @@ pub fn load_defs(
|
||||||
["relativeto", id] => {
|
["relativeto", id] => {
|
||||||
// NOTE: call this command before "id", otherwise actors that
|
// NOTE: call this command before "id", otherwise actors that
|
||||||
// set their position relative to this actor will get the wrong offset
|
// set their position relative to this actor will get the wrong offset
|
||||||
|
// TODO: fix the above
|
||||||
match id2pos.get(&id.to_string()) {
|
match id2pos.get(&id.to_string()) {
|
||||||
Some(pos) => {
|
Some(pos) => {
|
||||||
state.pos += *pos;
|
state.pos += *pos;
|
||||||
|
@ -362,6 +370,9 @@ pub fn load_defs(
|
||||||
["collider", "mesh"] => {
|
["collider", "mesh"] => {
|
||||||
state.collider_is_mesh = true;
|
state.collider_is_mesh = true;
|
||||||
}
|
}
|
||||||
|
["collider", "handcrafted"] => {
|
||||||
|
state.collider_is_one_mesh_of_scene = true;
|
||||||
|
}
|
||||||
["player", "yes"] => {
|
["player", "yes"] => {
|
||||||
state.is_player = true;
|
state.is_player = true;
|
||||||
state.is_alive = true;
|
state.is_alive = true;
|
||||||
|
@ -414,6 +425,9 @@ pub fn load_defs(
|
||||||
["armodel", asset_name] => {
|
["armodel", asset_name] => {
|
||||||
state.ar_model = Some(asset_name.to_string());
|
state.ar_model = Some(asset_name.to_string());
|
||||||
}
|
}
|
||||||
|
["targeted", "yes"] => {
|
||||||
|
state.is_targeted_on_startup = true;
|
||||||
|
}
|
||||||
_ => {
|
_ => {
|
||||||
error!("No match for [{}]", parts.join(","));
|
error!("No match for [{}]", parts.join(","));
|
||||||
}
|
}
|
||||||
|
@ -482,11 +496,23 @@ fn spawn_entities(
|
||||||
actor.insert(AngularVelocity(state.angular_momentum));
|
actor.insert(AngularVelocity(state.angular_momentum));
|
||||||
actor.insert(ColliderDensity(state.density));
|
actor.insert(ColliderDensity(state.density));
|
||||||
if state.collider_is_mesh {
|
if state.collider_is_mesh {
|
||||||
|
actor.insert(MassPropertiesBundle::new_computed(
|
||||||
|
&Collider::sphere(0.5 * state.model_scale as f64), state.density));
|
||||||
actor.insert(AsyncSceneCollider::new(Some(
|
actor.insert(AsyncSceneCollider::new(Some(
|
||||||
ComputedCollider::TriMesh
|
ComputedCollider::TriMesh
|
||||||
//ComputedCollider::ConvexDecomposition(VHACDParameters::default())
|
//ComputedCollider::ConvexDecomposition(VHACDParameters::default())
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
|
else if state.collider_is_one_mesh_of_scene {
|
||||||
|
actor.insert(MassPropertiesBundle::new_computed(
|
||||||
|
&Collider::sphere(0.5 * state.model_scale as f64), state.density));
|
||||||
|
actor.insert(AsyncSceneCollider::new(None)
|
||||||
|
.with_shape_for_name("Collider", ComputedCollider::TriMesh)
|
||||||
|
.with_layers_for_name("Collider", CollisionLayers::ALL)
|
||||||
|
//.with_density_for_name("Collider", state.density)
|
||||||
|
);
|
||||||
|
actor.insert(NeedsSceneColliderRemoved);
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
actor.insert(state.collider.clone());
|
actor.insert(state.collider.clone());
|
||||||
}
|
}
|
||||||
|
@ -498,6 +524,9 @@ fn spawn_entities(
|
||||||
actor.insert(actor::Player);
|
actor.insert(actor::Player);
|
||||||
actor.insert(actor::PlayerCamera);
|
actor.insert(actor::PlayerCamera);
|
||||||
}
|
}
|
||||||
|
if state.is_targeted_on_startup {
|
||||||
|
actor.insert(hud::IsTargeted);
|
||||||
|
}
|
||||||
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));
|
||||||
|
@ -586,3 +615,20 @@ fn spawn_entities(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pub fn hide_colliders(
|
||||||
|
//mut commands: Commands,
|
||||||
|
mut q_mesh: Query<(&mut Visibility, &Name), With<Handle<Mesh>>>,
|
||||||
|
//q_flag: Query<Entity, With<NeedsSceneColliderRemoved>>,
|
||||||
|
) {
|
||||||
|
for (mut visibility, name) in &mut q_mesh {
|
||||||
|
if name.as_str() == "Collider" {
|
||||||
|
*visibility = Visibility::Hidden;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// TODO: not quite done here yet...
|
||||||
|
// for entity in &q_flag {
|
||||||
|
// commands.entity(entity).remove::<NeedsSceneColliderRemoved>();
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
20
src/data/keybindings.in
Normal file
20
src/data/keybindings.in
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
X: Teleport to target [CHEAT]
|
||||||
|
C: Impossibly instant stopping [CHEAT]
|
||||||
|
Shift+V/B: Same as V/B, but a thousand times faster [CHEAT]
|
||||||
|
V/B: Impossible acceleration forward/backward [CHEAT]
|
||||||
|
G: Toggle god mode / cheats [CHEAT]
|
||||||
|
M: Toggle sound effects
|
||||||
|
T: Toggle music
|
||||||
|
Y: Toggle rotation stabilizer
|
||||||
|
F: Toggle 3rd person view
|
||||||
|
F11: Toggle fullscreen
|
||||||
|
Tab: Toggle HUD + Augmented Reality
|
||||||
|
Right click: Zoom [AUGMENTED REALITY ONLY]
|
||||||
|
Left click: Target objects [AUGMENTED REALITY ONLY]
|
||||||
|
JKULIO: Mouseless camera rotation
|
||||||
|
F7: Restart game
|
||||||
|
Q: Exit vehicle
|
||||||
|
E: Interact: Talk to people, enter vehicles
|
||||||
|
R: Rotate (hold & move mouse)
|
||||||
|
AWSD/Shift/Ctrl: Accelerate
|
||||||
|
Space: Slow down (or match velocity)
|
56
src/defs.txt
56
src/defs.txt
|
@ -14,10 +14,11 @@ actor 0 593051 0 suit
|
||||||
player yes
|
player yes
|
||||||
id player
|
id player
|
||||||
scale 2
|
scale 2
|
||||||
|
density 200
|
||||||
|
collider handcrafted
|
||||||
oxygen 0.008
|
oxygen 0.008
|
||||||
health 0.3
|
health 0.3
|
||||||
angularmomentum 0 0 0
|
angularmomentum 0 0 0
|
||||||
collider capsule 1 0.5
|
|
||||||
thrust 1.2 1 1 400 1.5
|
thrust 1.2 1 1 400 1.5
|
||||||
rotationy 0.65
|
rotationy 0.65
|
||||||
engine monopropellant
|
engine monopropellant
|
||||||
|
@ -27,11 +28,11 @@ actor 10 -30 20 MeteorAceGT
|
||||||
relativeto player
|
relativeto player
|
||||||
scale 5
|
scale 5
|
||||||
vehicle yes
|
vehicle yes
|
||||||
thrust 24.5 4.8 3.3 500000 3
|
collider mesh
|
||||||
|
thrust 24.5 4.8 3.3 100000 3
|
||||||
engine ion
|
engine ion
|
||||||
collider sphere 1
|
|
||||||
camdistance 50
|
camdistance 50
|
||||||
density 200
|
density 500
|
||||||
angularmomentum 0.1 0.1 0.3
|
angularmomentum 0.1 0.1 0.3
|
||||||
|
|
||||||
actor 0 0 0 io
|
actor 0 0 0 io
|
||||||
|
@ -88,9 +89,25 @@ actor 0 0 0 moonlet
|
||||||
|
|
||||||
actor 3000 0 0 moonlet
|
actor 3000 0 0 moonlet
|
||||||
name Moonlet
|
name Moonlet
|
||||||
|
collider mesh
|
||||||
relativeto player
|
relativeto player
|
||||||
|
density 10000000000
|
||||||
scale 500
|
scale 500
|
||||||
angularmomentum 0 0.15 0
|
angularmomentum 0 0.015 0
|
||||||
|
|
||||||
|
actor 220 -2400 410 asteroid_lum
|
||||||
|
relativeto player
|
||||||
|
name Lum
|
||||||
|
id Lum
|
||||||
|
collider mesh
|
||||||
|
density 10000000000
|
||||||
|
scale 300
|
||||||
|
angularmomentum 0 0.015 0
|
||||||
|
actor -80 0 0 lightorb
|
||||||
|
relativeto Lum
|
||||||
|
name "Light Orb"
|
||||||
|
scale 0.3
|
||||||
|
light FF8F4A 500000
|
||||||
|
|
||||||
actor -200 -110 1000 satellite
|
actor -200 -110 1000 satellite
|
||||||
name "Communications Satellite"
|
name "Communications Satellite"
|
||||||
|
@ -139,6 +156,7 @@ actor -3300 10 0 pizzeria
|
||||||
relativeto player
|
relativeto player
|
||||||
id pizzeria
|
id pizzeria
|
||||||
scale 40
|
scale 40
|
||||||
|
collider mesh
|
||||||
rotationy 0.30
|
rotationy 0.30
|
||||||
angularmomentum 0 0 0
|
angularmomentum 0 0 0
|
||||||
actor -120 0 20 MeteorAceGT
|
actor -120 0 20 MeteorAceGT
|
||||||
|
@ -146,11 +164,11 @@ actor -3300 10 0 pizzeria
|
||||||
relativeto pizzeria
|
relativeto pizzeria
|
||||||
scale 5
|
scale 5
|
||||||
vehicle yes
|
vehicle yes
|
||||||
thrust 24.5 4.8 3.3 500000 3
|
collider mesh
|
||||||
|
thrust 24.5 4.8 3.3 100000 3
|
||||||
engine ion
|
engine ion
|
||||||
collider sphere 1
|
|
||||||
camdistance 50
|
camdistance 50
|
||||||
density 200
|
density 500
|
||||||
angularmomentum 0 0 0.2
|
angularmomentum 0 0 0.2
|
||||||
actor -100 63 -13 pizzasign
|
actor -100 63 -13 pizzasign
|
||||||
name "Pizzeria Sign"
|
name "Pizzeria Sign"
|
||||||
|
@ -159,12 +177,12 @@ actor -3300 10 0 pizzeria
|
||||||
density 200
|
density 200
|
||||||
rotationy 0.45
|
rotationy 0.45
|
||||||
angularmomentum 0 0 0
|
angularmomentum 0 0 0
|
||||||
actor -16 -10 0 lightorb
|
actor -36 -10 0 lightorb
|
||||||
name "Light Orb"
|
name "Light Orb"
|
||||||
relativeto pizzeria
|
relativeto pizzeria
|
||||||
scale 0.5
|
scale 0.5
|
||||||
light FF8F4A 1000000
|
light FF8F4A 1000000
|
||||||
actor -14 -3 -2 lightorb
|
actor -34 -3 -2 lightorb
|
||||||
name "Light Orb"
|
name "Light Orb"
|
||||||
relativeto pizzeria
|
relativeto pizzeria
|
||||||
scale 0.5
|
scale 0.5
|
||||||
|
@ -188,7 +206,7 @@ actor -3300 10 0 pizzeria
|
||||||
armodel suit_ar_chefhat
|
armodel suit_ar_chefhat
|
||||||
alive yes
|
alive yes
|
||||||
scale 2
|
scale 2
|
||||||
collider capsule 1 0.5
|
collider handcrafted
|
||||||
thrust 1.2 1 1 10 1.5
|
thrust 1.2 1 1 10 1.5
|
||||||
wants maxrotation 0
|
wants maxrotation 0
|
||||||
wants maxvelocity 0
|
wants maxvelocity 0
|
||||||
|
@ -203,7 +221,7 @@ actor 60 -15 -40 suit
|
||||||
chatid Icarus
|
chatid Icarus
|
||||||
alive yes
|
alive yes
|
||||||
scale 2
|
scale 2
|
||||||
collider capsule 1 0.5
|
collider handcrafted
|
||||||
angularmomentum 0.4 0.2 0.1
|
angularmomentum 0.4 0.2 0.1
|
||||||
rotationy 0.6
|
rotationy 0.6
|
||||||
rotationx 1
|
rotationx 1
|
||||||
|
@ -219,7 +237,7 @@ actor -300 0 40 suit
|
||||||
chatid Drifter
|
chatid Drifter
|
||||||
oxygen 0.08
|
oxygen 0.08
|
||||||
scale 2
|
scale 2
|
||||||
collider capsule 1 0.5
|
collider handcrafted
|
||||||
|
|
||||||
actor 100 -18000 2000 "orb_busstop"
|
actor 100 -18000 2000 "orb_busstop"
|
||||||
relativeto player
|
relativeto player
|
||||||
|
@ -337,3 +355,15 @@ actor 27643e3 -44e3 -124434e3 "orb_busstop"
|
||||||
name "Light Orb"
|
name "Light Orb"
|
||||||
relativeto busstopclippy3
|
relativeto busstopclippy3
|
||||||
light "47FF00" 1000000
|
light "47FF00" 1000000
|
||||||
|
|
||||||
|
actor 110 -2000 0 whale
|
||||||
|
relativeto busstop3
|
||||||
|
name "The Whale"
|
||||||
|
vehicle yes
|
||||||
|
collider mesh
|
||||||
|
density 100000
|
||||||
|
camdistance 4000
|
||||||
|
scale 300
|
||||||
|
angularmomentum 0 0.015 0
|
||||||
|
thrust 2.45 0.48 0.33 1000000000000000 3
|
||||||
|
engine ion
|
||||||
|
|
42
src/hud.rs
42
src/hud.rs
|
@ -9,9 +9,9 @@ use std::time::SystemTime;
|
||||||
|
|
||||||
pub const HUD_REFRESH_TIME: f32 = 0.1;
|
pub const HUD_REFRESH_TIME: f32 = 0.1;
|
||||||
pub const FONT: &str = "fonts/Yupiter-Regular.ttf";
|
pub const FONT: &str = "fonts/Yupiter-Regular.ttf";
|
||||||
pub const LOG_MAX: usize = 16;
|
|
||||||
pub const LOG_MAX_TIME_S: f64 = 30.0;
|
pub const LOG_MAX_TIME_S: f64 = 30.0;
|
||||||
pub const LOG_MAX_ROWS: usize = 30;
|
pub const LOG_MAX_ROWS: usize = 30;
|
||||||
|
pub const LOG_MAX: usize = LOG_MAX_ROWS;
|
||||||
pub const MAX_CHOICES: usize = 10;
|
pub const MAX_CHOICES: usize = 10;
|
||||||
pub const AMBIENT_LIGHT: f32 = 0.0; // Space is DARK
|
pub const AMBIENT_LIGHT: f32 = 0.0; // Space is DARK
|
||||||
pub const AMBIENT_LIGHT_AR: f32 = 15.0;
|
pub const AMBIENT_LIGHT_AR: f32 = 15.0;
|
||||||
|
@ -74,6 +74,7 @@ pub struct AugmentedRealityOverlay {
|
||||||
struct FPSUpdateTimer(Timer);
|
struct FPSUpdateTimer(Timer);
|
||||||
|
|
||||||
pub enum LogLevel {
|
pub enum LogLevel {
|
||||||
|
Always,
|
||||||
Warning,
|
Warning,
|
||||||
//Error,
|
//Error,
|
||||||
Info,
|
Info,
|
||||||
|
@ -234,6 +235,9 @@ fn setup(
|
||||||
));
|
));
|
||||||
|
|
||||||
// Add Console
|
// Add Console
|
||||||
|
// This one is intentionally NOT a ToggleableHudElement. Instead, console entries
|
||||||
|
// are filtered based on whether the hud is active or not. LogLevel::Always is
|
||||||
|
// even shown when hud is inactive.
|
||||||
let bundle_chatbox = TextBundle::from_sections((0..LOG_MAX_ROWS).map(|_|
|
let bundle_chatbox = TextBundle::from_sections((0..LOG_MAX_ROWS).map(|_|
|
||||||
TextSection::new("", style_console.clone()))
|
TextSection::new("", style_console.clone()))
|
||||||
).with_style(Style {
|
).with_style(Style {
|
||||||
|
@ -243,7 +247,6 @@ fn setup(
|
||||||
..default()
|
..default()
|
||||||
}).with_text_justify(JustifyText::Right);
|
}).with_text_justify(JustifyText::Right);
|
||||||
commands.spawn((
|
commands.spawn((
|
||||||
ToggleableHudElement,
|
|
||||||
NodeBundle {
|
NodeBundle {
|
||||||
style: Style {
|
style: Style {
|
||||||
width: Val::Percent(50.0),
|
width: Val::Percent(50.0),
|
||||||
|
@ -253,7 +256,6 @@ fn setup(
|
||||||
right: Val::VMin(3.0),
|
right: Val::VMin(3.0),
|
||||||
..default()
|
..default()
|
||||||
},
|
},
|
||||||
visibility,
|
|
||||||
..default()
|
..default()
|
||||||
},
|
},
|
||||||
)).with_children(|parent| {
|
)).with_children(|parent| {
|
||||||
|
@ -420,6 +422,8 @@ fn update_hud(
|
||||||
|
|
||||||
// Target display
|
// Target display
|
||||||
let dist_scalar: f64;
|
let dist_scalar: f64;
|
||||||
|
let mut target_multiple = false;
|
||||||
|
let mut target_error = false;
|
||||||
if let Ok((IsClickable { distance: Some(dist), .. }, _, _)) = q_target.get_single() {
|
if let Ok((IsClickable { distance: Some(dist), .. }, _, _)) = q_target.get_single() {
|
||||||
dist_scalar = *dist;
|
dist_scalar = *dist;
|
||||||
}
|
}
|
||||||
|
@ -431,7 +435,12 @@ fn update_hud(
|
||||||
else if q_target.is_empty() {
|
else if q_target.is_empty() {
|
||||||
target = Some(DVec3::new(0.0, 0.0, 0.0));
|
target = Some(DVec3::new(0.0, 0.0, 0.0));
|
||||||
}
|
}
|
||||||
|
else if q_target.iter().len() > 1 {
|
||||||
|
target_multiple = true;
|
||||||
|
target = None;
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
|
target_error = true;
|
||||||
target = None;
|
target = None;
|
||||||
}
|
}
|
||||||
if let Some(target_pos) = target {
|
if let Some(target_pos) = target {
|
||||||
|
@ -456,7 +465,13 @@ fn update_hud(
|
||||||
let speed_readable = nature::readable_distance(speed);
|
let speed_readable = nature::readable_distance(speed);
|
||||||
text.sections[14].value = format!("\n{speed_readable}/s\n{gforce:.1}g{dev_speed}");
|
text.sections[14].value = format!("\n{speed_readable}/s\n{gforce:.1}g{dev_speed}");
|
||||||
|
|
||||||
if let Ok((clickable, _, target_v_maybe)) = q_target.get_single() {
|
if target_multiple {
|
||||||
|
text.sections[15].value = "\n\nERROR: MULTIPLE TARGETS".to_string();
|
||||||
|
}
|
||||||
|
else if target_error {
|
||||||
|
text.sections[15].value = "\n\nERROR: FAILED TO AQUIRE TARGET".to_string();
|
||||||
|
}
|
||||||
|
else if let Ok((clickable, _, target_v_maybe)) = q_target.get_single() {
|
||||||
let distance = if dist_scalar.is_nan() {
|
let distance = if dist_scalar.is_nan() {
|
||||||
"UNKNOWN".to_string()
|
"UNKNOWN".to_string()
|
||||||
} else if dist_scalar != 0.0 {
|
} else if dist_scalar != 0.0 {
|
||||||
|
@ -503,7 +518,16 @@ fn update_hud(
|
||||||
let mut row = 0;
|
let mut row = 0;
|
||||||
|
|
||||||
// Chat Log and System Log
|
// Chat Log and System Log
|
||||||
|
let logfilter = if settings.hud_active {
|
||||||
|
|_msg: &&Message| { true }
|
||||||
|
} else {
|
||||||
|
|msg: &&Message| { match msg.level {
|
||||||
|
LogLevel::Always => true,
|
||||||
|
_ => false
|
||||||
|
}}
|
||||||
|
};
|
||||||
let messages: Vec<&Message> = log.logs.iter()
|
let messages: Vec<&Message> = log.logs.iter()
|
||||||
|
.filter(logfilter)
|
||||||
.rev()
|
.rev()
|
||||||
.take(LOG_MAX_ROWS)
|
.take(LOG_MAX_ROWS)
|
||||||
.collect();
|
.collect();
|
||||||
|
@ -511,14 +535,14 @@ fn update_hud(
|
||||||
for msg in &messages {
|
for msg in &messages {
|
||||||
chat.sections[row].value = msg.format();
|
chat.sections[row].value = msg.format();
|
||||||
let freshness = msg.get_freshness();
|
let freshness = msg.get_freshness();
|
||||||
let clr: f32 = (freshness.powf(1.5) as f32).clamp(0.1, 1.0);
|
let opacity: f32 = (freshness.powf(1.5) as f32).clamp(0.0, 1.0);
|
||||||
freshest_line = freshest_line.max(freshness);
|
freshest_line = freshest_line.max(freshness);
|
||||||
chat.sections[row].style.color = match msg.level {
|
chat.sections[row].style.color = match msg.level {
|
||||||
LogLevel::Warning => settings.hud_color_console_warn,
|
LogLevel::Warning => settings.hud_color_console_warn,
|
||||||
LogLevel::Info => settings.hud_color_console_system,
|
LogLevel::Info => settings.hud_color_console_system,
|
||||||
_ => settings.hud_color_console,
|
_ => settings.hud_color_console,
|
||||||
};
|
};
|
||||||
chat.sections[row].style.color.set_a(clr);
|
chat.sections[row].style.color.set_a(opacity);
|
||||||
row += 1;
|
row += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -591,6 +615,7 @@ fn handle_input(
|
||||||
keyboard_input: Res<ButtonInput<KeyCode>>,
|
keyboard_input: Res<ButtonInput<KeyCode>>,
|
||||||
mouse_input: Res<ButtonInput<MouseButton>>,
|
mouse_input: Res<ButtonInput<MouseButton>>,
|
||||||
mut settings: ResMut<var::Settings>,
|
mut settings: ResMut<var::Settings>,
|
||||||
|
mut log: ResMut<Log>,
|
||||||
mut q_hud: Query<(&mut Visibility, Option<&OnlyHideWhenTogglingHud>), With<ToggleableHudElement>>,
|
mut q_hud: Query<(&mut Visibility, Option<&OnlyHideWhenTogglingHud>), With<ToggleableHudElement>>,
|
||||||
mut ew_sfx: EventWriter<audio::PlaySfxEvent>,
|
mut ew_sfx: EventWriter<audio::PlaySfxEvent>,
|
||||||
mut ew_togglemusic: EventWriter<audio::ToggleMusicEvent>,
|
mut ew_togglemusic: EventWriter<audio::ToggleMusicEvent>,
|
||||||
|
@ -599,6 +624,11 @@ fn handle_input(
|
||||||
q_objects: Query<(Entity, &Transform), (With<IsClickable>, Without<IsTargeted>, Without<actor::PlayerDrivesThis>, Without<actor::Player>)>,
|
q_objects: Query<(Entity, &Transform), (With<IsClickable>, Without<IsTargeted>, Without<actor::PlayerDrivesThis>, Without<actor::Player>)>,
|
||||||
q_camera: Query<&Transform, With<Camera>>,
|
q_camera: Query<&Transform, With<Camera>>,
|
||||||
) {
|
) {
|
||||||
|
if keyboard_input.just_pressed(settings.key_help) {
|
||||||
|
for line in include_str!("data/keybindings.in").trim().split("\n") {
|
||||||
|
log.add(line.to_string(), "".to_string(), LogLevel::Always);
|
||||||
|
}
|
||||||
|
}
|
||||||
if keyboard_input.just_pressed(settings.key_togglehud) {
|
if keyboard_input.just_pressed(settings.key_togglehud) {
|
||||||
if settings.hud_active {
|
if settings.hud_active {
|
||||||
for (mut hudelement_visibility, _) in q_hud.iter_mut() {
|
for (mut hudelement_visibility, _) in q_hud.iter_mut() {
|
||||||
|
|
22
src/main.rs
22
src/main.rs
|
@ -5,6 +5,7 @@ mod chat;
|
||||||
mod commands;
|
mod commands;
|
||||||
mod effects;
|
mod effects;
|
||||||
mod hud;
|
mod hud;
|
||||||
|
mod shading;
|
||||||
mod var;
|
mod var;
|
||||||
mod world;
|
mod world;
|
||||||
|
|
||||||
|
@ -15,6 +16,7 @@ use bevy::window::{Window, WindowMode, PrimaryWindow, CursorGrabMode};
|
||||||
use bevy::diagnostic::FrameTimeDiagnosticsPlugin;
|
use bevy::diagnostic::FrameTimeDiagnosticsPlugin;
|
||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
use bevy_embedded_assets::{EmbeddedAssetPlugin, PluginMode};
|
use bevy_embedded_assets::{EmbeddedAssetPlugin, PluginMode};
|
||||||
|
use bevy::pbr::ExtendedMaterial;
|
||||||
use std::env;
|
use std::env;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
@ -46,6 +48,7 @@ impl Plugin for OutFlyPlugin {
|
||||||
fn build(&self, app: &mut App) {
|
fn build(&self, app: &mut App) {
|
||||||
app.add_systems(Startup, setup);
|
app.add_systems(Startup, setup);
|
||||||
app.add_systems(Update, handle_input);
|
app.add_systems(Update, handle_input);
|
||||||
|
app.add_systems(Update, debug);
|
||||||
app.insert_resource(var::Settings::default());
|
app.insert_resource(var::Settings::default());
|
||||||
app.insert_resource(var::GameVars::default());
|
app.insert_resource(var::GameVars::default());
|
||||||
app.add_plugins((
|
app.add_plugins((
|
||||||
|
@ -59,6 +62,7 @@ impl Plugin for OutFlyPlugin {
|
||||||
commands::CommandsPlugin,
|
commands::CommandsPlugin,
|
||||||
effects::EffectsPlugin,
|
effects::EffectsPlugin,
|
||||||
hud::HudPlugin,
|
hud::HudPlugin,
|
||||||
|
shading::ShadingPlugin,
|
||||||
world::WorldPlugin,
|
world::WorldPlugin,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
@ -94,3 +98,21 @@ fn handle_input(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn debug(
|
||||||
|
settings: Res<var::Settings>,
|
||||||
|
keyboard_input: Res<ButtonInput<KeyCode>>,
|
||||||
|
mut commands: Commands,
|
||||||
|
mut extended_materials: ResMut<Assets<ExtendedMaterial<StandardMaterial, shading::AsteroidSurface>>>,
|
||||||
|
materials: Query<(Entity, Option<&Name>, &Handle<Mesh>)>,
|
||||||
|
) {
|
||||||
|
if settings.dev_mode && keyboard_input.pressed(KeyCode::KeyP) {
|
||||||
|
for (entity, _name, mesh) in &materials {
|
||||||
|
dbg!(mesh);
|
||||||
|
let mut entity = commands.entity(entity);
|
||||||
|
entity.remove::<Handle<StandardMaterial>>();
|
||||||
|
let material = extended_materials.add(shading::AsteroidSurface::material());
|
||||||
|
entity.insert(material);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
77
src/shading.rs
Normal file
77
src/shading.rs
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
use bevy::prelude::*;
|
||||||
|
use bevy::render::render_resource::{AsBindGroup, ShaderRef};
|
||||||
|
use bevy::pbr::{ExtendedMaterial, MaterialExtension, OpaqueRendererMethod};
|
||||||
|
|
||||||
|
pub struct ShadingPlugin;
|
||||||
|
impl Plugin for ShadingPlugin {
|
||||||
|
fn build(&self, app: &mut App) {
|
||||||
|
app.add_plugins(MaterialPlugin::<JupitersRing>::default());
|
||||||
|
app.add_plugins(MaterialPlugin::<SkyBox>::default());
|
||||||
|
app.add_plugins(MaterialPlugin::<ExtendedMaterial<StandardMaterial, AsteroidSurface, >>::default());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Jupiter's Ring
|
||||||
|
#[derive(Asset, TypePath, AsBindGroup, Debug, Clone)]
|
||||||
|
pub struct JupitersRing {
|
||||||
|
pub alpha_mode: AlphaMode,
|
||||||
|
#[uniform(0)]
|
||||||
|
pub ring_radius: f32,
|
||||||
|
#[uniform(1)]
|
||||||
|
pub jupiter_radius: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Material for JupitersRing {
|
||||||
|
fn fragment_shader() -> ShaderRef {
|
||||||
|
"shaders/jupiters_rings.wgsl".into()
|
||||||
|
}
|
||||||
|
fn alpha_mode(&self) -> AlphaMode {
|
||||||
|
self.alpha_mode
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sky Box
|
||||||
|
#[derive(Asset, TypePath, AsBindGroup, Debug, Clone)]
|
||||||
|
pub struct SkyBox {}
|
||||||
|
impl Material for SkyBox {
|
||||||
|
fn fragment_shader() -> ShaderRef {
|
||||||
|
"shaders/skybox.wgsl".into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Asteroid Surface
|
||||||
|
#[derive(Asset, Reflect, AsBindGroup, Debug, Clone)]
|
||||||
|
pub struct AsteroidSurface {
|
||||||
|
#[uniform(100)]
|
||||||
|
quantize_steps: u32
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MaterialExtension for AsteroidSurface {
|
||||||
|
fn fragment_shader() -> ShaderRef {
|
||||||
|
"shaders/material_asteroid.wgsl".into()
|
||||||
|
}
|
||||||
|
fn deferred_fragment_shader() -> ShaderRef {
|
||||||
|
"shaders/material_asteroid.wgsl".into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AsteroidSurface {
|
||||||
|
pub fn material() -> ExtendedMaterial<StandardMaterial, AsteroidSurface> {
|
||||||
|
ExtendedMaterial {
|
||||||
|
base: StandardMaterial {
|
||||||
|
base_color: Color::rgb(0.29, 0.255, 0.208),
|
||||||
|
perceptual_roughness: 1.0,
|
||||||
|
opaque_render_method: OpaqueRendererMethod::Auto,
|
||||||
|
..default()
|
||||||
|
},
|
||||||
|
extension: Self::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Default for AsteroidSurface {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
quantize_steps: 3,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -49,6 +49,7 @@ pub struct Settings {
|
||||||
pub key_exit: KeyCode,
|
pub key_exit: KeyCode,
|
||||||
pub key_restart: KeyCode,
|
pub key_restart: KeyCode,
|
||||||
pub key_fullscreen: KeyCode,
|
pub key_fullscreen: KeyCode,
|
||||||
|
pub key_help: KeyCode,
|
||||||
pub key_forward: KeyCode,
|
pub key_forward: KeyCode,
|
||||||
pub key_back: KeyCode,
|
pub key_back: KeyCode,
|
||||||
pub key_left: KeyCode,
|
pub key_left: KeyCode,
|
||||||
|
@ -126,11 +127,11 @@ impl Default for Settings {
|
||||||
font_size_conversations: 32.0,
|
font_size_conversations: 32.0,
|
||||||
font_size_choices: 28.0,
|
font_size_choices: 28.0,
|
||||||
font_size_console: 20.0,
|
font_size_console: 20.0,
|
||||||
hud_color: Color::rgb(0.2, 0.5, 0.2),
|
hud_color: Color::rgb(0.1, 0.5, 0.1),
|
||||||
hud_color_console: Color::rgb(0.2, 0.5, 0.2),
|
hud_color_console: Color::rgb(0.1, 0.5, 0.1),
|
||||||
hud_color_console_warn: Color::rgb(1.0, 0.3, 0.3),
|
hud_color_console_warn: Color::rgb(1.0, 0.3, 0.3),
|
||||||
hud_color_console_system: Color::rgb(0.5, 0.5, 0.5),
|
hud_color_console_system: Color::rgb(0.5, 0.5, 0.5),
|
||||||
hud_color_alert: Color::rgb(0.7, 0.3, 0.3),
|
hud_color_alert: Color::rgb(0.6, 0.094, 0.322),
|
||||||
hud_color_subtitles: Color::rgb(0.8, 0.8, 0.8),
|
hud_color_subtitles: Color::rgb(0.8, 0.8, 0.8),
|
||||||
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 },
|
||||||
|
@ -144,6 +145,7 @@ impl Default for Settings {
|
||||||
key_exit: KeyCode::Escape,
|
key_exit: KeyCode::Escape,
|
||||||
key_restart: KeyCode::F7,
|
key_restart: KeyCode::F7,
|
||||||
key_fullscreen: KeyCode::F11,
|
key_fullscreen: KeyCode::F11,
|
||||||
|
key_help: KeyCode::F1,
|
||||||
key_forward: KeyCode::KeyW,
|
key_forward: KeyCode::KeyW,
|
||||||
key_back: KeyCode::KeyS,
|
key_back: KeyCode::KeyS,
|
||||||
key_left: KeyCode::KeyA,
|
key_left: KeyCode::KeyA,
|
||||||
|
|
118
src/world.rs
118
src/world.rs
|
@ -1,10 +1,10 @@
|
||||||
use crate::{actor, audio, hud, nature, var};
|
use crate::{actor, audio, hud, nature, shading, var};
|
||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
use bevy::render::render_resource::{AsBindGroup, ShaderRef};
|
|
||||||
use bevy::math::{DVec3, I64Vec3};
|
use bevy::math::{DVec3, I64Vec3};
|
||||||
use bevy::scene::{InstanceId, SceneInstance};
|
use bevy::scene::{InstanceId, SceneInstance};
|
||||||
|
use bevy::render::mesh::Indices;
|
||||||
use bevy_xpbd_3d::prelude::*;
|
use bevy_xpbd_3d::prelude::*;
|
||||||
use bevy_xpbd_3d::plugins::sync::SyncConfig;
|
use bevy_xpbd_3d::plugins::sync;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::f32::consts::PI;
|
use std::f32::consts::PI;
|
||||||
use fastrand;
|
use fastrand;
|
||||||
|
@ -23,10 +23,11 @@ const ASSET_ASTEROID1: &str = "models/asteroid.glb#Scene0";
|
||||||
const ASSET_ASTEROID2: &str = "models/asteroid2.glb#Scene0";
|
const ASSET_ASTEROID2: &str = "models/asteroid2.glb#Scene0";
|
||||||
pub fn asset_name_to_path(name: &str) -> &'static str {
|
pub fn asset_name_to_path(name: &str) -> &'static str {
|
||||||
match name {
|
match name {
|
||||||
"suit" => "models/suit.glb#Scene0",
|
"suit" => "models/suit_with_collider.glb#Scene0",
|
||||||
"suit_ar_chefhat" => "models/suit_ar_chefhat.glb#Scene0",
|
"suit_ar_chefhat" => "models/suit_ar_chefhat.glb#Scene0",
|
||||||
"asteroid1" => ASSET_ASTEROID1,
|
"asteroid1" => ASSET_ASTEROID1,
|
||||||
"asteroid2" => ASSET_ASTEROID2,
|
"asteroid2" => ASSET_ASTEROID2,
|
||||||
|
"asteroid_lum" => "models/asteroid_lum.glb#Scene0",
|
||||||
"moonlet" => "models/moonlet.glb#Scene0",
|
"moonlet" => "models/moonlet.glb#Scene0",
|
||||||
"monolith" => "models/monolith_neon.glb#Scene0",
|
"monolith" => "models/monolith_neon.glb#Scene0",
|
||||||
"lightorb" => "models/lightorb.glb#Scene0",
|
"lightorb" => "models/lightorb.glb#Scene0",
|
||||||
|
@ -39,6 +40,7 @@ pub fn asset_name_to_path(name: &str) -> &'static str {
|
||||||
"selectagon" => "models/selectagon.glb#Scene0",
|
"selectagon" => "models/selectagon.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",
|
||||||
_ => "models/error.glb#Scene0",
|
_ => "models/error.glb#Scene0",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -51,7 +53,6 @@ impl Plugin for WorldPlugin {
|
||||||
app.add_systems(PostUpdate, handle_despawn);
|
app.add_systems(PostUpdate, handle_despawn);
|
||||||
app.add_systems(Update, spawn_despawn_asteroids);
|
app.add_systems(Update, spawn_despawn_asteroids);
|
||||||
app.add_plugins(PhysicsPlugins::default());
|
app.add_plugins(PhysicsPlugins::default());
|
||||||
app.add_plugins(MaterialPlugin::<RingMaterial>::default());
|
|
||||||
//app.add_plugins(PhysicsDebugPlugin::default());
|
//app.add_plugins(PhysicsDebugPlugin::default());
|
||||||
app.insert_resource(Gravity(DVec3::splat(0.0)));
|
app.insert_resource(Gravity(DVec3::splat(0.0)));
|
||||||
app.insert_resource(AsteroidUpdateTimer(
|
app.insert_resource(AsteroidUpdateTimer(
|
||||||
|
@ -62,12 +63,14 @@ impl Plugin for WorldPlugin {
|
||||||
|
|
||||||
if CENTER_WORLD_ON_PLAYER {
|
if CENTER_WORLD_ON_PLAYER {
|
||||||
// Disable bevy_xpbd's position->transform sync function
|
// Disable bevy_xpbd's position->transform sync function
|
||||||
app.insert_resource(SyncConfig {
|
app.insert_resource(sync::SyncConfig {
|
||||||
position_to_transform: false,
|
position_to_transform: true,
|
||||||
transform_to_position: false,
|
transform_to_position: false,
|
||||||
});
|
});
|
||||||
// Add own position->transform sync function
|
// Add own position->transform sync function
|
||||||
app.add_systems(PreUpdate, position_to_transform);
|
app.add_systems(PostUpdate, position_to_transform
|
||||||
|
.after(sync::position_to_transform)
|
||||||
|
.in_set(sync::SyncSet::PositionToTransform));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -93,24 +96,6 @@ pub struct DespawnEvent {
|
||||||
origin: I64Vec3,
|
origin: I64Vec3,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Asset, TypePath, AsBindGroup, Debug, Clone)]
|
|
||||||
pub struct RingMaterial {
|
|
||||||
alpha_mode: AlphaMode,
|
|
||||||
#[uniform(0)]
|
|
||||||
ring_radius: f32,
|
|
||||||
#[uniform(1)]
|
|
||||||
jupiter_radius: f32,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Material for RingMaterial {
|
|
||||||
fn fragment_shader() -> ShaderRef {
|
|
||||||
"shaders/jupiters_rings.wgsl".into()
|
|
||||||
}
|
|
||||||
fn alpha_mode(&self) -> AlphaMode {
|
|
||||||
self.alpha_mode
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Component)]
|
#[derive(Component)]
|
||||||
pub struct Star;
|
pub struct Star;
|
||||||
|
|
||||||
|
@ -118,7 +103,8 @@ 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_custom: ResMut<Assets<RingMaterial>>,
|
mut materials_jupiter: ResMut<Assets<shading::JupitersRing>>,
|
||||||
|
mut materials_skybox: ResMut<Assets<shading::SkyBox>>,
|
||||||
asset_server: Res<AssetServer>,
|
asset_server: Res<AssetServer>,
|
||||||
) {
|
) {
|
||||||
// Load assets
|
// Load assets
|
||||||
|
@ -195,13 +181,34 @@ pub fn setup(
|
||||||
}
|
}
|
||||||
info!("Generated {starcount} stars");
|
info!("Generated {starcount} stars");
|
||||||
|
|
||||||
|
// Add shaded skybox
|
||||||
|
//let mut mesh = Mesh::from(Sphere::new(1e9).mesh().uv(50, 50));
|
||||||
|
let mut mesh = Mesh::from(Sphere::new(1e10).mesh().uv(5, 5));
|
||||||
|
//let mut mesh = Mesh::from(Cuboid::from_size(Vec3::splat(2e10)));
|
||||||
|
if let Some(Indices::U32(indices)) = mesh.indices_mut() {
|
||||||
|
// Reverse the order of each triangle to avoid backface culling
|
||||||
|
for slice in indices.chunks_mut(3) {
|
||||||
|
slice.reverse();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
commands.spawn((
|
||||||
|
MaterialMeshBundle {
|
||||||
|
mesh: meshes.add(mesh),
|
||||||
|
material: materials_skybox.add(shading::SkyBox {}),
|
||||||
|
transform: Transform::from_translation(Vec3::new(0.0, 0.0, 0.0)),
|
||||||
|
..default()
|
||||||
|
},
|
||||||
|
Position::from_xyz(0.0, 0.0, 0.0),
|
||||||
|
Rotation::from(Quat::IDENTITY),
|
||||||
|
));
|
||||||
|
|
||||||
// Add shaded ring
|
// Add shaded ring
|
||||||
let ring_radius = 229_000_000.0;
|
let ring_radius = 229_000_000.0;
|
||||||
let jupiter_radius = 71_492_000.0;
|
let jupiter_radius = 71_492_000.0;
|
||||||
commands.spawn((
|
commands.spawn((
|
||||||
MaterialMeshBundle {
|
MaterialMeshBundle {
|
||||||
mesh: meshes.add(Mesh::from(Cylinder::new(ring_radius, 1.0))),
|
mesh: meshes.add(Mesh::from(Cylinder::new(ring_radius, 1.0))),
|
||||||
material: materials_custom.add(RingMaterial {
|
material: materials_jupiter.add(shading::JupitersRing {
|
||||||
alpha_mode: AlphaMode::Blend,
|
alpha_mode: AlphaMode::Blend,
|
||||||
ring_radius: ring_radius,
|
ring_radius: ring_radius,
|
||||||
jupiter_radius: jupiter_radius,
|
jupiter_radius: jupiter_radius,
|
||||||
|
@ -466,58 +473,21 @@ fn handle_cheats(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// A variant of bevy_xpbd_3d::plugins::position_to_transform that adjusts
|
// An extension of bevy_xpbd_3d::plugins::position_to_transform that adjusts
|
||||||
// the rendering position to center entities at the player camera.
|
// the rendering position to center entities at the player camera.
|
||||||
// This avoids rendering glitches when very far away from the origin.
|
// This avoids rendering glitches when very far away from the origin.
|
||||||
pub fn position_to_transform(
|
pub fn position_to_transform(
|
||||||
q_player: Query<&Position, With<actor::PlayerCamera>>,
|
q_player: Query<&Position, With<actor::PlayerCamera>>,
|
||||||
mut q_trans: Query<(&'static mut Transform, &'static Position, &'static Rotation, Option<&'static Parent>)>,
|
mut q_trans: Query<(&'static mut Transform, &'static Position, &'static Rotation), Without<Parent>>,
|
||||||
parents: Query<(&'static GlobalTransform, Option<&'static Position>, Option<&'static Rotation>), With<Children>>,
|
|
||||||
) {
|
) {
|
||||||
if let Ok(player_pos) = q_player.get_single() {
|
if let Ok(player_pos) = q_player.get_single() {
|
||||||
for (mut transform, pos, rot, parent) in &mut q_trans {
|
for (mut transform, pos, rot) in &mut q_trans {
|
||||||
if let Some(parent) = parent {
|
transform.translation = Vec3::new(
|
||||||
if let Ok((parent_transform, parent_pos, parent_rot)) = parents.get(**parent) {
|
(pos.x - player_pos.x) as f32,
|
||||||
// Compute the global transform of the parent using its Position and Rotation
|
(pos.y - player_pos.y) as f32,
|
||||||
let parent_transform = parent_transform.compute_transform();
|
(pos.z - player_pos.z) as f32,
|
||||||
let parent_pos = parent_pos.map_or(parent_transform.translation, |pos| {
|
);
|
||||||
pos.as_vec3()
|
transform.rotation = rot.as_quat();
|
||||||
// NOTE: I commented out this because it turns a vec3 to a vec4,
|
|
||||||
// and I don't understand why bevy_xpbd would do that.
|
|
||||||
//.extend(parent_transform.translation.z)
|
|
||||||
});
|
|
||||||
let parent_rot = parent_rot.map_or(parent_transform.rotation, |rot| {
|
|
||||||
rot.as_quat()
|
|
||||||
});
|
|
||||||
let parent_scale = parent_transform.scale;
|
|
||||||
let parent_transform = Transform::from_translation(parent_pos)
|
|
||||||
.with_rotation(parent_rot)
|
|
||||||
.with_scale(parent_scale);
|
|
||||||
|
|
||||||
// The new local transform of the child body,
|
|
||||||
// computed from the its global transform and its parents global transform
|
|
||||||
let new_transform = GlobalTransform::from(
|
|
||||||
Transform::from_translation(
|
|
||||||
pos.as_vec3()
|
|
||||||
// NOTE: I commented out this because it turns a vec3 to a vec4,
|
|
||||||
// and I don't understand why bevy_xpbd would do that.
|
|
||||||
//.extend(parent_pos.z + transform.translation.z * parent_scale.z),
|
|
||||||
)
|
|
||||||
.with_rotation(rot.as_quat()),
|
|
||||||
)
|
|
||||||
.reparented_to(&GlobalTransform::from(parent_transform));
|
|
||||||
|
|
||||||
transform.translation = new_transform.translation;
|
|
||||||
transform.rotation = new_transform.rotation;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
transform.translation = Vec3::new(
|
|
||||||
(pos.x - player_pos.x) as f32,
|
|
||||||
(pos.y - player_pos.y) as f32,
|
|
||||||
(pos.z - player_pos.z) as f32,
|
|
||||||
);
|
|
||||||
transform.rotation = rot.as_quat();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue