Compare commits
44 commits
838b8b7fd6
...
73410efc09
Author | SHA1 | Date | |
---|---|---|---|
yuni | 73410efc09 | ||
yuni | e7df73d4fc | ||
yuni | 9c4167f6e9 | ||
yuni | 2ecb976b14 | ||
yuni | 8fa7859568 | ||
yuni | 29f0850874 | ||
yuni | ce65022905 | ||
yuni | 7f55ca7d80 | ||
yuni | 08f88f7eeb | ||
yuni | 6bf2596649 | ||
yuni | 191d918e4f | ||
yuni | 228380b9f4 | ||
yuni | c9adeeb94f | ||
yuni | 44f0770226 | ||
yuni | bc9ff6b7a6 | ||
yuni | f118384661 | ||
yuni | 68f274cb90 | ||
yuni | a1910c4075 | ||
yuni | a12ffac841 | ||
yuni | dff3652c37 | ||
yuni | a52773f15d | ||
yuni | 8c8b9e0b43 | ||
yuni | c1e76d09a9 | ||
yuni | 267ffc105c | ||
yuni | 6267be23cd | ||
yuni | 2d2be6bd7e | ||
yuni | bf87866244 | ||
yuni | e1d48c72a3 | ||
yuni | 8e987f6d22 | ||
yuni | 556f097193 | ||
yuni | 00e4fb4957 | ||
yuni | b9bce22ead | ||
yuni | 7d2fc6224a | ||
yuni | 7b21c2b820 | ||
yuni | 38a8f5421c | ||
yuni | 1da7ad151f | ||
yuni | 15592b837e | ||
yuni | fad7347cd9 | ||
yuni | 634a13fcf9 | ||
yuni | 0687952258 | ||
yuni | 03a5cd0831 | ||
yuni | 9d8d28937f | ||
yuni | 1adb56c0e2 | ||
yuni | 39d8eefa17 |
|
@ -1,3 +1,15 @@
|
|||
```
|
||||
▄████████▄ + ███ + ▄█████████ ███ +
|
||||
███▀ ▀███ + + ███ ███▀ + ███ + +
|
||||
███ + ███ ███ ███ █████████ ███ ███ ███ ███
|
||||
███ +███ ███ ███ ███ ███▐██████ ███ ███ ███
|
||||
███ + ███ ███+ ███ +███ ███ + ███ ███ + ███
|
||||
███▄ ▄███ ███▄ ███ ███ + ███ + ███ ███▄ ███
|
||||
▀████████▀ + ▀███████ ███▄ ███▄ ▀████ ▀███████
|
||||
+ + + ███
|
||||
+ ▀████████████████████████████████████████████████████▀
|
||||
```
|
||||
|
||||
# Developer Commentary
|
||||
## Clippy Convenience Companion
|
||||
|
||||
|
|
13
Cargo.toml
13
Cargo.toml
|
@ -1,3 +1,13 @@
|
|||
# ▄████████▄ + ███ + ▄█████████ ███ +
|
||||
# ███▀ ▀███ + + ███ ███▀ + ███ + +
|
||||
# ███ + ███ ███ ███ █████████ ███ ███ ███ ███
|
||||
# ███ +███ ███ ███ ███ ███▐██████ ███ ███ ███
|
||||
# ███ + ███ ███+ ███ +███ ███ + ███ ███ + ███
|
||||
# ███▄ ▄███ ███▄ ███ ███ + ███ + ███ ███▄ ███
|
||||
# ▀████████▀ + ▀███████ ███▄ ███▄ ▀████ ▀███████
|
||||
# + + + ███
|
||||
# + ▀████████████████████████████████████████████████████▀
|
||||
|
||||
[package]
|
||||
name = "outfly"
|
||||
version = "0.7.3"
|
||||
|
@ -14,7 +24,7 @@ build = "build/build.rs"
|
|||
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", "tonemapping_luts", "vorbis"]}
|
||||
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 = { version = "0.10.2", optional = true }
|
||||
fastrand = "2.0"
|
||||
serde = "1.0"
|
||||
serde_yaml = "0.9"
|
||||
|
@ -28,6 +38,7 @@ dev = ["bevy/dynamic_linking", "bevy/file_watcher"]
|
|||
wasm = ["bevy/webgl2"]
|
||||
x11 = ["bevy/x11"]
|
||||
wayland = ["bevy/wayland"]
|
||||
embed_assets = ["dep:bevy_embedded_assets"]
|
||||
|
||||
[profile.dev]
|
||||
opt-level = 1
|
||||
|
|
89
README.md
89
README.md
|
@ -1,6 +1,20 @@
|
|||
# OutFly
|
||||
```
|
||||
▄████████▄ + ███ + ▄█████████ ███ +
|
||||
███▀ ▀███ + + ███ ███▀ + ███ + +
|
||||
███ + ███ ███ ███ █████████ ███ ███ ███ ███
|
||||
███ +███ ███ ███ ███ ███▐██████ ███ ███ ███
|
||||
███ + ███ ███+ ███ +███ ███ + ███ ███ + ███
|
||||
███▄ ▄███ ███▄ ███ ███ + ███ + ███ ███▄ ███
|
||||
▀████████▀ + ▀███████ ███▄ ███▄ ▀████ ▀███████
|
||||
+ + + ███
|
||||
+ ▀████████████████████████████████████████████████████▀
|
||||
```
|
||||
|
||||
![screenshot](doc/images/screenshot1.jpg)
|
||||
Chapters: [Features](#features) • [Controls](#controls) • [Running OutFly](#running-outfly) • [Building](#building) • [Changelog](#changelog) • [Credits](#credits)
|
||||
|
||||
Links: [Code](https://codeberg.org/hut/outfly) • [itch.io](https://yunicode.itch.io/outfly) • [Mastodon](https://mastodon.gamedev.place/@outfly) • [Chat](https://matrix.to/#/#outfly:pub.solar)
|
||||
|
||||
# OutFly
|
||||
|
||||
OutFly is an atmospheric, open world, 100% hard sci-fi 3D game that throws you into the [Rings of Jupiter](https://en.wikipedia.org/wiki/Rings_of_Jupiter) with a self-sufficient sportswear space suit that will take you anywhere.
|
||||
|
||||
|
@ -8,7 +22,9 @@ Imagine a blend of [Fallout](https://en.wikipedia.org/wiki/Fallout_%28series%29)
|
|||
|
||||
This game aims to respect the player as much as possible. It doesn't waste your time: Despite the vastness of space, nothing takes too long. Speed cheats are active by default, allowing you to visit places you normally couldn't, without passing out from the g-forces. There are no anxiety-causing features (apart of, maybe, space itself), no loading screens, nothing to micromanage, not even save games. You can plunge into the game any time you feel like it, and it's up to you whether you just want to soak in the beautiful scenery, engage with the survival mechanics [still in development], or dive into the game story [still in development]. And finally, it's not just DRM-free but completely open source, allowing you to tinker on any part of the game to your liking.
|
||||
|
||||
Key features:
|
||||
![screenshot](doc/images/screenshot3.jpg)
|
||||
|
||||
# Features
|
||||
|
||||
- Open source forever
|
||||
- Open world, realistic hard sci-fi, atmospheric, deadly
|
||||
|
@ -17,16 +33,7 @@ Key features:
|
|||
- Written in [Rust](https://www.rust-lang.org) with the [Bevy game engine](https://bevyengine.org)
|
||||
- Status: Early access, not much content
|
||||
|
||||
Links:
|
||||
|
||||
- [Source code](https://codeberg.org/hut/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)
|
||||
|
||||
![screenshot](doc/images/screenshot2.jpg)
|
||||
|
||||
# Key Bindings
|
||||
# Controls
|
||||
|
||||
- F1: Show key bindings
|
||||
- Space: Slow down (or match velocity)
|
||||
|
@ -34,19 +41,19 @@ Links:
|
|||
- R: Rotate (hold & move mouse)
|
||||
- E: Interact: Talk to people, enter vehicles
|
||||
- Q: Exit vehicle
|
||||
- F7: Restart game
|
||||
- JKULIO: Mouseless camera rotation
|
||||
- Augmented Reality: (toggle with Tab)
|
||||
- Left click: Target objects
|
||||
- Right click: Zoom
|
||||
- Settings
|
||||
- Tab: Toggle HUD/AR
|
||||
- F11: Toggle fullscreen
|
||||
- F: Toggle 3rd person view
|
||||
- M: Toggle map
|
||||
- F: Toggle 3rd person view
|
||||
- Y: Toggle rotation stabilizer
|
||||
- F4: Toggle music
|
||||
- F3: Toggle sound effects
|
||||
- F4: Toggle music
|
||||
- F7: Restart game
|
||||
- F11: Toggle fullscreen
|
||||
- Cheats
|
||||
- G: Toggle god mode / cheats
|
||||
- V/B: Impossible acceleration forward/backward
|
||||
|
@ -54,35 +61,45 @@ Links:
|
|||
- C: Impossibly instant stopping
|
||||
- X: Teleport to target
|
||||
|
||||
# System Requirements
|
||||
# Running OutFly
|
||||
## System Requirements
|
||||
|
||||
- Screen, keyboard
|
||||
- Operating System: Linux, Windows, MacOS
|
||||
- Ideally, a graphics card with Vulkan support
|
||||
- Screen/keyboard/mouse
|
||||
- Operating System: Linux, Windows, Mac
|
||||
- A graphics card with vulkan support
|
||||
|
||||
If your GPU does not support Vulkan, try rendering with OpenGL by setting the environment variable `WGPU_BACKEND` to `gl`, like:
|
||||
## Running on Linux
|
||||
|
||||
1. Download and unpack the latest release: https://codeberg.org/hut/outfly/releases
|
||||
2. Open a terminal and navigate to the directory where you unpacked outfly
|
||||
3. If you are on ArchLinux, type the following commands. For other distributions, replace "pacman -S" with the distro's command to install packages. Also, the packages may be called slightly differently.
|
||||
|
||||
```
|
||||
pacman -S glibc libcap gcc-libs alsa-lib systemd-libs
|
||||
./outfly
|
||||
```
|
||||
|
||||
If your graphics card does not support vulkan, try setting the environment variable `WGPU_BACKEND=gl`: (will result in poor performance)
|
||||
|
||||
```
|
||||
WGPU_BACKEND=gl ./outfly
|
||||
or
|
||||
WGPU_BACKEND=gl cargo run
|
||||
```
|
||||
|
||||
However, this may result in poor performance and visual glitches.
|
||||
|
||||
# Running OutFly
|
||||
|
||||
1. Download a release for your operating system at https://codeberg.org/hut/outfly/releases
|
||||
2. On Linux, you need the dependency packages: `glibc libcap gcc-libs alsa-lib systemd-libs`. These are the names for ArchLinux, they may differ on your distribution.
|
||||
3. Unpack and run the outfly/outfly.exe executable.
|
||||
1. On Windows, just double-click on outfly.exe
|
||||
2. On Linux, open the console and type this:
|
||||
Alternatively, you can also install OutFly as a package, if your distribution has one. This will place OutFly in your "start menu". As of writing, only an ArchLinux AUR package exists, which you can install with this command:
|
||||
|
||||
```
|
||||
cd [path-to-extracted-outfly-directory]
|
||||
./outfly
|
||||
yay -S outfly-git
|
||||
```
|
||||
|
||||
## Running on Windows
|
||||
|
||||
1. Download and unpack the latest release: https://codeberg.org/hut/outfly/releases
|
||||
2. Double-click on `OutFly.exe`
|
||||
|
||||
## Running on MacOS / Android / iOS
|
||||
|
||||
No releases for these operating systems exist yet. For MacOS, you can build OutFly yourself using the instructions below. Support for Android/iOS is planned for the future.
|
||||
|
||||
# Building
|
||||
|
||||
If there is no package for the version or operating system that you need, or if you wish to tinker on the game, you can also build outfly yourself.
|
||||
|
@ -221,7 +238,7 @@ python -m http.server -d wasm
|
|||
- v0.1.1: Better sky box and HUD
|
||||
- v0.1.0: First release with basic controls, HUD, sounds, skybox, sun
|
||||
|
||||
# Credits and License
|
||||
# Credits
|
||||
|
||||
- Source code: GPL Version 3.0
|
||||
- 3D models: Original art, placed under the Creative Commons CC0 License
|
||||
|
|
BIN
assets/models/point_of_interest.glb
Normal file
BIN
assets/models/point_of_interest.glb
Normal file
Binary file not shown.
Binary file not shown.
BIN
assets/models/suit_v1/collider.glb
Normal file
BIN
assets/models/suit_v1/collider.glb
Normal file
Binary file not shown.
BIN
assets/models/suit_v1/head.glb
Normal file
BIN
assets/models/suit_v1/head.glb
Normal file
Binary file not shown.
BIN
assets/models/suit_v1/lower_arm.glb
Normal file
BIN
assets/models/suit_v1/lower_arm.glb
Normal file
Binary file not shown.
BIN
assets/models/suit_v1/lower_leg.glb
Normal file
BIN
assets/models/suit_v1/lower_leg.glb
Normal file
Binary file not shown.
BIN
assets/models/suit_v1/upper_arm.glb
Normal file
BIN
assets/models/suit_v1/upper_arm.glb
Normal file
Binary file not shown.
BIN
assets/models/suit_v1/upper_leg.glb
Normal file
BIN
assets/models/suit_v1/upper_leg.glb
Normal file
Binary file not shown.
Binary file not shown.
|
@ -1,3 +1,4 @@
|
|||
// NOTE: This is currently not being used
|
||||
#import bevy_pbr::{
|
||||
mesh_view_bindings::globals,
|
||||
forward_io::VertexOutput,
|
||||
|
|
|
@ -1,3 +1,13 @@
|
|||
// ▄████████▄ + ███ + ▄█████████ ███ +
|
||||
// ███▀ ▀███ + + ███ ███▀ + ███ + +
|
||||
// ███ + ███ ███ ███ █████████ ███ ███ ███ ███
|
||||
// ███ +███ ███ ███ ███ ███▐██████ ███ ███ ███
|
||||
// ███ + ███ ███+ ███ +███ ███ + ███ ███ + ███
|
||||
// ███▄ ▄███ ███▄ ███ ███ + ███ + ███ ███▄ ███
|
||||
// ▀████████▀ + ▀███████ ███▄ ███▄ ▀████ ▀███████
|
||||
// + + + ███
|
||||
// + ▀████████████████████████████████████████████████████▀
|
||||
|
||||
fn main() {
|
||||
let target = std::env::var("TARGET").unwrap();
|
||||
if target.contains("windows") {
|
||||
|
|
|
@ -1,4 +1,14 @@
|
|||
#!/usr/bin/env python
|
||||
# ▄████████▄ + ███ + ▄█████████ ███ +
|
||||
# ███▀ ▀███ + + ███ ███▀ + ███ + +
|
||||
# ███ + ███ ███ ███ █████████ ███ ███ ███ ███
|
||||
# ███ +███ ███ ███ ███ ███▐██████ ███ ███ ███
|
||||
# ███ + ███ ███+ ███ +███ ███ + ███ ███ + ███
|
||||
# ███▄ ▄███ ███▄ ███ ███ + ███ + ███ ███▄ ███
|
||||
# ▀████████▀ + ▀███████ ███▄ ███▄ ▀████ ▀███████
|
||||
# + + + ███
|
||||
# + ▀████████████████████████████████████████████████████▀
|
||||
#
|
||||
# This script requires the following file in the extra/ directory:
|
||||
# https://github.com/astronexus/HYG-Database/blob/cbd21013d2bb89732b893be357a6f41836dbe614/hyg/CURRENT/hygdata_v41.csv
|
||||
|
||||
|
|
|
@ -1,4 +1,14 @@
|
|||
#!/bin/sh
|
||||
# ▄████████▄ + ███ + ▄█████████ ███ +
|
||||
# ███▀ ▀███ + + ███ ███▀ + ███ + +
|
||||
# ███ + ███ ███ ███ █████████ ███ ███ ███ ███
|
||||
# ███ +███ ███ ███ ███ ███▐██████ ███ ███ ███
|
||||
# ███ + ███ ███+ ███ +███ ███ + ███ ███ + ███
|
||||
# ███▄ ▄███ ███▄ ███ ███ + ███ + ███ ███▄ ███
|
||||
# ▀████████▀ + ▀███████ ███▄ ███▄ ▀████ ▀███████
|
||||
# + + + ███
|
||||
# + ▀████████████████████████████████████████████████████▀
|
||||
#
|
||||
# usage: run this script from the project root, like this: build/install.sh [rootdir]
|
||||
|
||||
rootdir="${1:-}"
|
||||
|
|
|
@ -1,3 +1,13 @@
|
|||
# ▄████████▄ + ███ + ▄█████████ ███ +
|
||||
# ███▀ ▀███ + + ███ ███▀ + ███ + +
|
||||
# ███ + ███ ███ ███ █████████ ███ ███ ███ ███
|
||||
# ███ +███ ███ ███ ███ ███▐██████ ███ ███ ███
|
||||
# ███ + ███ ███+ ███ +███ ███ + ███ ███ + ███
|
||||
# ███▄ ▄███ ███▄ ███ ███ + ███ + ███ ███▄ ███
|
||||
# ▀████████▀ + ▀███████ ███▄ ███▄ ▀████ ▀███████
|
||||
# + + + ███
|
||||
# + ▀████████████████████████████████████████████████████▀
|
||||
|
||||
[Desktop Entry]
|
||||
Type=Application
|
||||
Name=OutFly
|
||||
|
|
|
@ -1,12 +1,22 @@
|
|||
#!/bin/sh
|
||||
# ▄████████▄ + ███ + ▄█████████ ███ +
|
||||
# ███▀ ▀███ + + ███ ███▀ + ███ + +
|
||||
# ███ + ███ ███ ███ █████████ ███ ███ ███ ███
|
||||
# ███ +███ ███ ███ ███ ███▐██████ ███ ███ ███
|
||||
# ███ + ███ ███+ ███ +███ ███ + ███ ███ + ███
|
||||
# ███▄ ▄███ ███▄ ███ ███ + ███ + ███ ███▄ ███
|
||||
# ▀████████▀ + ▀███████ ███▄ ███▄ ▀████ ▀███████
|
||||
# + + + ███
|
||||
# + ▀████████████████████████████████████████████████████▀
|
||||
#
|
||||
# A script to package release binaries + README.md into zip files.
|
||||
# Usage: cd outfly; doc/scripts/pack.sh
|
||||
# Usage: cd outfly; build/pack.sh
|
||||
|
||||
set -e
|
||||
|
||||
if [ "$1" == "-b" ]; then
|
||||
cargo build --release --target=x86_64-unknown-linux-gnu --features "x11 wayland"
|
||||
cargo build --release --target=x86_64-pc-windows-gnu --no-default-features
|
||||
cargo build --release --target=x86_64-unknown-linux-gnu --no-default-features --features "x11 wayland embed_assets"
|
||||
cargo build --release --target=x86_64-pc-windows-gnu --no-default-features --features "embed_assets"
|
||||
fi
|
||||
|
||||
VERSION="$(sed -nr 's/^\s*version\s*=\s*"(.*)"\s*$/\1/p' Cargo.toml)"
|
||||
|
|
BIN
doc/images/screenshot3.jpg
Normal file
BIN
doc/images/screenshot3.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 36 KiB |
137
src/actor.rs
137
src/actor.rs
|
@ -1,10 +1,28 @@
|
|||
// ▄████████▄ + ███ + ▄█████████ ███ +
|
||||
// ███▀ ▀███ + + ███ ███▀ + ███ + +
|
||||
// ███ + ███ ███ ███ █████████ ███ ███ ███ ███
|
||||
// ███ +███ ███ ███ ███ ███▐██████ ███ ███ ███
|
||||
// ███ + ███ ███+ ███ +███ ███ + ███ ███ + ███
|
||||
// ███▄ ▄███ ███▄ ███ ███ + ███ + ███ ███▄ ███
|
||||
// ▀████████▀ + ▀███████ ███▄ ███▄ ▀████ ▀███████
|
||||
// + + + ███
|
||||
// + ▀████████████████████████████████████████████████████▀
|
||||
//
|
||||
// This module manages the internal states of individual characters,
|
||||
// such as their resources, the damage they receive, and interactions
|
||||
// between characters and with vehicles. It also handles cheats.
|
||||
//
|
||||
// This module should never handle any visual aspects directly.
|
||||
|
||||
use bevy::prelude::*;
|
||||
use bevy_xpbd_3d::prelude::*;
|
||||
use bevy_xpbd_3d::plugins::sync;
|
||||
use bevy::scene::SceneInstance;
|
||||
use bevy::math::DVec3;
|
||||
use crate::{actor, audio, camera, chat, commands, effects, hud, nature, var, world};
|
||||
use std::collections::HashMap;
|
||||
|
||||
const CENTER_WORLD_ON_PLAYER: bool = true;
|
||||
pub const ENGINE_SPEED_FACTOR: f32 = 30.0;
|
||||
const MAX_TRANSMISSION_DISTANCE: f32 = 100.0;
|
||||
const MAX_INTERACT_DISTANCE: f32 = 50.0;
|
||||
|
@ -25,6 +43,7 @@ impl Plugin for ActorPlugin {
|
|||
handle_input,
|
||||
handle_collisions,
|
||||
handle_damage,
|
||||
handle_cheats,
|
||||
));
|
||||
app.add_systems(PostUpdate, (
|
||||
handle_vehicle_enter_exit,
|
||||
|
@ -33,6 +52,18 @@ impl Plugin for ActorPlugin {
|
|||
app.add_event::<VehicleEnterExitEvent>();
|
||||
app.add_event::<PlayerDiesEvent>();
|
||||
app.insert_resource(Id2Pos(HashMap::new()));
|
||||
|
||||
if CENTER_WORLD_ON_PLAYER {
|
||||
// Disable bevy_xpbd's position->transform sync function
|
||||
app.insert_resource(sync::SyncConfig {
|
||||
position_to_transform: true,
|
||||
transform_to_position: false,
|
||||
});
|
||||
// Add own position->transform sync function
|
||||
app.add_systems(PostUpdate, position_to_transform
|
||||
.after(sync::position_to_transform)
|
||||
.in_set(sync::SyncSet::PositionToTransform));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -538,3 +569,109 @@ fn update_id2pos(
|
|||
id2pos.0.insert(id.0.clone(), pos.0);
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_cheats(
|
||||
key_input: Res<ButtonInput<KeyCode>>,
|
||||
mut q_player: Query<(&Transform, &mut Position, &mut LinearVelocity), With<actor::PlayerCamera>>,
|
||||
mut q_life: Query<(&mut actor::LifeForm, &mut actor::ExperiencesGForce), With<actor::Player>>,
|
||||
q_target: Query<(&Transform, &Position, &LinearVelocity), (With<hud::IsTargeted>, Without<actor::PlayerCamera>)>,
|
||||
mut ew_playerdies: EventWriter<actor::PlayerDiesEvent>,
|
||||
mut settings: ResMut<var::Settings>,
|
||||
id2pos: Res<actor::Id2Pos>,
|
||||
mut ew_sfx: EventWriter<audio::PlaySfxEvent>,
|
||||
) {
|
||||
if q_player.is_empty() || q_life.is_empty() {
|
||||
return;
|
||||
}
|
||||
let (trans, mut pos, mut v) = q_player.get_single_mut().unwrap();
|
||||
let (mut lifeform, mut gforce) = q_life.get_single_mut().unwrap();
|
||||
let boost = if key_input.pressed(KeyCode::ShiftLeft) {
|
||||
1e6
|
||||
} else {
|
||||
1e3
|
||||
};
|
||||
if key_input.just_pressed(settings.key_cheat_god_mode) {
|
||||
settings.god_mode ^= true;
|
||||
if settings.god_mode {
|
||||
ew_sfx.send(audio::PlaySfxEvent(audio::Sfx::EnterVehicle));
|
||||
}
|
||||
}
|
||||
if !settings.god_mode && !settings.dev_mode {
|
||||
return;
|
||||
}
|
||||
|
||||
if key_input.just_pressed(settings.key_cheat_stop) {
|
||||
gforce.ignore_gforce_seconds = 1.0;
|
||||
v.0 = DVec3::ZERO;
|
||||
}
|
||||
if key_input.pressed(settings.key_cheat_speed) {
|
||||
gforce.ignore_gforce_seconds = 1.0;
|
||||
v.0 += DVec3::from(trans.rotation * Vec3::new(0.0, 0.0, boost));
|
||||
}
|
||||
if key_input.pressed(settings.key_cheat_speed_backward) {
|
||||
gforce.ignore_gforce_seconds = 1.0;
|
||||
v.0 += DVec3::from(trans.rotation * Vec3::new(0.0, 0.0, -boost));
|
||||
}
|
||||
if key_input.just_pressed(settings.key_cheat_teleport) {
|
||||
if let Ok((transform, target_pos, target_v)) = q_target.get_single() {
|
||||
let offset: DVec3 = 4.0 * (**pos - **target_pos).normalize() * transform.scale.as_dvec3();
|
||||
pos.0 = **target_pos + offset;
|
||||
*v = target_v.clone();
|
||||
}
|
||||
}
|
||||
|
||||
if !settings.dev_mode {
|
||||
return;
|
||||
}
|
||||
|
||||
if key_input.just_pressed(settings.key_cheat_pizza) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
if key_input.just_pressed(settings.key_cheat_farview1) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
if key_input.just_pressed(settings.key_cheat_farview2) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
if key_input.pressed(settings.key_cheat_adrenaline_zero) {
|
||||
lifeform.adrenaline = 0.0;
|
||||
}
|
||||
if key_input.pressed(settings.key_cheat_adrenaline_mid) {
|
||||
lifeform.adrenaline = 0.5;
|
||||
}
|
||||
if key_input.pressed(settings.key_cheat_adrenaline_max) {
|
||||
lifeform.adrenaline = 1.0;
|
||||
}
|
||||
if key_input.just_pressed(settings.key_cheat_die) {
|
||||
settings.god_mode = false;
|
||||
ew_playerdies.send(actor::PlayerDiesEvent(actor::DamageType::Trauma));
|
||||
}
|
||||
}
|
||||
|
||||
// An extension of bevy_xpbd_3d::plugins::position_to_transform that adjusts
|
||||
// the rendering position to center entities at the player camera.
|
||||
// This avoids rendering glitches when very far away from the origin.
|
||||
pub fn position_to_transform(
|
||||
q_player: Query<&Position, With<actor::PlayerCamera>>,
|
||||
mut q_trans: Query<(&'static mut Transform, &'static Position, &'static Rotation), Without<Parent>>,
|
||||
) {
|
||||
if let Ok(player_pos) = q_player.get_single() {
|
||||
for (mut transform, pos, rot) in &mut q_trans {
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
12
src/audio.rs
12
src/audio.rs
|
@ -1,3 +1,15 @@
|
|||
// ▄████████▄ + ███ + ▄█████████ ███ +
|
||||
// ███▀ ▀███ + + ███ ███▀ + ███ + +
|
||||
// ███ + ███ ███ ███ █████████ ███ ███ ███ ███
|
||||
// ███ +███ ███ ███ ███ ███▐██████ ███ ███ ███
|
||||
// ███ + ███ ███+ ███ +███ ███ + ███ ███ + ███
|
||||
// ███▄ ▄███ ███▄ ███ ███ + ███ + ███ ███▄ ███
|
||||
// ▀████████▀ + ▀███████ ███▄ ███▄ ▀████ ▀███████
|
||||
// + + + ███
|
||||
// + ▀████████████████████████████████████████████████████▀
|
||||
//
|
||||
// This module manages sound effects and music.
|
||||
|
||||
use bevy::prelude::*;
|
||||
use bevy::audio::{PlaybackMode, Volume};
|
||||
use crate::var;
|
||||
|
|
|
@ -1,3 +1,17 @@
|
|||
// ▄████████▄ + ███ + ▄█████████ ███ +
|
||||
// ███▀ ▀███ + + ███ ███▀ + ███ + +
|
||||
// ███ + ███ ███ ███ █████████ ███ ███ ███ ███
|
||||
// ███ +███ ███ ███ ███ ███▐██████ ███ ███ ███
|
||||
// ███ + ███ ███+ ███ +███ ███ + ███ ███ + ███
|
||||
// ███▄ ▄███ ███▄ ███ ███ + ███ + ███ ███▄ ███
|
||||
// ▀████████▀ + ▀███████ ███▄ ███▄ ▀████ ▀███████
|
||||
// + + + ███
|
||||
// + ▀████████████████████████████████████████████████████▀
|
||||
//
|
||||
// This module manages the game's viewport, handles camera- and
|
||||
// movement-related keyboard input, and provides some camera-
|
||||
// related computation functions.
|
||||
|
||||
use bevy::prelude::*;
|
||||
use bevy::input::mouse::{MouseMotion, MouseWheel};
|
||||
use bevy::window::PrimaryWindow;
|
||||
|
@ -183,6 +197,10 @@ pub fn update_map_camera(
|
|||
if keyboard_input.pressed(settings.key_left) {
|
||||
offset_z += 1.0;
|
||||
}
|
||||
if keyboard_input.pressed(settings.key_stop) {
|
||||
mapcam.offset_x = 0.0;
|
||||
mapcam.offset_z = 0.0;
|
||||
}
|
||||
|
||||
// Update zoom level
|
||||
if !mapcam.initialized {
|
||||
|
@ -254,6 +272,7 @@ pub fn handle_input(
|
|||
mut settings: ResMut<var::Settings>,
|
||||
mut mapcam: ResMut<MapCam>,
|
||||
mut ew_sfx: EventWriter<audio::PlaySfxEvent>,
|
||||
mut ew_updateoverlays: EventWriter<hud::UpdateOverlayVisibility>,
|
||||
) {
|
||||
if keyboard_input.just_pressed(settings.key_camera) {
|
||||
settings.third_person ^= true;
|
||||
|
@ -261,6 +280,7 @@ pub fn handle_input(
|
|||
if keyboard_input.just_pressed(settings.key_map) {
|
||||
settings.map_active ^= true;
|
||||
*mapcam = MapCam::default();
|
||||
ew_updateoverlays.send(hud::UpdateOverlayVisibility);
|
||||
}
|
||||
if keyboard_input.just_pressed(settings.key_rotation_stabilizer) {
|
||||
ew_sfx.send(audio::PlaySfxEvent(audio::Sfx::Click));
|
||||
|
|
14
src/chat.rs
14
src/chat.rs
|
@ -1,3 +1,16 @@
|
|||
// ▄████████▄ + ███ + ▄█████████ ███ +
|
||||
// ███▀ ▀███ + + ███ ███▀ + ███ + +
|
||||
// ███ + ███ ███ ███ █████████ ███ ███ ███ ███
|
||||
// ███ +███ ███ ███ ███ ███▐██████ ███ ███ ███
|
||||
// ███ + ███ ███+ ███ +███ ███ + ███ ███ + ███
|
||||
// ███▄ ▄███ ███▄ ███ ███ + ███ + ███ ███▄ ███
|
||||
// ▀████████▀ + ▀███████ ███▄ ███▄ ▀████ ▀███████
|
||||
// + + + ███
|
||||
// + ▀████████████████████████████████████████████████████▀
|
||||
//
|
||||
// This module loads the chat definitions from the YAML files
|
||||
// and manages the flow of conversations.
|
||||
|
||||
use crate::{actor, audio, effects, hud, var, world};
|
||||
use bevy::prelude::*;
|
||||
use bevy::math::DVec3;
|
||||
|
@ -9,6 +22,7 @@ use std::collections::HashMap;
|
|||
pub const CHATS: &[&str] = &[
|
||||
include_str!("chats/serenity.yaml"),
|
||||
include_str!("chats/startrans.yaml"),
|
||||
include_str!("chats/thebe.yaml"),
|
||||
];
|
||||
|
||||
pub const TOKEN_CHAT: &str = "chat";
|
||||
|
|
|
@ -1,20 +1,12 @@
|
|||
- chat: Drifter
|
||||
- system: "Error: No response"
|
||||
- system: No life signs detected
|
||||
- Damn, it's gotta be moldy in that suit. How long has it been drifting?:
|
||||
- Harvest some oxygen:
|
||||
- script: refilloxygen 1 Drifter
|
||||
|
||||
|
||||
---
|
||||
|
||||
|
||||
- chat: SubduedClippy
|
||||
- At your service!
|
||||
|
||||
|
||||
---
|
||||
|
||||
# ▄████████▄ + ███ + ▄█████████ ███ +
|
||||
# ███▀ ▀███ + + ███ ███▀ + ███ + +
|
||||
# ███ + ███ ███ ███ █████████ ███ ███ ███ ███
|
||||
# ███ +███ ███ ███ ███ ███▐██████ ███ ███ ███
|
||||
# ███ + ███ ███+ ███ +███ ███ + ███ ███ + ███
|
||||
# ███▄ ▄███ ███▄ ███ ███ + ███ + ███ ███▄ ███
|
||||
# ▀████████▀ + ▀███████ ███▄ ███▄ ▀████ ▀███████
|
||||
# + + + ███
|
||||
# + ▀████████████████████████████████████████████████████▀
|
||||
|
||||
- chat: Icarus
|
||||
- if $met:
|
||||
|
@ -134,53 +126,6 @@
|
|||
---
|
||||
|
||||
|
||||
- chat: SpacePizzaChef
|
||||
- Welcome to Space Pizza™, best pizza around the rings!
|
||||
- Great to see a customer, we don't get many lately
|
||||
- Would you like to order today's special?
|
||||
- label: offer
|
||||
- What's the special?:
|
||||
- Suspicious Spacefunghi
|
||||
- With free pineapple imitation
|
||||
- Our pizza smoothies are freshly blended every day
|
||||
- Wait... pizza smoothie?:
|
||||
- Huh? Of course, smoothie! How else do you want to get that pizza down your spacesuit feeding tube?
|
||||
- An emulsion of deliciousness!
|
||||
- I think I'll pass...:
|
||||
- Your loss, mate
|
||||
- goto: EXIT
|
||||
- Wh... what's a pizzeria doing here?:
|
||||
- Hah, beautiful, right? I carved it out this asteroid myself!
|
||||
- You know how much work it was to neutralize the rotation of the asteroid, so my valued customers don't bang against the walls while drinking my pizza?
|
||||
- Now would you like today's special or not?
|
||||
- goto: offer
|
||||
- My head hurts, my suit leaks, I think I'm dying...:
|
||||
- Seriously? Let me have a look. Just press the 'Grant Access' button please.
|
||||
- "[GRANT ACCESS TO SPACESUIT WIFI]":
|
||||
- label: hack
|
||||
- warn: MALWARE DETECTED
|
||||
- warn: BITCOIN MINER DETECTED
|
||||
- nowait: true
|
||||
Hey, what are you doing with me?:
|
||||
- Just checking your systems, hang on tight
|
||||
- Yeah, suit's fucked, I'd look out for a repair shop
|
||||
- Anyway, wanna order today's special?
|
||||
- goto: offer
|
||||
- "[DENY ACCESS TO SPACESUIT WIFI]":
|
||||
- Oh come on, do you want my help or not?
|
||||
- "[GRANT ACCESS TO SPACESUIT WIFI]":
|
||||
- goto: hack
|
||||
- "[DENY ACCESS TO SPACESUIT WIFI]":
|
||||
- Great, the first customer in ages, and they're brain damaged...
|
||||
- Fuck off!:
|
||||
- Great, the first customer in ages, and they're brain damaged...
|
||||
- goto: EXIT
|
||||
- Hey, are you still there? Is this a prank?
|
||||
|
||||
|
||||
---
|
||||
|
||||
|
||||
- chat: PizzaChef
|
||||
- if $eat:
|
||||
- Ah, they always come back.
|
||||
|
@ -351,3 +296,21 @@
|
|||
- Push the TAB button, your space suit's AR will show you the date and time.
|
||||
- goto: generic_questions
|
||||
- I think I'm good for now.: []
|
||||
|
||||
|
||||
---
|
||||
|
||||
|
||||
- chat: Drifter
|
||||
- system: "Error: No response"
|
||||
- system: No life signs detected
|
||||
- Damn, it's gotta be moldy in that suit. How long has it been drifting?:
|
||||
- Harvest some oxygen:
|
||||
- script: refilloxygen 1 Drifter
|
||||
|
||||
|
||||
---
|
||||
|
||||
|
||||
- chat: SubduedClippy
|
||||
- At your service!
|
||||
|
|
|
@ -1,3 +1,13 @@
|
|||
# ▄████████▄ + ███ + ▄█████████ ███ +
|
||||
# ███▀ ▀███ + + ███ ███▀ + ███ + +
|
||||
# ███ + ███ ███ ███ █████████ ███ ███ ███ ███
|
||||
# ███ +███ ███ ███ ███ ███▐██████ ███ ███ ███
|
||||
# ███ + ███ ███+ ███ +███ ███ + ███ ███ + ███
|
||||
# ███▄ ▄███ ███▄ ███ ███ + ███ + ███ ███▄ ███
|
||||
# ▀████████▀ + ▀███████ ███▄ ███▄ ▀████ ▀███████
|
||||
# + + + ███
|
||||
# + ▀████████████████████████████████████████████████████▀
|
||||
|
||||
- chat: NPCinCryoStasis
|
||||
- system: "Error: No response"
|
||||
- system: Lifeform in cryostasis detected
|
||||
|
|
93
src/chats/thebe.yaml
Normal file
93
src/chats/thebe.yaml
Normal file
|
@ -0,0 +1,93 @@
|
|||
# ▄████████▄ + ███ + ▄█████████ ███ +
|
||||
# ███▀ ▀███ + + ███ ███▀ + ███ + +
|
||||
# ███ + ███ ███ ███ █████████ ███ ███ ███ ███
|
||||
# ███ +███ ███ ███ ███ ███▐██████ ███ ███ ███
|
||||
# ███ + ███ ███+ ███ +███ ███ + ███ ███ + ███
|
||||
# ███▄ ▄███ ███▄ ███ ███ + ███ + ███ ███▄ ███
|
||||
# ▀████████▀ + ▀███████ ███▄ ███▄ ▀████ ▀███████
|
||||
# + + + ███
|
||||
# + ▀████████████████████████████████████████████████████▀
|
||||
|
||||
- chat: Yuni
|
||||
- if $introduced:
|
||||
- Hi again!
|
||||
- goto: questions
|
||||
- OH!
|
||||
- Wow, you found me!
|
||||
- You've come a long way, let me patch you up!
|
||||
- script: repairsuit
|
||||
- system: SuitPatch™ SuperGlue™ applied.
|
||||
- script: refilloxygen 1
|
||||
- system: Oxygen refilled
|
||||
- How the 卫生纸 did you even get here?
|
||||
- I saw the point-of-interest marker and flew all the way here!:
|
||||
- Holy 螃蟹, that's impressive.
|
||||
- It's really not easy, with all the asteroids on the way.
|
||||
- Well, uhm, I might have cheated a little bit.:
|
||||
- "Hah :)"
|
||||
- Nothing to be ashamed of, of course.
|
||||
- Feel free to explore this world on your own terms.
|
||||
- Hope you like this place so far.
|
||||
- Took me quite a long time to get all the details just right.
|
||||
- nowait: true
|
||||
Ah, you're the game developer, aren't you?:
|
||||
- "Well, in a sense, yes, I am :)"
|
||||
- Tell me, what do you like the most?
|
||||
- set: $introduced
|
||||
- The stars are so pretty!:
|
||||
- "*_* Yes!! I love them too!"
|
||||
- Have you tried opening the map and zooming all the way out?
|
||||
- That really blows my mind and brings tears to my eyes.
|
||||
- Really shows how small we are, and how much more there is out there.
|
||||
- Jupiter! It's beautiful and terrifying at the same time!:
|
||||
- Jupiter really creeps me out!
|
||||
- I visited Metis Prime earlier, and how Jupiter was eating up half the night sky shook me to the core.
|
||||
- This planet is so gigantic, it's even bigger than some red dwarf stars!
|
||||
- Some abysmal cosmic horror, if you ask me.
|
||||
- Thebe, this moon here, on the other hand, is small and cozy in comparison.
|
||||
- I can get up close without too much fear of dying.
|
||||
- The pizza sure is awesome here:
|
||||
- Ah come on, don't lie to me.
|
||||
- Nobody likes pizza through their feeding tube.
|
||||
- Even if it's the legendary Old Earth Pizza smoothies, it's still smoothies.
|
||||
- I love the freedom I have in this world:
|
||||
- Right, nobody tells you what to do or not to do. :)
|
||||
- I love crashing things into one another and watching things fly off into the distance.
|
||||
- Have you been to Metis Prime and tried out driving The Whale?
|
||||
- That ship is enormous and can swallow pretty much anything.
|
||||
- But did you know that you can also take it with you on a bus ride?
|
||||
- Give that a try if you like, it's hilarious.
|
||||
- I wish I could tell you, but the thing I want to say is not listed here.:
|
||||
- Oh, what a pity!
|
||||
- Come on, let's change that.
|
||||
- If you write me a message, out there in "reality", I can add your choice here.
|
||||
- Check out the README for ways of contacting me! :)
|
||||
- Anyway.
|
||||
|
||||
- label: questions
|
||||
- What are you doing here?:
|
||||
- Thinking.
|
||||
- I want to add a space station orbiting Thebe.
|
||||
- But I don't have any inspiration yet.
|
||||
- I thought that if I come over here myself, maybe some inspiration will come to me.
|
||||
- Visit again later, it'll be cool! :)
|
||||
- How are you doing?:
|
||||
- Great. Creating this world is quite the blast! :)
|
||||
- I have so many ideas though, and so little time.
|
||||
- You should check for updates in a couple months.
|
||||
- If my "reality" persona is still alive by then, I'm sure there'll be cool new things to explore.
|
||||
- Are you... God?:
|
||||
- I'm the avatar of the game creator, if that's what you mean.
|
||||
- But I'm not omnipotent or something.
|
||||
- In here, I'm still constrained to the same laws of physics as you are.
|
||||
- And out there, in "reality", I am a mere mortal of flesh and bone.
|
||||
- "What do *you* like the most?":
|
||||
- Watching this place grow!
|
||||
- It started out with just a black window. Then came a skybox.
|
||||
- But now, look at this! It's really starting to get cozy here.
|
||||
- I keep discovering new, beautiful things here that just blow my mind.
|
||||
- Can't wait to see what I'm going to add next.
|
||||
- See you around!:
|
||||
- Don't be a stranger!
|
||||
- goto: EXIT
|
||||
- goto: questions
|
|
@ -1,9 +1,20 @@
|
|||
// This plugin loads "defs.txt" and applies the therein contained commands
|
||||
// ▄████████▄ + ███ + ▄█████████ ███ +
|
||||
// ███▀ ▀███ + + ███ ███▀ + ███ + +
|
||||
// ███ + ███ ███ ███ █████████ ███ ███ ███ ███
|
||||
// ███ +███ ███ ███ ███ ███▐██████ ███ ███ ███
|
||||
// ███ + ███ ███+ ███ +███ ███ + ███ ███ + ███
|
||||
// ███▄ ▄███ ███▄ ███ ███ + ███ + ███ ███▄ ███
|
||||
// ▀████████▀ + ▀███████ ███▄ ███▄ ▀████ ▀███████
|
||||
// + + + ███
|
||||
// + ▀████████████████████████████████████████████████████▀
|
||||
//
|
||||
// This module populates the world with actors as defined in "defs.txt"
|
||||
|
||||
extern crate regex;
|
||||
use bevy::prelude::*;
|
||||
use bevy_xpbd_3d::prelude::*;
|
||||
use bevy::math::DVec3;
|
||||
use crate::{actor, camera, chat, hud, nature, shading, world};
|
||||
use crate::{actor, camera, chat, hud, nature, shading, skeleton, world};
|
||||
use regex::Regex;
|
||||
use std::f32::consts::PI;
|
||||
use std::f64::consts::PI as PI64;
|
||||
|
@ -54,6 +65,7 @@ struct ParserState {
|
|||
is_clickable: bool,
|
||||
is_targeted_on_startup: bool,
|
||||
is_sun: bool,
|
||||
is_point_of_interest: bool,
|
||||
has_physics: bool,
|
||||
has_ring: bool,
|
||||
wants_maxrotation: Option<f64>,
|
||||
|
@ -103,6 +115,7 @@ impl Default for ParserState {
|
|||
is_clickable: true,
|
||||
is_targeted_on_startup: false,
|
||||
is_sun: false,
|
||||
is_point_of_interest: false,
|
||||
has_physics: true,
|
||||
has_ring: false,
|
||||
wants_maxrotation: None,
|
||||
|
@ -133,7 +146,7 @@ pub fn load_defs(
|
|||
) {
|
||||
let re1 = Regex::new(r"^\s*([a-z_-]+)\s+(.*)$").unwrap();
|
||||
let re2 = Regex::new("\"([^\"]*)\"|(-?[0-9]+[0-9e-]*(?:\\.[0-9e-]+)?)|([a-zA-Z_-][a-zA-Z0-9_-]*)").unwrap();
|
||||
let defs_string = include_str!("defs.txt");
|
||||
let defs_string = include_str!("data/defs.txt");
|
||||
let mut lines = defs_string.lines();
|
||||
let mut state = ParserState::default();
|
||||
let mut command;
|
||||
|
@ -252,6 +265,9 @@ pub fn load_defs(
|
|||
["ring", "yes"] => {
|
||||
state.has_ring = true;
|
||||
}
|
||||
["pointofinterest", "yes"] => {
|
||||
state.is_point_of_interest = true;
|
||||
}
|
||||
["oxygen", amount] => {
|
||||
if let Ok(amount) = amount.parse::<f32>() {
|
||||
state.is_lifeform = true;
|
||||
|
@ -523,14 +539,14 @@ fn spawn_entities(
|
|||
..default()
|
||||
});
|
||||
} else if let Some(model) = &state.model {
|
||||
actor.insert(SceneBundle {
|
||||
actor.insert(SpatialBundle {
|
||||
transform: Transform {
|
||||
scale: Vec3::splat(state.model_scale),
|
||||
..default()
|
||||
},
|
||||
scene: asset_server.load(world::asset_name_to_path(model.as_str())),
|
||||
..default()
|
||||
});
|
||||
skeleton::load(model.as_str(), &mut actor, &*asset_server);
|
||||
}
|
||||
|
||||
// Physics Parameters
|
||||
|
@ -663,17 +679,30 @@ fn spawn_entities(
|
|||
}
|
||||
|
||||
if let Some(ar_asset_name) = &state.ar_model {
|
||||
commands.spawn((
|
||||
let mut entitycmd = commands.spawn((
|
||||
hud::AugmentedRealityOverlay {
|
||||
owner: actor_entity,
|
||||
},
|
||||
world::DespawnOnPlayerDeath,
|
||||
SceneBundle {
|
||||
scene: asset_server.load(world::asset_name_to_path(ar_asset_name)),
|
||||
SpatialBundle {
|
||||
visibility: Visibility::Hidden,
|
||||
..default()
|
||||
},
|
||||
));
|
||||
skeleton::load(ar_asset_name, &mut entitycmd, &*asset_server);
|
||||
}
|
||||
|
||||
if state.is_point_of_interest {
|
||||
let mut entitycmd = commands.spawn((
|
||||
hud::PointOfInterestMarker(actor_entity),
|
||||
world::DespawnOnPlayerDeath,
|
||||
hud::ToggleableHudElement,
|
||||
SpatialBundle {
|
||||
visibility: Visibility::Hidden,
|
||||
..default()
|
||||
},
|
||||
));
|
||||
skeleton::load("point_of_interest", &mut entitycmd, &*asset_server);
|
||||
}
|
||||
|
||||
if state.has_ring {
|
||||
|
@ -698,19 +727,10 @@ 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>>,
|
||||
) {
|
||||
pub fn hide_colliders(mut q_mesh: Query<(&mut Visibility, &Name), (Added<Visibility>, With<Handle<Mesh>>)>) {
|
||||
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>();
|
||||
// }
|
||||
}
|
||||
|
|
|
@ -120,7 +120,7 @@ actor 0 0 0 jupiter
|
|||
clickable no
|
||||
physics off
|
||||
|
||||
actor 0 593051 0 suit
|
||||
actor 0 593051 0 suitv1
|
||||
relativeto jupiter
|
||||
orbit 224000e3 0.66
|
||||
player yes
|
||||
|
@ -146,6 +146,7 @@ actor 10 -30 20 MeteorAceGT
|
|||
camdistance 50
|
||||
density 500
|
||||
angularmomentum 0.1 0.1 0.3
|
||||
pointofinterest yes
|
||||
|
||||
actor 0 0 0 io
|
||||
name Io
|
||||
|
@ -206,6 +207,20 @@ actor 0 0 0 moonlet
|
|||
orbit 221900e3 0.66
|
||||
scale 50e3
|
||||
angularmomentum 0 0.025 0
|
||||
actor -48e3 20e3 0 suitv1
|
||||
relativeto thebe
|
||||
id yuni
|
||||
name "Yuni"
|
||||
chatid Yuni
|
||||
scale 2
|
||||
density 200
|
||||
collider handcrafted
|
||||
thrust 1.2 1 1 400 1.5
|
||||
rotationx 1
|
||||
engine monopropellant
|
||||
wants maxrotation 0
|
||||
wants maxvelocity 0
|
||||
pointofinterest yes
|
||||
|
||||
actor 0 0 0 moonlet
|
||||
name Metis
|
||||
|
@ -301,6 +316,7 @@ actor -3300 10 0 pizzeria
|
|||
relativeto player
|
||||
id pizzeria
|
||||
scale 40
|
||||
pointofinterest yes
|
||||
collider mesh
|
||||
rotationy 0.30
|
||||
angularmomentum 0 0 0
|
||||
|
@ -315,6 +331,7 @@ actor -3300 10 0 pizzeria
|
|||
camdistance 50
|
||||
density 500
|
||||
angularmomentum 0 0 0.2
|
||||
pointofinterest yes
|
||||
actor -100 63 -13 pizzasign
|
||||
name "Pizzeria Sign"
|
||||
relativeto pizzeria
|
||||
|
@ -345,7 +362,7 @@ actor -3300 10 0 pizzeria
|
|||
chatid SubduedClippy
|
||||
pronoun it
|
||||
|
||||
actor -45 -4 -4 suit
|
||||
actor -45 -4 -4 suitv1
|
||||
relativeto pizzeria
|
||||
name "Nox"
|
||||
chatid PizzaChef
|
||||
|
@ -360,7 +377,7 @@ actor -3300 10 0 pizzeria
|
|||
angularmomentum 0 0 0
|
||||
pronoun he
|
||||
|
||||
actor 60 -15 -40 suit
|
||||
actor 60 -15 -40 suitv1
|
||||
relativeto player
|
||||
name Icarus
|
||||
id Icarus
|
||||
|
@ -371,17 +388,19 @@ actor 60 -15 -40 suit
|
|||
angularmomentum 0.4 0.2 0.1
|
||||
rotationy 0.6
|
||||
rotationx 1
|
||||
pointofinterest yes
|
||||
thrust 1.2 1 1 10 1.5
|
||||
wants maxrotation 0.5
|
||||
wants maxvelocity 0
|
||||
pronoun it
|
||||
|
||||
actor -300 0 40 suit
|
||||
actor -300 0 40 suitv1
|
||||
relativeto player
|
||||
id Drifter
|
||||
name "梓涵"
|
||||
chatid Drifter
|
||||
oxygen 0.08
|
||||
pointofinterest yes
|
||||
scale 2
|
||||
collider handcrafted
|
||||
pronoun she
|
||||
|
@ -391,6 +410,7 @@ actor 100 -18000 2000 "orb_busstop"
|
|||
id "busstop"
|
||||
name "StarTrans Bus Stop: Serenity Station"
|
||||
scale 100
|
||||
pointofinterest yes
|
||||
wants maxrotation 0
|
||||
wants maxvelocity 0
|
||||
actor 120 864 150 clippy
|
||||
|
@ -422,7 +442,7 @@ actor 100 -18000 2000 "orb_busstop"
|
|||
name "Light Orb"
|
||||
relativeto busstopclippy
|
||||
light "47FF00" 1000000
|
||||
actor 8 2 0 suit
|
||||
actor 8 2 0 suitv1
|
||||
relativeto "busstopclippy"
|
||||
name "Rudy"
|
||||
wants maxrotation 0.2
|
||||
|
@ -438,6 +458,7 @@ actor -184971e3 149410e3 -134273e3 "orb_busstop"
|
|||
id "busstop2"
|
||||
name "StarTrans Bus Station 'Oscillation Station'"
|
||||
scale 100
|
||||
pointofinterest yes
|
||||
wants maxrotation 0
|
||||
wants maxvelocity 0
|
||||
actor 120 864 150 clippy
|
||||
|
@ -475,6 +496,7 @@ actor 27643e3 -44e3 -124434e3 "orb_busstop"
|
|||
id "busstop3"
|
||||
name "StarTrans Bus Station 'Metis Prime'"
|
||||
scale 100
|
||||
pointofinterest yes
|
||||
wants maxrotation 0
|
||||
wants maxvelocity 0
|
||||
actor 120 864 150 clippy
|
||||
|
@ -515,6 +537,7 @@ actor 110 -2000 0 whale
|
|||
density 100000
|
||||
camdistance 4000
|
||||
scale 300
|
||||
pointofinterest yes
|
||||
angularmomentum 0 0.015 0
|
||||
thrust 2.45 0.48 0.33 1000000000000000 3
|
||||
engine ion
|
|
@ -1,3 +1,15 @@
|
|||
// ▄████████▄ + ███ + ▄█████████ ███ +
|
||||
// ███▀ ▀███ + + ███ ███▀ + ███ + +
|
||||
// ███ + ███ ███ ███ █████████ ███ ███ ███ ███
|
||||
// ███ +███ ███ ███ ███ ███▐██████ ███ ███ ███
|
||||
// ███ + ███ ███+ ███ +███ ███ + ███ ███ + ███
|
||||
// ███▄ ▄███ ███▄ ███ ███ + ███ + ███ ███▄ ███
|
||||
// ▀████████▀ + ▀███████ ███▄ ███▄ ▀████ ▀███████
|
||||
// + + + ███
|
||||
// + ▀████████████████████████████████████████████████████▀
|
||||
//
|
||||
// This module manages visual effects.
|
||||
|
||||
use bevy::prelude::*;
|
||||
use crate::{camera, var};
|
||||
|
||||
|
|
99
src/hud.rs
99
src/hud.rs
|
@ -1,4 +1,16 @@
|
|||
use crate::{actor, audio, camera, chat, nature, var, world};
|
||||
// ▄████████▄ + ███ + ▄█████████ ███ +
|
||||
// ███▀ ▀███ + + ███ ███▀ + ███ + +
|
||||
// ███ + ███ ███ ███ █████████ ███ ███ ███ ███
|
||||
// ███ +███ ███ ███ ███ ███▐██████ ███ ███ ███
|
||||
// ███ + ███ ███+ ███ +███ ███ + ███ ███ + ███
|
||||
// ███▄ ▄███ ███▄ ███ ███ + ███ + ███ ███▄ ███
|
||||
// ▀████████▀ + ▀███████ ███▄ ███▄ ▀████ ▀███████
|
||||
// + + + ███
|
||||
// + ▀████████████████████████████████████████████████████▀
|
||||
//
|
||||
// This module manages the heads-up display and augmented reality overlays.
|
||||
|
||||
use crate::{actor, audio, camera, chat, nature, skeleton, var};
|
||||
use bevy::prelude::*;
|
||||
use bevy::diagnostic::{DiagnosticsStore, FrameTimeDiagnosticsPlugin};
|
||||
use bevy::transform::TransformSystem;
|
||||
|
@ -29,8 +41,12 @@ impl Plugin for HudPlugin {
|
|||
handle_target_event,
|
||||
));
|
||||
app.add_systems(PostUpdate, (
|
||||
update_overlay_visibility,
|
||||
update_ar_overlays
|
||||
.after(world::position_to_transform)
|
||||
.after(actor::position_to_transform)
|
||||
.in_set(sync::SyncSet::PositionToTransform),
|
||||
update_poi_overlays
|
||||
.after(actor::position_to_transform)
|
||||
.in_set(sync::SyncSet::PositionToTransform),
|
||||
update_target_selectagon
|
||||
.after(PhysicsSet::Sync)
|
||||
|
@ -47,19 +63,23 @@ impl Plugin for HudPlugin {
|
|||
app.insert_resource(FPSUpdateTimer(
|
||||
Timer::from_seconds(HUD_REFRESH_TIME, TimerMode::Repeating)));
|
||||
app.add_event::<TargetEvent>();
|
||||
app.add_event::<UpdateOverlayVisibility>();
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Event)] pub struct TargetEvent(pub Option<Entity>);
|
||||
#[derive(Event)] pub struct UpdateOverlayVisibility;
|
||||
#[derive(Component)] struct NodeHud;
|
||||
#[derive(Component)] struct NodeConsole;
|
||||
#[derive(Component)] struct NodeChoiceText;
|
||||
#[derive(Component)] struct NodeCurrentChatLine;
|
||||
#[derive(Component)] struct Reticule;
|
||||
#[derive(Component)] struct ToggleableHudElement;
|
||||
#[derive(Component)] pub struct ToggleableHudElement;
|
||||
#[derive(Component)] pub struct ToggleableHudMapElement;
|
||||
#[derive(Component)] struct OnlyHideWhenTogglingHud;
|
||||
#[derive(Component)] struct Selectagon;
|
||||
#[derive(Component)] pub struct IsTargeted;
|
||||
#[derive(Component)] pub struct PointOfInterestMarker(pub Entity);
|
||||
|
||||
#[derive(Resource)]
|
||||
pub struct AugmentedRealityState {
|
||||
|
@ -338,16 +358,16 @@ fn setup(
|
|||
});
|
||||
|
||||
// Selectagon
|
||||
commands.spawn((
|
||||
let mut entitycmd = commands.spawn((
|
||||
Selectagon,
|
||||
ToggleableHudElement,
|
||||
OnlyHideWhenTogglingHud,
|
||||
SceneBundle {
|
||||
scene: asset_server.load(world::asset_name_to_path("selectagon")),
|
||||
SpatialBundle {
|
||||
visibility: Visibility::Hidden,
|
||||
..default()
|
||||
},
|
||||
));
|
||||
skeleton::load("selectagon", &mut entitycmd, &*asset_server);
|
||||
|
||||
// AR-related things
|
||||
ambient_light.brightness = if settings.hud_active {
|
||||
|
@ -626,10 +646,10 @@ fn handle_input(
|
|||
mouse_input: Res<ButtonInput<MouseButton>>,
|
||||
mut settings: ResMut<var::Settings>,
|
||||
mut log: ResMut<Log>,
|
||||
mut q_hud: Query<(&mut Visibility, Option<&OnlyHideWhenTogglingHud>), With<ToggleableHudElement>>,
|
||||
mut ew_sfx: EventWriter<audio::PlaySfxEvent>,
|
||||
mut ew_togglemusic: EventWriter<audio::ToggleMusicEvent>,
|
||||
mut ew_target: EventWriter<TargetEvent>,
|
||||
mut ew_updateoverlays: EventWriter<UpdateOverlayVisibility>,
|
||||
mut ambient_light: ResMut<AmbientLight>,
|
||||
q_objects: Query<(Entity, &Transform), (With<IsClickable>, Without<IsTargeted>, Without<actor::PlayerDrivesThis>, Without<actor::Player>)>,
|
||||
q_camera: Query<&Transform, With<Camera>>,
|
||||
|
@ -640,21 +660,12 @@ fn handle_input(
|
|||
}
|
||||
}
|
||||
if keyboard_input.just_pressed(settings.key_togglehud) {
|
||||
ew_updateoverlays.send(UpdateOverlayVisibility);
|
||||
settings.hud_active ^= true;
|
||||
if settings.hud_active {
|
||||
for (mut hudelement_visibility, _) in q_hud.iter_mut() {
|
||||
*hudelement_visibility = Visibility::Hidden;
|
||||
}
|
||||
settings.hud_active = false;
|
||||
ambient_light.brightness = AMBIENT_LIGHT;
|
||||
}
|
||||
else {
|
||||
for (mut hudelement_visibility, only_hide) in q_hud.iter_mut() {
|
||||
if only_hide.is_none() {
|
||||
*hudelement_visibility = Visibility::Inherited;
|
||||
}
|
||||
}
|
||||
settings.hud_active = true;
|
||||
ambient_light.brightness = AMBIENT_LIGHT_AR;
|
||||
} else {
|
||||
ambient_light.brightness = AMBIENT_LIGHT;
|
||||
}
|
||||
ew_sfx.send(audio::PlaySfxEvent(audio::Sfx::Switch));
|
||||
ew_togglemusic.send(audio::ToggleMusicEvent());
|
||||
|
@ -770,3 +781,51 @@ fn update_ar_overlays (
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn update_poi_overlays (
|
||||
mut q_marker: Query<(&mut Transform, &PointOfInterestMarker)>,
|
||||
q_parent: Query<&Transform, Without<PointOfInterestMarker>>,
|
||||
q_camera: Query<&Transform, (With<Camera>, Without<PointOfInterestMarker>)>,
|
||||
settings: ResMut<var::Settings>,
|
||||
) {
|
||||
if !settings.hud_active || !settings.map_active || q_camera.is_empty() {
|
||||
return;
|
||||
}
|
||||
let camera_trans = q_camera.get_single().unwrap();
|
||||
for (mut trans, marker) in &mut q_marker {
|
||||
if let Ok(parent_trans) = q_parent.get(marker.0) {
|
||||
// Enlarge POI marker to a minimum angular diameter
|
||||
trans.translation = parent_trans.translation;
|
||||
trans.scale = Vec3::splat(1.0);
|
||||
let (angular_diameter, _, _) = camera::calc_angular_diameter(
|
||||
&trans, camera_trans);
|
||||
let min_angular_diameter = 3.0f32.to_radians();
|
||||
if angular_diameter < min_angular_diameter {
|
||||
trans.scale *= min_angular_diameter / angular_diameter;
|
||||
}
|
||||
trans.look_at(camera_trans.translation, camera_trans.up().into());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn update_overlay_visibility(
|
||||
mut q_marker: Query<&mut Visibility, With<PointOfInterestMarker>>,
|
||||
mut q_hudelement: Query<&mut Visibility, (With<ToggleableHudElement>, Without<PointOfInterestMarker>)>,
|
||||
er_target: EventReader<UpdateOverlayVisibility>,
|
||||
settings: Res<var::Settings>,
|
||||
) {
|
||||
if er_target.is_empty() {
|
||||
return;
|
||||
}
|
||||
let check = {|check: bool|
|
||||
if check { Visibility::Inherited } else { Visibility::Hidden }
|
||||
};
|
||||
let show_poi = check(settings.hud_active && settings.map_active);
|
||||
let show_hud = check(settings.hud_active);
|
||||
for mut vis in &mut q_marker {
|
||||
*vis = show_poi;
|
||||
}
|
||||
for mut vis in &mut q_hudelement {
|
||||
*vis = show_hud;
|
||||
}
|
||||
}
|
||||
|
|
31
src/main.rs
31
src/main.rs
|
@ -1,3 +1,16 @@
|
|||
// ▄████████▄ + ███ + ▄█████████ ███ +
|
||||
// ███▀ ▀███ + + ███ ███▀ + ███ + +
|
||||
// ███ + ███ ███ ███ █████████ ███ ███ ███ ███
|
||||
// ███ +███ ███ ███ ███ ███▐██████ ███ ███ ███
|
||||
// ███ + ███ ███+ ███ +███ ███ + ███ ███ + ███
|
||||
// ███▄ ▄███ ███▄ ███ ███ + ███ + ███ ███▄ ███
|
||||
// ▀████████▀ + ▀███████ ███▄ ███▄ ▀████ ▀███████
|
||||
// + + + ███
|
||||
// + ▀████████████████████████████████████████████████████▀
|
||||
//
|
||||
// This module initializes the game, handles command-line arguments,
|
||||
// and manages window-related key bindings.
|
||||
|
||||
mod actor;
|
||||
mod audio;
|
||||
mod camera;
|
||||
|
@ -6,6 +19,7 @@ mod commands;
|
|||
mod effects;
|
||||
mod hud;
|
||||
mod shading;
|
||||
mod skeleton;
|
||||
mod var;
|
||||
mod world;
|
||||
|
||||
|
@ -15,7 +29,6 @@ mod nature;
|
|||
use bevy::window::{Window, WindowMode, PrimaryWindow, CursorGrabMode};
|
||||
use bevy::diagnostic::FrameTimeDiagnosticsPlugin;
|
||||
use bevy::prelude::*;
|
||||
use bevy_embedded_assets::{EmbeddedAssetPlugin, PluginMode};
|
||||
use bevy::pbr::ExtendedMaterial;
|
||||
use std::env;
|
||||
|
||||
|
@ -32,15 +45,12 @@ fn main() {
|
|||
return;
|
||||
}
|
||||
}
|
||||
if cfg!(debug_assertions) {
|
||||
App::new().add_plugins(OutFlyPlugin).run();
|
||||
} else {
|
||||
// In release builds, embed assets into the binary
|
||||
App::new().add_plugins((
|
||||
EmbeddedAssetPlugin { mode: PluginMode::ReplaceDefault },
|
||||
OutFlyPlugin,
|
||||
)).run();
|
||||
}
|
||||
let mut app = App::new();
|
||||
#[cfg(feature = "embed_assets")]
|
||||
app.add_plugins(bevy_embedded_assets::EmbeddedAssetPlugin {
|
||||
mode: bevy_embedded_assets::PluginMode::ReplaceDefault
|
||||
});
|
||||
app.add_plugins(OutFlyPlugin).run();
|
||||
}
|
||||
|
||||
pub struct OutFlyPlugin;
|
||||
|
@ -63,6 +73,7 @@ impl Plugin for OutFlyPlugin {
|
|||
effects::EffectsPlugin,
|
||||
hud::HudPlugin,
|
||||
shading::ShadingPlugin,
|
||||
skeleton::SkeletonPlugin,
|
||||
world::WorldPlugin,
|
||||
));
|
||||
}
|
||||
|
|
|
@ -1,6 +1,14 @@
|
|||
// This stuff here, this stuff is messy. Nobody wants to deal with this,
|
||||
// nobody cares how it works, but I guess we need it as an ingredient for
|
||||
// the universe *sigh* so here we go.
|
||||
// ▄████████▄ + ███ + ▄█████████ ███ +
|
||||
// ███▀ ▀███ + + ███ ███▀ + ███ + +
|
||||
// ███ + ███ ███ ███ █████████ ███ ███ ███ ███
|
||||
// ███ +███ ███ ███ ███ ███▐██████ ███ ███ ███
|
||||
// ███ + ███ ███+ ███ +███ ███ + ███ ███ + ███
|
||||
// ███▄ ▄███ ███▄ ███ ███ + ███ + ███ ███▄ ███
|
||||
// ▀████████▀ + ▀███████ ███▄ ███▄ ▀████ ▀███████
|
||||
// + + + ███
|
||||
// + ▀████████████████████████████████████████████████████▀
|
||||
//
|
||||
// This module manages the messy, impure parts of our universe.
|
||||
|
||||
pub const OXYGEN_USE_KG_PER_S: f32 = 1e-5;
|
||||
pub const OXY_S: f32 = OXYGEN_USE_KG_PER_S;
|
||||
|
|
|
@ -1,3 +1,15 @@
|
|||
// ▄████████▄ + ███ + ▄█████████ ███ +
|
||||
// ███▀ ▀███ + + ███ ███▀ + ███ + +
|
||||
// ███ + ███ ███ ███ █████████ ███ ███ ███ ███
|
||||
// ███ +███ ███ ███ ███ ███▐██████ ███ ███ ███
|
||||
// ███ + ███ ███+ ███ +███ ███ + ███ ███ + ███
|
||||
// ███▄ ▄███ ███▄ ███ ███ + ███ + ███ ███▄ ███
|
||||
// ▀████████▀ + ▀███████ ███▄ ███▄ ▀████ ▀███████
|
||||
// + + + ███
|
||||
// + ▀████████████████████████████████████████████████████▀
|
||||
//
|
||||
// This module manages graphics shaders.
|
||||
|
||||
use bevy::prelude::*;
|
||||
use bevy::render::render_resource::{AsBindGroup, ShaderRef};
|
||||
use bevy::pbr::{ExtendedMaterial, MaterialExtension, OpaqueRendererMethod};
|
||||
|
|
329
src/skeleton.rs
Normal file
329
src/skeleton.rs
Normal file
|
@ -0,0 +1,329 @@
|
|||
// ▄████████▄ + ███ + ▄█████████ ███ +
|
||||
// ███▀ ▀███ + + ███ ███▀ + ███ + +
|
||||
// ███ + ███ ███ ███ █████████ ███ ███ ███ ███
|
||||
// ███ +███ ███ ███ ███ ███▐██████ ███ ███ ███
|
||||
// ███ + ███ ███+ ███ +███ ███ + ███ ███ + ███
|
||||
// ███▄ ▄███ ███▄ ███ ███ + ███ + ███ ███▄ ███
|
||||
// ▀████████▀ + ▀███████ ███▄ ███▄ ▀████ ▀███████
|
||||
// + + + ███
|
||||
// + ▀████████████████████████████████████████████████████▀
|
||||
//
|
||||
// This module manages model loading and animation.
|
||||
|
||||
use crate::world;
|
||||
use bevy::ecs::system::EntityCommands;
|
||||
use bevy::prelude::*;
|
||||
|
||||
pub struct SkeletonPlugin;
|
||||
impl Plugin for SkeletonPlugin {
|
||||
fn build(&self, app: &mut App) {
|
||||
app.add_systems(Update, animate_skeleton_parts);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn asset_name_to_path(name: &str) -> &'static str {
|
||||
match name {
|
||||
"suit_ar_chefhat" => "models/suit_v1/ar_chefhat.glb#Scene0",
|
||||
"asteroid1" => "models/asteroid.glb#Scene0",
|
||||
"asteroid2" => "models/asteroid2.glb#Scene0",
|
||||
"asteroid_lum" => "models/asteroid_lum.glb#Scene0",
|
||||
"moonlet" => "models/moonlet.glb#Scene0",
|
||||
"monolith" => "models/monolith_neon.glb#Scene0",
|
||||
"lightorb" => "models/lightorb.glb#Scene0",
|
||||
"orb_busstop" => "models/orb_busstop.glb#Scene0",
|
||||
"orb_busstop_dim" => "models/orb_busstop_dim.glb#Scene0",
|
||||
"MeteorAceGT" => "models/MeteorAceGT.glb#Scene0",
|
||||
"satellite" => "models/satellite.glb#Scene0",
|
||||
"pizzeria" => "models/pizzeria2.glb#Scene0",
|
||||
"pizzasign" => "models/pizzasign.glb#Scene0",
|
||||
"selectagon" => "models/selectagon.glb#Scene0",
|
||||
"orbitring" => "models/orbitring.glb#Scene0",
|
||||
"clippy" => "models/clippy/clippy.glb#Scene0",
|
||||
"clippy_ar" => "models/clippy/ar_happy.glb#Scene0",
|
||||
"whale" => "models/whale.glb#Scene0",
|
||||
"point_of_interest" => "models/point_of_interest.glb#Scene0",
|
||||
_ => "models/error.glb#Scene0",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn skeleton_name_to_skeletondef(name: &str) -> Option<SkeletonDef> {
|
||||
// x: positive: left, negative: right
|
||||
// y: positive: upward, negative: downward
|
||||
// z: positive: forward, negative: backward
|
||||
match name {
|
||||
"suitv1" => Some(SkeletonDef::Human(HumanDef {
|
||||
collider: "models/suit_v1/collider.glb#Scene0".into(),
|
||||
base: "models/suit_v1/base.glb#Scene0".into(),
|
||||
limbs: vec![
|
||||
LimbDef {
|
||||
class: Limb::Head,
|
||||
path: "models/suit_v1/head.glb#Scene0".into(),
|
||||
pos: Vec3::new(0.0, 0.46, 0.0),
|
||||
..default()
|
||||
},
|
||||
LimbDef {
|
||||
class: Limb::UpperArmLeft,
|
||||
path: "models/suit_v1/upper_arm.glb#Scene0".into(),
|
||||
pos: Vec3::new(0.22, 0.3, 0.0),
|
||||
mirror: true,
|
||||
children: vec![LimbDef {
|
||||
class: Limb::LowerArmLeft,
|
||||
path: "models/suit_v1/lower_arm.glb#Scene0".into(),
|
||||
pos: Vec3::new(-0.33, 0.0, 0.0),
|
||||
..default()
|
||||
}],
|
||||
..default()
|
||||
},
|
||||
LimbDef {
|
||||
class: Limb::UpperArmRight,
|
||||
path: "models/suit_v1/upper_arm.glb#Scene0".into(),
|
||||
pos: Vec3::new(-0.22, 0.3, 0.0),
|
||||
children: vec![LimbDef {
|
||||
class: Limb::LowerArmRight,
|
||||
path: "models/suit_v1/lower_arm.glb#Scene0".into(),
|
||||
pos: Vec3::new(-0.33, 0.0, 0.0),
|
||||
..default()
|
||||
}],
|
||||
..default()
|
||||
},
|
||||
LimbDef {
|
||||
class: Limb::UpperLegLeft,
|
||||
path: "models/suit_v1/upper_leg.glb#Scene0".into(),
|
||||
pos: Vec3::new(0.15, -0.25, 0.1),
|
||||
mirror: true,
|
||||
children: vec![LimbDef {
|
||||
class: Limb::LowerLegLeft,
|
||||
path: "models/suit_v1/lower_leg.glb#Scene0".into(),
|
||||
pos: Vec3::new(0.0, -0.3, 0.0),
|
||||
..default()
|
||||
}],
|
||||
..default()
|
||||
},
|
||||
LimbDef {
|
||||
class: Limb::UpperLegRight,
|
||||
path: "models/suit_v1/upper_leg.glb#Scene0".into(),
|
||||
pos: Vec3::new(-0.15, -0.25, 0.1),
|
||||
children: vec![LimbDef {
|
||||
class: Limb::LowerLegRight,
|
||||
path: "models/suit_v1/lower_leg.glb#Scene0".into(),
|
||||
pos: Vec3::new(0.0, -0.3, 0.0),
|
||||
..default()
|
||||
}],
|
||||
..default()
|
||||
},
|
||||
],
|
||||
})),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Component)] pub struct SkeletonLimb;
|
||||
#[derive(Component)] pub struct MirroredLimb;
|
||||
pub enum SkeletonDef {
|
||||
Human(HumanDef)
|
||||
}
|
||||
|
||||
pub struct HumanDef {
|
||||
collider: String,
|
||||
base: String,
|
||||
limbs: Vec<LimbDef>,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct LimbDef {
|
||||
path: String,
|
||||
pos: Vec3,
|
||||
class: Limb,
|
||||
mirror: bool,
|
||||
children: Vec<LimbDef>,
|
||||
}
|
||||
|
||||
#[derive(Component, Default)]
|
||||
pub enum Limb {
|
||||
#[default]
|
||||
Base,
|
||||
Head,
|
||||
UpperArmRight,
|
||||
UpperArmLeft,
|
||||
LowerArmRight,
|
||||
LowerArmLeft,
|
||||
UpperLegRight,
|
||||
UpperLegLeft,
|
||||
LowerLegRight,
|
||||
LowerLegLeft,
|
||||
}
|
||||
|
||||
#[derive(Component)]
|
||||
pub enum Animation {
|
||||
HumanFloat,
|
||||
}
|
||||
|
||||
pub fn load(
|
||||
name: &str,
|
||||
entity_commands: &mut EntityCommands,
|
||||
asset_server: &AssetServer,
|
||||
) {
|
||||
if let Some(skel) = skeleton_name_to_skeletondef(name) {
|
||||
match skel {
|
||||
SkeletonDef::Human(human) => {
|
||||
entity_commands.insert(load_scene_by_path(human.collider.as_str(), asset_server));
|
||||
entity_commands.with_children(|parent| {
|
||||
parent.spawn((
|
||||
Limb::Base,
|
||||
Animation::HumanFloat,
|
||||
world::DespawnOnPlayerDeath,
|
||||
SceneBundle {
|
||||
scene: load_scene_by_path(human.base.as_str(), asset_server),
|
||||
..default()
|
||||
}
|
||||
));
|
||||
for limb in human.limbs {
|
||||
let rot = if limb.mirror {
|
||||
Quat::from_rotation_y(180.0f32.to_radians())
|
||||
} else {
|
||||
Quat::IDENTITY
|
||||
};
|
||||
let mut parent_limb = parent.spawn((
|
||||
limb.class,
|
||||
Animation::HumanFloat,
|
||||
world::DespawnOnPlayerDeath,
|
||||
SceneBundle {
|
||||
scene: load_scene_by_path(limb.path.as_str(), asset_server),
|
||||
transform: Transform::from_translation(limb.pos).with_rotation(rot),
|
||||
..default()
|
||||
}
|
||||
));
|
||||
if limb.mirror {
|
||||
parent_limb.insert(MirroredLimb);
|
||||
}
|
||||
if !limb.children.is_empty() {
|
||||
parent_limb.with_children(|parent| {
|
||||
for child_limb in limb.children {
|
||||
let rot = if child_limb.mirror {
|
||||
Quat::from_rotation_y(180.0f32.to_radians())
|
||||
} else {
|
||||
Quat::IDENTITY
|
||||
};
|
||||
let mut entity_commands = parent.spawn((
|
||||
child_limb.class,
|
||||
Animation::HumanFloat,
|
||||
world::DespawnOnPlayerDeath,
|
||||
SceneBundle {
|
||||
scene: load_scene_by_path(child_limb.path.as_str(), asset_server),
|
||||
transform: Transform::from_translation(child_limb.pos).with_rotation(rot),
|
||||
..default()
|
||||
}
|
||||
));
|
||||
if child_limb.mirror {
|
||||
entity_commands.insert(MirroredLimb);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
} else {
|
||||
entity_commands.insert(load_scene_by_path(asset_name_to_path(name), asset_server));
|
||||
}
|
||||
}
|
||||
|
||||
//pub fn load_scene(
|
||||
// path: &str,
|
||||
// asset_server: &AssetServer
|
||||
//) -> Handle<Scene> {
|
||||
// load_scene_by_path(asset_name_to_path(path), asset_server)
|
||||
//}
|
||||
|
||||
#[inline]
|
||||
pub fn load_scene_by_path(
|
||||
path: &str,
|
||||
asset_server: &AssetServer
|
||||
) -> Handle<Scene> {
|
||||
let path_string = path.to_string();
|
||||
if let Some(handle) = asset_server.get_handle(&path_string) {
|
||||
handle
|
||||
} else {
|
||||
asset_server.load(&path_string)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn _build_body(
|
||||
_name: String,
|
||||
mut _entity_commands: EntityCommands,
|
||||
) {
|
||||
}
|
||||
|
||||
pub fn animate_skeleton_parts(
|
||||
time: Res<Time>,
|
||||
mut q_limb: Query<(&mut Transform, &Limb, &Animation, Option<&MirroredLimb>)>,
|
||||
) {
|
||||
let t = time.elapsed_seconds();
|
||||
for (mut trans, limb, animation, mirror) in &mut q_limb {
|
||||
let mirror = mirror.is_some();
|
||||
match animation {
|
||||
Animation::HumanFloat =>
|
||||
animate_human_float(&mut trans, &limb, mirror, t),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn rot(trans: &mut Transform, x: f32, y: f32, z: f32) {
|
||||
trans.rotation = Quat::from_euler(
|
||||
EulerRot::XYZ,
|
||||
x.to_radians(),
|
||||
y.to_radians(),
|
||||
z.to_radians()
|
||||
);
|
||||
}
|
||||
|
||||
pub fn animate_human_float(mut trans: &mut Transform, limb: &Limb, mirror: bool, t: f32) {
|
||||
// x: lean head forward/backward
|
||||
// y: close/open arms together in front of the torso
|
||||
// z: spread legs sidewards
|
||||
let m = {|angle| if mirror { 180f32 + angle } else { angle }};
|
||||
match limb {
|
||||
Limb::UpperArmRight => rot(&mut trans,
|
||||
0.0,
|
||||
m(40.0 + 5.0 * (t * 0.5).sin()),
|
||||
20.0 + 10.0 * (t * 0.5).sin(),
|
||||
),
|
||||
Limb::UpperArmLeft => rot(&mut trans,
|
||||
0.0,
|
||||
m(-(40.0 + 5.0 * (t * 0.5).sin())),
|
||||
20.0 + 10.0 * (t * 0.5).sin(),
|
||||
),
|
||||
Limb::LowerArmRight => rot(&mut trans,
|
||||
0.0,
|
||||
m(20.0),
|
||||
-20.0,
|
||||
),
|
||||
Limb::LowerArmLeft => rot(&mut trans,
|
||||
0.0,
|
||||
m(-20.0),
|
||||
-20.0,
|
||||
),
|
||||
Limb::UpperLegRight => rot(&mut trans,
|
||||
-30.0 + 10.0 * (t * 0.5).sin(),
|
||||
0.0,
|
||||
-20.0 + 2.5 * (t * 0.5).cos(),
|
||||
),
|
||||
Limb::UpperLegLeft => rot(&mut trans,
|
||||
-30.0 + 10.0 * (t * 0.5).sin(),
|
||||
0.0,
|
||||
20.0 - 2.5 * (t * 0.5).cos(),
|
||||
),
|
||||
Limb::LowerLegRight => rot(&mut trans,
|
||||
35.0 + 5.0 * (t * 0.5).sin(),
|
||||
0.0,
|
||||
0.0,
|
||||
),
|
||||
Limb::LowerLegLeft => rot(&mut trans,
|
||||
35.0 + 5.0 * (t * 0.5).sin(),
|
||||
0.0,
|
||||
0.0,
|
||||
),
|
||||
_ => {},
|
||||
}
|
||||
}
|
13
src/var.rs
13
src/var.rs
|
@ -1,3 +1,16 @@
|
|||
// ▄████████▄ + ███ + ▄█████████ ███ +
|
||||
// ███▀ ▀███ + + ███ ███▀ + ███ + +
|
||||
// ███ + ███ ███ ███ █████████ ███ ███ ███ ███
|
||||
// ███ +███ ███ ███ ███ ███▐██████ ███ ███ ███
|
||||
// ███ + ███ ███+ ███ +███ ███ + ███ ███ + ███
|
||||
// ███▄ ▄███ ███▄ ███ ███ + ███ + ███ ███▄ ███
|
||||
// ▀████████▀ + ▀███████ ███▄ ███▄ ▀████ ▀███████
|
||||
// + + + ███
|
||||
// + ▀████████████████████████████████████████████████████▀
|
||||
//
|
||||
// This module manages variables, settings, as well as evaluating
|
||||
// "if"-conditions in chats.
|
||||
|
||||
use bevy::prelude::*;
|
||||
use std::collections::HashMap;
|
||||
use std::env;
|
||||
|
|
179
src/world.rs
179
src/world.rs
|
@ -1,10 +1,21 @@
|
|||
use crate::{actor, audio, hud, nature, shading, var};
|
||||
// ▄████████▄ + ███ + ▄█████████ ███ +
|
||||
// ███▀ ▀███ + + ███ ███▀ + ███ + +
|
||||
// ███ + ███ ███ ███ █████████ ███ ███ ███ ███
|
||||
// ███ +███ ███ ███ ███ ███▐██████ ███ ███ ███
|
||||
// ███ + ███ ███+ ███ +███ ███ + ███ ███ + ███
|
||||
// ███▄ ▄███ ███▄ ███ ███ + ███ + ███ ███▄ ███
|
||||
// ▀████████▀ + ▀███████ ███▄ ███▄ ▀████ ▀███████
|
||||
// + + + ███
|
||||
// + ▀████████████████████████████████████████████████████▀
|
||||
//
|
||||
// This module populates the world with stars and asteroids.
|
||||
|
||||
use crate::{actor, hud, nature, shading, skeleton};
|
||||
use bevy::prelude::*;
|
||||
use bevy::math::{DVec3, I64Vec3};
|
||||
use bevy::scene::{InstanceId, SceneInstance};
|
||||
use bevy::render::mesh::Indices;
|
||||
use bevy_xpbd_3d::prelude::*;
|
||||
use bevy_xpbd_3d::plugins::sync;
|
||||
use std::collections::HashMap;
|
||||
use std::f32::consts::PI;
|
||||
use fastrand;
|
||||
|
@ -14,44 +25,18 @@ const ASTEROID_SIZE_FACTOR: f32 = 10.0;
|
|||
const RING_THICKNESS: f64 = 8.0e6;
|
||||
const STARS_MAX_MAGNITUDE: f32 = 5.5; // max 7.0, see generate_starchart.py
|
||||
|
||||
const CENTER_WORLD_ON_PLAYER: bool = true;
|
||||
const SKYBOX: bool = false;
|
||||
|
||||
const ASTEROID_SPAWN_STEP: f64 = 500.0;
|
||||
const ASTEROID_VIEW_RADIUS: f64 = 3000.0;
|
||||
|
||||
const ASSET_ASTEROID1: &str = "models/asteroid.glb#Scene0";
|
||||
const ASSET_ASTEROID2: &str = "models/asteroid2.glb#Scene0";
|
||||
pub fn asset_name_to_path(name: &str) -> &'static str {
|
||||
match name {
|
||||
"suit" => "models/suit_with_collider.glb#Scene0",
|
||||
"suit_ar_chefhat" => "models/suit_ar_chefhat.glb#Scene0",
|
||||
"asteroid1" => ASSET_ASTEROID1,
|
||||
"asteroid2" => ASSET_ASTEROID2,
|
||||
"asteroid_lum" => "models/asteroid_lum.glb#Scene0",
|
||||
"moonlet" => "models/moonlet.glb#Scene0",
|
||||
"monolith" => "models/monolith_neon.glb#Scene0",
|
||||
"lightorb" => "models/lightorb.glb#Scene0",
|
||||
"orb_busstop" => "models/orb_busstop.glb#Scene0",
|
||||
"orb_busstop_dim" => "models/orb_busstop_dim.glb#Scene0",
|
||||
"MeteorAceGT" => "models/MeteorAceGT.glb#Scene0",
|
||||
"satellite" => "models/satellite.glb#Scene0",
|
||||
"pizzeria" => "models/pizzeria2.glb#Scene0",
|
||||
"pizzasign" => "models/pizzasign.glb#Scene0",
|
||||
"selectagon" => "models/selectagon.glb#Scene0",
|
||||
"orbitring" => "models/orbitring.glb#Scene0",
|
||||
"clippy" => "models/clippy.glb#Scene0",
|
||||
"clippy_ar" => "models/clippy_ar.glb#Scene0",
|
||||
"whale" => "models/whale.glb#Scene0",
|
||||
_ => "models/error.glb#Scene0",
|
||||
}
|
||||
}
|
||||
const ASSET_NAME_ASTEROID1: &str = "asteroid1";
|
||||
const ASSET_NAME_ASTEROID2: &str = "asteroid2";
|
||||
|
||||
pub struct WorldPlugin;
|
||||
impl Plugin for WorldPlugin {
|
||||
fn build(&self, app: &mut App) {
|
||||
app.add_systems(Startup, setup);
|
||||
app.add_systems(Update, handle_cheats);
|
||||
app.add_systems(PostUpdate, handle_despawn);
|
||||
app.add_systems(Update, spawn_despawn_asteroids);
|
||||
app.add_plugins(PhysicsPlugins::default());
|
||||
|
@ -61,18 +46,6 @@ impl Plugin for WorldPlugin {
|
|||
Timer::from_seconds(ASTEROID_UPDATE_INTERVAL, TimerMode::Repeating)));
|
||||
app.insert_resource(ActiveAsteroids(HashMap::new()));
|
||||
app.add_event::<DespawnEvent>();
|
||||
|
||||
if CENTER_WORLD_ON_PLAYER {
|
||||
// Disable bevy_xpbd's position->transform sync function
|
||||
app.insert_resource(sync::SyncConfig {
|
||||
position_to_transform: true,
|
||||
transform_to_position: false,
|
||||
});
|
||||
// Add own position->transform sync function
|
||||
app.add_systems(PostUpdate, position_to_transform
|
||||
.after(sync::position_to_transform)
|
||||
.in_set(sync::SyncSet::PositionToTransform));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -104,12 +77,7 @@ pub fn setup(
|
|||
mut meshes: ResMut<Assets<Mesh>>,
|
||||
mut materials: ResMut<Assets<StandardMaterial>>,
|
||||
mut materials_skybox: ResMut<Assets<shading::SkyBox>>,
|
||||
asset_server: Res<AssetServer>,
|
||||
) {
|
||||
// Load assets
|
||||
commands.insert_resource(AsteroidModel1(asset_server.load(ASSET_ASTEROID1)));
|
||||
commands.insert_resource(AsteroidModel2(asset_server.load(ASSET_ASTEROID2)));
|
||||
|
||||
// Generate starmap
|
||||
let sphere_handle = meshes.add(Sphere::new(1.0).mesh().uv(16, 16));
|
||||
let mut starcount = 0;
|
||||
|
@ -204,11 +172,10 @@ fn spawn_despawn_asteroids(
|
|||
q_player: Query<&Position, With<actor::PlayerCamera>>,
|
||||
mut ew_despawn: EventWriter<DespawnEvent>,
|
||||
mut db: ResMut<ActiveAsteroids>,
|
||||
asteroid1_handle: Res<AsteroidModel1>,
|
||||
asteroid2_handle: Res<AsteroidModel2>,
|
||||
mut q_asteroid: Query<(Entity, &SceneInstance), With<Asteroid>>,
|
||||
mut last_player_cell: Local<I64Vec3>,
|
||||
id2pos: Res<actor::Id2Pos>,
|
||||
asset_server: Res<AssetServer>,
|
||||
) {
|
||||
if !timer.0.tick(time.delta()).just_finished() || q_player.is_empty() {
|
||||
//if q_player.is_empty() {
|
||||
|
@ -345,17 +312,17 @@ fn spawn_despawn_asteroids(
|
|||
DespawnOnPlayerDeath,
|
||||
));
|
||||
let model = match class {
|
||||
0 => asteroid1_handle.0.clone(),
|
||||
_ => asteroid2_handle.0.clone(),
|
||||
0 => ASSET_NAME_ASTEROID1,
|
||||
_ => ASSET_NAME_ASTEROID2,
|
||||
};
|
||||
entity_commands.insert(SceneBundle {
|
||||
scene: model,
|
||||
entity_commands.insert(SpatialBundle {
|
||||
transform: Transform {
|
||||
scale: Vec3::splat(size),
|
||||
..default()
|
||||
},
|
||||
..default()
|
||||
});
|
||||
skeleton::load(model, &mut entity_commands, &*asset_server);
|
||||
db.0.insert(origin, AsteroidData {
|
||||
entity: entity_commands.id(),
|
||||
//viewdistance: 99999999.0,
|
||||
|
@ -377,109 +344,3 @@ fn handle_despawn(
|
|||
db.0.remove(&despawn.origin);
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_cheats(
|
||||
key_input: Res<ButtonInput<KeyCode>>,
|
||||
mut q_player: Query<(&Transform, &mut Position, &mut LinearVelocity), With<actor::PlayerCamera>>,
|
||||
mut q_life: Query<(&mut actor::LifeForm, &mut actor::ExperiencesGForce), With<actor::Player>>,
|
||||
q_target: Query<(&Transform, &Position, &LinearVelocity), (With<hud::IsTargeted>, Without<actor::PlayerCamera>)>,
|
||||
mut ew_playerdies: EventWriter<actor::PlayerDiesEvent>,
|
||||
mut settings: ResMut<var::Settings>,
|
||||
id2pos: Res<actor::Id2Pos>,
|
||||
mut ew_sfx: EventWriter<audio::PlaySfxEvent>,
|
||||
) {
|
||||
if q_player.is_empty() || q_life.is_empty() {
|
||||
return;
|
||||
}
|
||||
let (trans, mut pos, mut v) = q_player.get_single_mut().unwrap();
|
||||
let (mut lifeform, mut gforce) = q_life.get_single_mut().unwrap();
|
||||
let boost = if key_input.pressed(KeyCode::ShiftLeft) {
|
||||
1e6
|
||||
} else {
|
||||
1e3
|
||||
};
|
||||
if key_input.just_pressed(settings.key_cheat_god_mode) {
|
||||
settings.god_mode ^= true;
|
||||
if settings.god_mode {
|
||||
ew_sfx.send(audio::PlaySfxEvent(audio::Sfx::EnterVehicle));
|
||||
}
|
||||
}
|
||||
if !settings.god_mode && !settings.dev_mode {
|
||||
return;
|
||||
}
|
||||
|
||||
if key_input.just_pressed(settings.key_cheat_stop) {
|
||||
gforce.ignore_gforce_seconds = 1.0;
|
||||
v.0 = DVec3::ZERO;
|
||||
}
|
||||
if key_input.pressed(settings.key_cheat_speed) {
|
||||
gforce.ignore_gforce_seconds = 1.0;
|
||||
v.0 += DVec3::from(trans.rotation * Vec3::new(0.0, 0.0, boost));
|
||||
}
|
||||
if key_input.pressed(settings.key_cheat_speed_backward) {
|
||||
gforce.ignore_gforce_seconds = 1.0;
|
||||
v.0 += DVec3::from(trans.rotation * Vec3::new(0.0, 0.0, -boost));
|
||||
}
|
||||
if key_input.just_pressed(settings.key_cheat_teleport) {
|
||||
if let Ok((transform, target_pos, target_v)) = q_target.get_single() {
|
||||
let offset: DVec3 = 4.0 * (**pos - **target_pos).normalize() * transform.scale.as_dvec3();
|
||||
pos.0 = **target_pos + offset;
|
||||
*v = target_v.clone();
|
||||
}
|
||||
}
|
||||
|
||||
if !settings.dev_mode {
|
||||
return;
|
||||
}
|
||||
|
||||
if key_input.just_pressed(settings.key_cheat_pizza) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
if key_input.just_pressed(settings.key_cheat_farview1) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
if key_input.just_pressed(settings.key_cheat_farview2) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
if key_input.pressed(settings.key_cheat_adrenaline_zero) {
|
||||
lifeform.adrenaline = 0.0;
|
||||
}
|
||||
if key_input.pressed(settings.key_cheat_adrenaline_mid) {
|
||||
lifeform.adrenaline = 0.5;
|
||||
}
|
||||
if key_input.pressed(settings.key_cheat_adrenaline_max) {
|
||||
lifeform.adrenaline = 1.0;
|
||||
}
|
||||
if key_input.just_pressed(settings.key_cheat_die) {
|
||||
settings.god_mode = false;
|
||||
ew_playerdies.send(actor::PlayerDiesEvent(actor::DamageType::Trauma));
|
||||
}
|
||||
}
|
||||
|
||||
// An extension of bevy_xpbd_3d::plugins::position_to_transform that adjusts
|
||||
// the rendering position to center entities at the player camera.
|
||||
// This avoids rendering glitches when very far away from the origin.
|
||||
pub fn position_to_transform(
|
||||
q_player: Query<&Position, With<actor::PlayerCamera>>,
|
||||
mut q_trans: Query<(&'static mut Transform, &'static Position, &'static Rotation), Without<Parent>>,
|
||||
) {
|
||||
if let Ok(player_pos) = q_player.get_single() {
|
||||
for (mut transform, pos, rot) in &mut q_trans {
|
||||
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