* Get bevy 0.17 compiling and running (#72) * get bevy 0.17 compiling and running * try to fix CI breaking from const assertion for client/server features * fix `bin` -> `lib` for `shared` in CI * typo * fix some collider issues (#73) * Physics/controller improvements (#74) * trying to fix physics prediction * fixed prediction desync * substantial controller improvements * Finish off main bevy 0.17 migration (#75) * fix lookdir issues - airplane moving backwards - player model facing backwards - camera was technically backwards the whole time, and player models were facing the right way; camera is now facing forwards - firing without a target now respects lookdir * fix aim targeting * migrate to bevy_trenchbroom 0.10 crates release * fixed colliders not being adjusted out of worldspace * predict platforms to stop constant rollbacks while riding them * fix key/head drop visuals not working * Fix key/head drop random initial force * fixed static head drops duplicating * fix platform velocity inheritance * fix thrown projectiles not autorotating * fix inconsistent explosion animations * update avian3d to 0.4.1 * fix controller snapping to fixed angle upon switching heads * clean up commented code * fix broken physics positions * Clean comments, fix warnings (#77) * clean comments, fix warnings * fix missing import * steamworks 162 libs * fix mouselook --------- Co-authored-by: extrawurst <mail@rusticorn.com>
116 lines
3.5 KiB
Rust
116 lines
3.5 KiB
Rust
use avian3d::prelude::*;
|
|
use bevy::{
|
|
ecs::{relationship::RelatedSpawner, spawn::SpawnWith},
|
|
prelude::*,
|
|
};
|
|
use lightyear::prelude::{NetworkTarget, Replicate};
|
|
use shared::{
|
|
global_observer,
|
|
head_drop::{HeadCollected, HeadDrop, HeadDropEnableTime, HeadDrops, SecretHeadMarker},
|
|
heads_database::HeadsDatabase,
|
|
physics_layers::GameLayer,
|
|
player::Player,
|
|
protocol::{GltfSceneRoot, PlaySound},
|
|
utils::{
|
|
billboards::Billboard, one_shot_force::OneShotForce, squish_animation::SquishAnimation,
|
|
},
|
|
};
|
|
use std::f32::consts::PI;
|
|
|
|
pub fn plugin(app: &mut App) {
|
|
global_observer!(app, on_head_drop);
|
|
}
|
|
|
|
fn on_head_drop(
|
|
trigger: On<HeadDrops>,
|
|
mut commands: Commands,
|
|
heads_db: Res<HeadsDatabase>,
|
|
time: Res<Time>,
|
|
) -> Result<(), BevyError> {
|
|
let drop = trigger.event();
|
|
let should_impulse = drop.impulse;
|
|
|
|
let angle = rand::random::<f32>() * PI * 2.;
|
|
let spawn_dir = Quat::from_rotation_y(angle) * Vec3::new(0.5, 0.6, 0.).normalize();
|
|
let spawn_force = if should_impulse {
|
|
spawn_dir * 180.0 / time.delta_secs()
|
|
} else {
|
|
Vec3::ZERO
|
|
};
|
|
|
|
if drop.impulse {
|
|
commands.trigger(PlaySound::HeadDrop);
|
|
}
|
|
|
|
let mesh_addr = format!("{:?}", heads_db.head_stats(drop.head_id).ability).to_lowercase();
|
|
|
|
commands
|
|
.spawn((
|
|
Name::new("headdrop"),
|
|
Transform::from_translation(drop.pos),
|
|
Visibility::default(),
|
|
Collider::sphere(1.5),
|
|
LockedAxes::ROTATION_LOCKED,
|
|
RigidBody::Dynamic,
|
|
OneShotForce(spawn_force),
|
|
CollisionLayers::new(
|
|
GameLayer::CollectiblePhysics,
|
|
LayerMask::ALL & !GameLayer::Player.to_bits(),
|
|
),
|
|
Restitution::new(0.6),
|
|
Children::spawn(SpawnWith({
|
|
let head_id = drop.head_id;
|
|
let now = time.elapsed_secs();
|
|
move |parent: &mut RelatedSpawner<ChildOf>| {
|
|
parent
|
|
.spawn((
|
|
Collider::sphere(1.5),
|
|
CollisionLayers::new(GameLayer::CollectibleSensors, LayerMask::NONE),
|
|
Sensor,
|
|
CollisionEventsEnabled,
|
|
HeadDrop { head_id },
|
|
HeadDropEnableTime(now + 1.2),
|
|
))
|
|
.observe(on_collect_head);
|
|
}
|
|
})),
|
|
Replicate::to_clients(NetworkTarget::All),
|
|
))
|
|
.with_child((
|
|
Billboard::All,
|
|
SquishAnimation(2.6),
|
|
GltfSceneRoot::HeadDrop(mesh_addr),
|
|
));
|
|
|
|
Ok(())
|
|
}
|
|
|
|
fn on_collect_head(
|
|
trigger: On<CollisionStart>,
|
|
mut commands: Commands,
|
|
query_player: Query<&Player>,
|
|
query_collectable: Query<(&HeadDrop, &ChildOf)>,
|
|
query_secret: Query<&SecretHeadMarker>,
|
|
) {
|
|
let collectable = trigger.event().collider1;
|
|
let collider = trigger.event().collider2;
|
|
|
|
if query_player.contains(collider) {
|
|
let (drop, child_of) = query_collectable.get(collectable).unwrap();
|
|
|
|
let is_secret = query_secret.contains(collectable);
|
|
|
|
if is_secret {
|
|
commands.trigger(PlaySound::SecretHeadCollect);
|
|
} else {
|
|
commands.trigger(PlaySound::HeadCollect);
|
|
}
|
|
|
|
commands.entity(collider).trigger(|entity| HeadCollected {
|
|
head: drop.head_id,
|
|
entity,
|
|
});
|
|
commands.entity(child_of.parent()).despawn();
|
|
}
|
|
}
|