Compare commits

...

22 commits

Author SHA1 Message Date
yuni 0f33b6e88e fix engine vector 2024-11-17 02:26:15 +01:00
yuni 04825f467d less jumpy gforce on acceleration 2024-11-17 02:24:26 +01:00
yuni 14991879c9 ghjfdhgdjgfdgjh 2024-11-17 02:13:09 +01:00
yuni d4c8ca231a WIP crisper camera controls (fix match velocity in vehicles) 2024-11-17 01:54:47 +01:00
yuni 0ea4c00151 cargo fmt 2024-11-17 01:44:53 +01:00
yuni bb95469f44 WIP crisper camera controls (fix slow acceleration (space+movement)) 2024-11-17 01:44:31 +01:00
yuni 35d9f0b4fd WIP crisper camera controls (fix gforce calculation) 2024-11-17 01:16:34 +01:00
yuni 6a82c185f2 WIP crisper camera controls (fix mouse sensitivity while zooming) 2024-11-17 01:14:13 +01:00
yuni a3f1f4bd73 WIP crisper camera controls (fix direction of thrust) 2024-11-17 01:10:39 +01:00
yuni 3a7ab8c9ac WIP crisper camera controls (fix rotation/accleration with vehicles) 2024-11-17 01:07:16 +01:00
yuni 2e35f90a19 WIP crisper camera controls (prevent overshooting when braking) 2024-11-17 01:07:16 +01:00
yuni 3cef44c4b2 WIP crisper camera controls (implement matching velocity) 2024-11-17 01:07:16 +01:00
yuni 51059a2856 WIP crisper camera controls (mouse rot relative instead of absolute) 2024-11-17 01:07:16 +01:00
yuni 86999574d1 WIP crisper camera controls (fix scaling of engine parameters) 2024-11-17 01:07:16 +01:00
yuni 8fcb702623 WIP crisper camera controls (add visual effects, engine parameters) 2024-11-17 01:07:16 +01:00
yuni 94bf21b340 WIP crisper camera controls (play engine sound) 2024-11-17 01:07:16 +01:00
yuni 06c2d90228 WIP crisper camera controls (apply acceleration) 2024-11-17 01:07:16 +01:00
yuni e8e81e8e52 WIP crisper camera controls (apply rotation) 2024-11-17 01:07:16 +01:00
yuni 8ea2d1fb21 fix mudley conversation 2024-11-17 01:07:04 +01:00
yuni d329d35396 workaround for player becoming hidden in menu 2024-11-15 21:47:22 +01:00
yuni 3ffcfcf522 remove NotShadowReceiver from AR avatars (looks more natural in dark) 2024-11-15 16:13:50 +01:00
yuni 495a45d8c4 tweak skirt 2024-11-15 16:13:29 +01:00
7 changed files with 489 additions and 20 deletions

Binary file not shown.

View file

@ -45,6 +45,20 @@
"metallicFactor":0.5158730149269104,
"roughnessFactor":0.841269850730896
}
},
{
"doubleSided":true,
"name":"Black",
"pbrMetallicRoughness":{
"baseColorFactor":[
0.016740795224905014,
0.016740795224905014,
0.016740795224905014,
1
],
"metallicFactor":0.8086956739425659,
"roughnessFactor":0.917391300201416
}
}
],
"meshes":[
@ -59,6 +73,15 @@
},
"indices":3,
"material":0
},
{
"attributes":{
"POSITION":4,
"NORMAL":5,
"TEXCOORD_0":6
},
"indices":7,
"material":1
}
]
}
@ -80,15 +103,15 @@
{
"bufferView":0,
"componentType":5126,
"count":2761,
"count":1826,
"max":[
0.44324639439582825,
0.14108650386333466,
0.4957937002182007
0.4851364195346832
],
"min":[
-0.44725117087364197,
-0.3539474904537201,
-0.34535348415374756,
-0.2795291841030121
],
"type":"VEC3"
@ -96,45 +119,103 @@
{
"bufferView":1,
"componentType":5126,
"count":2761,
"count":1826,
"type":"VEC3"
},
{
"bufferView":2,
"componentType":5126,
"count":2761,
"count":1826,
"type":"VEC2"
},
{
"bufferView":3,
"componentType":5123,
"count":15360,
"count":9984,
"type":"SCALAR"
},
{
"bufferView":4,
"componentType":5126,
"count":939,
"max":[
0.44324639439582825,
0.08284013718366623,
0.4957937002182007
],
"min":[
-0.44700509309768677,
-0.3539474904537201,
-0.20792187750339508
],
"type":"VEC3"
},
{
"bufferView":5,
"componentType":5126,
"count":939,
"type":"VEC3"
},
{
"bufferView":6,
"componentType":5126,
"count":939,
"type":"VEC2"
},
{
"bufferView":7,
"componentType":5123,
"count":5376,
"type":"SCALAR"
}
],
"bufferViews":[
{
"buffer":0,
"byteLength":33132,
"byteLength":21912,
"byteOffset":0,
"target":34962
},
{
"buffer":0,
"byteLength":33132,
"byteOffset":33132,
"byteLength":21912,
"byteOffset":21912,
"target":34962
},
{
"buffer":0,
"byteLength":22088,
"byteOffset":66264,
"byteLength":14608,
"byteOffset":43824,
"target":34962
},
{
"buffer":0,
"byteLength":30720,
"byteOffset":88352,
"byteLength":19968,
"byteOffset":58432,
"target":34963
},
{
"buffer":0,
"byteLength":11268,
"byteOffset":78400,
"target":34962
},
{
"buffer":0,
"byteLength":11268,
"byteOffset":89668,
"target":34962
},
{
"buffer":0,
"byteLength":7512,
"byteOffset":100936,
"target":34962
},
{
"buffer":0,
"byteLength":10752,
"byteOffset":108448,
"target":34963
}
],
@ -146,7 +227,7 @@
],
"buffers":[
{
"byteLength":119072,
"byteLength":119200,
"uri":"ar_skirt_tartan.bin"
}
]

View file

@ -17,6 +17,7 @@
use crate::prelude::*;
use bevy::prelude::*;
use bevy_xpbd_3d::prelude::*;
use std::collections::HashMap;
pub const ENGINE_SPEED_FACTOR: f32 = 30.0;
const MAX_TRANSMISSION_DISTANCE: f32 = 100.0;
@ -38,6 +39,7 @@ impl Plugin for ActorPlugin {
update_physics_lifeforms.run_if(game_running),
update_power.run_if(game_running),
handle_gravity.run_if(game_running),
handle_wants_rotation_change.run_if(game_running),
handle_wants_maxrotation.run_if(game_running),
handle_wants_maxvelocity
.run_if(game_running)
@ -45,12 +47,23 @@ impl Plugin for ActorPlugin {
handle_wants_lookat.run_if(game_running).run_if(alive),
),
);
app.add_systems(
PreUpdate,
handle_wants_acceleration
.run_if(game_running)
.run_if(alive)
.after(PhysicsSet::Sync)
.after(sync::position_to_transform),
);
app.add_systems(
PostUpdate,
handle_gforce
.run_if(game_running)
.run_if(alive)
.after(PhysicsSet::Sync)
.after(sync::position_to_transform),
.after(sync::position_to_transform)
.after(handle_wants_acceleration),
);
app.add_systems(
Update,
@ -149,6 +162,12 @@ impl Default for ExperiencesGForce {
}
}
#[derive(Component, Default)]
pub struct WantsAcceleration {
pub direction: DVec3,
pub brake: bool,
}
#[derive(Component)]
pub struct Player; // Attached to the suit of the player
#[derive(Component)]
@ -164,6 +183,8 @@ pub struct ActorEnteringVehicle;
#[derive(Component)]
pub struct ActorVehicleBeingEntered;
#[derive(Component)]
pub struct HiddenInsideVehicle;
#[derive(Component)]
pub struct MessageOnVehicleEntry(pub String);
#[derive(Component)]
pub struct PlayersFlashLight;
@ -176,6 +197,8 @@ pub struct WantsMaxVelocity(pub f64);
#[derive(Component)]
pub struct WantsToLookAt(pub String);
#[derive(Component)]
pub struct WantsRotationChange(pub Vec3); // Vec3 = (pitch, yaw, rot)
#[derive(Component)]
pub struct WantsMatchVelocityWith(pub String);
#[derive(Component)]
pub struct Identifier(pub String);
@ -220,7 +243,7 @@ pub enum EngineType {
Ion,
}
#[derive(Component)]
#[derive(Component, Copy, Clone)]
pub struct Engine {
pub thrust_forward: f32,
pub thrust_back: f32,
@ -575,11 +598,18 @@ pub fn handle_vehicle_enter_exit(
*driver_vis = Visibility::Hidden; //seems to have no effect...
ew_sfx.send(audio::PlaySfxEvent(audio::Sfx::EnterVehicle));
commands.entity(driver).remove::<PlayerCamera>();
commands.entity(driver).remove::<WantsRotationChange>();
commands.entity(driver).remove::<Collider>();
commands.entity(driver).remove::<WantsAcceleration>();
commands.entity(driver).insert(JustNowEnteredVehicle);
commands.entity(driver).insert(HiddenInsideVehicle);
commands
.entity(vehicle)
.insert(WantsAcceleration::default());
commands.entity(vehicle).remove::<hud::IsTargeted>();
commands.entity(vehicle).insert(PlayerCamera);
commands.entity(vehicle).insert(PlayerDrivesThis);
commands.entity(vehicle).insert(WantsMaxRotation(0.0));
if let Ok(mut flashlight_trans) = q_playerflashlight.get_single_mut() {
flashlight_trans.rotation = Quat::from_rotation_y(0f32);
flashlight_trans.translation = Vec3::new(0.0, 0.0, 0.0);
@ -599,11 +629,16 @@ pub fn handle_vehicle_enter_exit(
Quat::from_rotation_y(180f32.to_radians());
flashlight_trans.translation = Vec3::new(0.0, 0.0, 1.0);
}
commands.entity(driver).remove::<HiddenInsideVehicle>();
commands.entity(driver).insert(WantsAcceleration::default());
commands.entity(driver).insert(RigidBody::Dynamic);
ew_sfx.send(audio::PlaySfxEvent(audio::Sfx::ExitVehicle));
commands.entity(vehicle).remove::<WantsMaxRotation>();
commands.entity(vehicle).remove::<PlayerCamera>();
commands.entity(driver).insert(PlayerCamera);
commands.entity(vehicle).remove::<PlayerDrivesThis>();
commands.entity(vehicle).remove::<WantsAcceleration>();
commands.entity(vehicle).remove::<WantsRotationChange>();
*vehicle_vis = Visibility::Visible;
}
}
@ -703,6 +738,260 @@ fn handle_wants_maxvelocity(
}
}
fn handle_wants_rotation_change(mut q_actor: Query<(&mut Rotation, &mut WantsRotationChange)>) {
for (mut rot, mut change_rot) in &mut q_actor {
if change_rot.0 == Vec3::ZERO {
continue;
}
let actual_change_rot = change_rot.0.clamp_length_max(0.10);
for axis in 0..3 {
let original = change_rot.0[axis];
change_rot.0[axis] = 0.90 * change_rot.0[axis] - actual_change_rot[axis];
if original.signum() != change_rot.0[axis].signum() {
change_rot.0[axis] = 0.0;
}
}
let change = DQuat::from_euler(
EulerRot::XYZ,
actual_change_rot[0] as f64,
actual_change_rot[1] as f64,
actual_change_rot[2] as f64,
);
**rot = **rot * change;
}
}
fn handle_wants_acceleration(
time: Res<Time>,
settings: Res<var::Settings>,
jupiter_pos: Res<game::JupiterPos>,
q_audiosinks: Query<(&audio::Sfx, &AudioSink)>,
mut q_actor: Query<
(
Entity,
&Transform,
&Position,
&mut LinearVelocity,
Option<&mut Engine>,
Option<&WantsAcceleration>,
Option<&hud::IsTargeted>,
Option<&PlayerCamera>,
),
(Without<visual::IsEffect>, Without<HiddenInsideVehicle>),
>,
mut ew_effect: EventWriter<visual::SpawnEffectEvent>,
) {
let dt = time.delta_seconds();
// Vector elements: (Entity, is_player, pos)
let mut request_closest: Vec<(Entity, bool, DVec3)> = vec![];
let mut closest_map: HashMap<Entity, DVec3> = HashMap::new();
// First, determine whether any actor wants to brake (=match velocity)
for (entity, _, pos, _, _, accel, _, is_player) in &mut q_actor {
if accel.is_some() && accel.unwrap().brake {
request_closest.push((entity, is_player.is_some(), pos.0.clone()));
}
}
// If an actor is braking, find out relative to what it wants to brake
for (entity, is_player, pos) in &request_closest {
let mut target_v: Option<DVec3> = None;
// First, if this is the player, check whether they targeted anything
// so we can match velocity to the target.
if *is_player {
for (_, _, _, v, _, _, is_target, _) in &q_actor {
if is_target.is_some() {
target_v = Some(v.0);
break;
}
}
}
// If not, simply look for the closest object and match velocity to that.
if target_v.is_none() {
let mut closest_distance = camera::MAX_DIST_FOR_MATCH_VELOCITY;
for (testentity, _, testpos, v, _, _, _, _) in &q_actor {
if *entity != testentity {
let distance = (*pos - testpos.0).length();
if distance < closest_distance {
target_v = Some(v.0);
closest_distance = distance;
}
}
}
}
// Last resort: Match velocity to the orbital velocity around Jupiter
if target_v.is_none() {
let relative_pos = *pos - jupiter_pos.0;
target_v = Some(nature::orbital_velocity(relative_pos, nature::JUPITER_MASS));
}
if let Some(target_v) = target_v {
closest_map.insert(*entity, target_v);
}
}
// Finally, apply the requested acceleration to the actor's velocity
let mut play_thruster_sound = false;
let mut players_engine: Option<Engine> = None;
for (entity, trans, pos, mut v, engine, accel, _, is_player) in &mut q_actor {
let mut thruster_on = false;
if let (Some(mut engine), Some(accel)) = (engine, accel) {
let mut delta_v = DVec3::ZERO;
let mut allow_fullstop = false;
let boost = engine.current_boost_factor;
engine.currently_matching_velocity = false;
if accel.brake {
if let Some(target_v) = closest_map.get(&entity) {
let stop_direction = (*target_v - v.0).as_vec3();
if stop_direction.length_squared() > 0.003 {
delta_v =
(trans.rotation.inverse() * stop_direction.normalize()).as_dvec3();
engine.currently_matching_velocity = true;
thruster_on = true;
}
}
}
if accel.direction != DVec3::ZERO {
// Player is pressing AWSD keys
let brake_factor = if accel.brake { 1.10 } else { 1.0 };
delta_v += accel.direction.normalize() * brake_factor;
} else if accel.brake {
// Player is only pressing space
allow_fullstop = true;
}
if delta_v.length_squared() > 0.003 {
// Engine is firing!
thruster_on = true;
engine.current_warmup =
(engine.current_warmup + dt / engine.warmup_seconds).clamp(0.0, 1.0);
delta_v = delta_v.clamp(DVec3::splat(-1.0), DVec3::splat(1.0));
// Adjust acceleration to what the engine can actually provide
let factor_forward = if accel.direction.z > 0.0 {
engine.thrust_forward
} else {
engine.thrust_back
};
let factor_right = engine.thrust_sideways;
let factor_up = engine.thrust_sideways;
let engine_factor = Vec3::new(factor_right, factor_up, factor_forward).as_dvec3()
* engine.current_warmup as f64
* ENGINE_SPEED_FACTOR as f64
* engine.current_boost_factor;
let final_accel =
(trans.rotation * (delta_v * engine_factor).as_vec3() * dt).as_dvec3();
// Apply acceleration to velocity
if allow_fullstop {
if let Some(target_v) = closest_map.get(&entity) {
// Prevent overshooting when matching velocity, which
// would result in oscillating acceleration back and forth
for axis in 0..3 {
let original = v[axis];
let target = target_v[axis];
v[axis] += final_accel[axis];
if (original - target).signum() != (v[axis] - target).signum() {
v[axis] = target;
}
}
}
} else {
**v += final_accel;
}
// Visual effect
if engine.engine_type == EngineType::Monopropellant {
let thruster_direction = final_accel.normalize();
let thruster_pos = pos.0 - 0.3 * thruster_direction;
let thruster_v = v.0 - boost * 5.0 * thruster_direction;
ew_effect.send(visual::SpawnEffectEvent {
duration: 2.0,
class: visual::Effects::ThrusterParticle(
Position::from(thruster_pos),
LinearVelocity::from(thruster_v),
),
});
}
} else {
// Engine is not firing
engine.current_warmup =
(engine.current_warmup - dt / engine.warmup_seconds).clamp(0.0, 1.0);
}
if is_player.is_some() {
play_thruster_sound = thruster_on;
players_engine = Some((*engine).clone());
}
}
}
// Play sound effects for player acceleration
let engine = if let Some(engine) = players_engine {
engine
} else {
warn!("Failed to retrieve player's engine type for playing SFX");
Engine::default()
};
let mut sinks: HashMap<audio::Sfx, &AudioSink> = HashMap::new();
for (sfx, sink) in &q_audiosinks {
sinks.insert(*sfx, sink);
}
let sinks = vec![
(
1.0,
engine.current_boost_factor as f32,
actor::EngineType::Monopropellant,
sinks.get(&audio::Sfx::Thruster),
),
(
1.0,
1.0,
actor::EngineType::Ion,
sinks.get(&audio::Sfx::Ion),
),
];
let seconds_to_max_vol = 0.05;
let seconds_to_min_vol = 0.05;
for sink_data in sinks {
if let (vol_boost, speed, engine_type, Some(sink)) = sink_data {
if settings.mute_sfx {
sink.pause();
} else {
let volume = sink.volume();
let maxvol = settings.volume_sfx * vol_boost;
if engine.engine_type == engine_type {
if play_thruster_sound {
sink.set_speed(speed);
sink.play();
if volume < maxvol {
sink.set_volume((volume + dt / seconds_to_max_vol).clamp(0.0, maxvol));
}
} else {
sink.set_volume((volume - dt / seconds_to_min_vol).clamp(0.0, maxvol));
}
} else if volume > 0.0 {
sink.set_volume((volume - dt / seconds_to_min_vol).clamp(0.0, maxvol));
}
if volume < 0.0001 {
sink.pause();
}
}
}
}
}
fn handle_wants_lookat(
mut query: Query<
(

Binary file not shown.

View file

@ -80,7 +80,10 @@ impl Plugin for CameraPlugin {
app.add_systems(
PostUpdate,
position_to_transform
.run_if(game_running)
// The if(game_running) condition should be there, but
// somehow everything apart of AR avatars ends up becoming
// invisible if I leave it in, so for now, we leave it out.
//.run_if(game_running)
.after(sync::position_to_transform)
.in_set(sync::SyncSet::PositionToTransform),
);
@ -440,8 +443,103 @@ fn manage_player_actor(
}
}
#[allow(clippy::too_many_arguments)]
pub fn apply_input_to_player(
mut commands: Commands,
settings: Res<var::Settings>,
mut q_player: Query<
(
Entity,
&mut actor::WantsAcceleration,
Option<&mut actor::WantsRotationChange>,
),
With<actor::PlayerCamera>,
>,
mut mouse_events: EventReader<MouseMotion>,
key_input: Res<ButtonInput<KeyCode>>,
q_windows: Query<&Window, With<PrimaryWindow>>,
) {
let player = q_player.get_single_mut();
if player.is_err() {
return;
}
let (entity, mut accel, rot_change) = player.unwrap();
let (win_res_x, win_res_y): (f32, f32);
if let Ok(window) = &q_windows.get_single() {
win_res_x = window.resolution.width();
win_res_y = window.resolution.height();
} else {
win_res_x = 1920.0;
win_res_y = 1050.0;
}
// Determine rotation delta
let mut pitch_yaw_rot = Vec3::ZERO;
let mut mouse_delta = Vec2::ZERO;
for mouse_event in mouse_events.read() {
mouse_delta += mouse_event.delta;
}
if mouse_delta != Vec2::ZERO {
if key_input.pressed(settings.key_rotate) {
pitch_yaw_rot[2] += mouse_delta.x / win_res_x;
} else {
pitch_yaw_rot[0] += mouse_delta.y / win_res_y;
pitch_yaw_rot[1] -= mouse_delta.x / win_res_x;
}
}
pitch_yaw_rot *= 2.0
* if settings.is_zooming {
settings.zoom_sensitivity_factor
} else {
1.0
};
// Apply rotation to player
if pitch_yaw_rot != Vec3::ZERO {
let rot_change_current = if let Some(rot_change) = &rot_change {
rot_change.0
} else {
Vec3::ZERO
};
let rot_target = rot_change_current + pitch_yaw_rot;
if let Some(mut rot_change) = rot_change {
rot_change.0 = rot_target;
} else {
commands
.entity(entity)
.try_insert(actor::WantsRotationChange(rot_target));
}
}
// Determine acceleration
let mut axis_input: DVec3 = DVec3::ZERO;
if key_input.pressed(settings.key_forward) || settings.cruise_control_active {
axis_input.z += 1.0;
}
if key_input.pressed(settings.key_back) {
axis_input.z -= 1.0;
}
if key_input.pressed(settings.key_right) {
axis_input.x -= 1.0;
}
if key_input.pressed(settings.key_left) {
axis_input.x += 1.0;
}
if key_input.pressed(settings.key_up) {
axis_input.y += 1.0;
}
if key_input.pressed(settings.key_down) {
axis_input.y -= 1.0;
}
//axis_input = axis_input.clamp(DVec3::splat(-1.0), DVec3::splat(1.0));
// Apply acceleration to player
accel.direction = axis_input;
accel.brake = key_input.pressed(settings.key_stop);
}
#[allow(clippy::too_many_arguments)]
pub fn apply_input_to_player_old(
time: Res<Time>,
mut commands: Commands,
settings: Res<var::Settings>,

View file

@ -1126,7 +1126,7 @@
- Nothing native, anyway.
- That's all, thanks!:
- Cool, anything else you wanted?
- goto: pig_node_main
- goto: entrypoint
- goto: pig_node_geo
- if: $pig
You're pork! Yummy! I'm starving!:

View file

@ -1134,7 +1134,9 @@ fn spawn_entities(
if state.is_player {
actor.insert(actor::Player);
actor.insert(actor::PlayerCamera);
actor.insert(actor::WantsAcceleration::default());
actor.insert(hud::AugmentedRealityOverlayBroadcaster);
//actor.insert(actor::WantsRotation(Quat::IDENTITY));
ew_updateavatar.send(hud::UpdateAvatarEvent);
}
if state.is_sun {
@ -1313,7 +1315,6 @@ fn spawn_entities(
..default()
},
NotShadowCaster,
NotShadowReceiver,
));
load_asset(ar_asset_name.as_str(), &mut entitycmd, &*asset_server);
}