use observable collision events
to simplify key/head_drop collecting
This commit is contained in:
@@ -4,7 +4,10 @@ use crate::{
|
|||||||
squish_animation::SquishAnimation, tb_entities::SecretHead,
|
squish_animation::SquishAnimation, tb_entities::SecretHead,
|
||||||
};
|
};
|
||||||
use avian3d::prelude::*;
|
use avian3d::prelude::*;
|
||||||
use bevy::prelude::*;
|
use bevy::{
|
||||||
|
ecs::{relationship::RelatedSpawner, spawn::SpawnWith},
|
||||||
|
prelude::*,
|
||||||
|
};
|
||||||
use std::f32::consts::PI;
|
use std::f32::consts::PI;
|
||||||
|
|
||||||
#[derive(Event, Reflect)]
|
#[derive(Event, Reflect)]
|
||||||
@@ -44,7 +47,6 @@ struct SecretHeadMarker;
|
|||||||
pub struct HeadCollected(pub usize);
|
pub struct HeadCollected(pub usize);
|
||||||
|
|
||||||
pub fn plugin(app: &mut App) {
|
pub fn plugin(app: &mut App) {
|
||||||
app.add_systems(Update, collect_head.run_if(in_state(GameState::Playing)));
|
|
||||||
app.add_systems(OnEnter(GameState::Playing), spawn);
|
app.add_systems(OnEnter(GameState::Playing), spawn);
|
||||||
|
|
||||||
global_observer!(app, on_head_drop);
|
global_observer!(app, on_head_drop);
|
||||||
@@ -85,6 +87,8 @@ fn on_head_drop(
|
|||||||
}
|
}
|
||||||
.ok_or("asset not found")?;
|
.ok_or("asset not found")?;
|
||||||
|
|
||||||
|
let head_id = drop.head_id;
|
||||||
|
|
||||||
commands
|
commands
|
||||||
.spawn((
|
.spawn((
|
||||||
Name::new("headdrop"),
|
Name::new("headdrop"),
|
||||||
@@ -97,15 +101,18 @@ fn on_head_drop(
|
|||||||
GameLayer::CollectiblePhysics,
|
GameLayer::CollectiblePhysics,
|
||||||
LayerMask::ALL & !GameLayer::Player.to_bits(),
|
LayerMask::ALL & !GameLayer::Player.to_bits(),
|
||||||
),
|
),
|
||||||
CollisionEventsEnabled,
|
|
||||||
Restitution::new(0.6),
|
Restitution::new(0.6),
|
||||||
children![(
|
Children::spawn(SpawnWith(move |parent: &mut RelatedSpawner<ChildOf>| {
|
||||||
|
parent
|
||||||
|
.spawn((
|
||||||
Collider::sphere(1.5),
|
Collider::sphere(1.5),
|
||||||
CollisionLayers::new(GameLayer::CollectibleSensors, GameLayer::Player),
|
CollisionLayers::new(GameLayer::CollectibleSensors, GameLayer::Player),
|
||||||
Sensor,
|
Sensor,
|
||||||
CollisionEventsEnabled,
|
CollisionEventsEnabled,
|
||||||
HeadDrop(drop.head_id),
|
HeadDrop(head_id),
|
||||||
)],
|
))
|
||||||
|
.observe(on_collect_head);
|
||||||
|
})),
|
||||||
))
|
))
|
||||||
.insert_if(
|
.insert_if(
|
||||||
ExternalImpulse::new(spawn_dir * 180.).with_persistence(false),
|
ExternalImpulse::new(spawn_dir * 180.).with_persistence(false),
|
||||||
@@ -120,23 +127,18 @@ fn on_head_drop(
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn collect_head(
|
fn on_collect_head(
|
||||||
|
trigger: Trigger<OnCollisionStart>,
|
||||||
mut commands: Commands,
|
mut commands: Commands,
|
||||||
mut collision_event_reader: EventReader<CollisionStarted>,
|
|
||||||
query_player: Query<&Player>,
|
query_player: Query<&Player>,
|
||||||
query_collectable: Query<(&HeadDrop, &ChildOf)>,
|
query_collectable: Query<(&HeadDrop, &ChildOf)>,
|
||||||
query_secret: Query<&SecretHeadMarker>,
|
query_secret: Query<&SecretHeadMarker>,
|
||||||
) {
|
) {
|
||||||
for CollisionStarted(e1, e2) in collision_event_reader.read() {
|
let collectable = trigger.target();
|
||||||
let collectable = if query_player.contains(*e1) && query_collectable.contains(*e2) {
|
let collider = trigger.collider;
|
||||||
*e2
|
|
||||||
} else if query_player.contains(*e2) && query_collectable.contains(*e1) {
|
|
||||||
*e1
|
|
||||||
} else {
|
|
||||||
continue;
|
|
||||||
};
|
|
||||||
|
|
||||||
let (key, child_of) = query_collectable.get(collectable).unwrap();
|
if query_player.contains(collider) {
|
||||||
|
let (drop, child_of) = query_collectable.get(collectable).unwrap();
|
||||||
|
|
||||||
let is_secret = query_secret.contains(collectable);
|
let is_secret = query_secret.contains(collectable);
|
||||||
|
|
||||||
@@ -145,7 +147,8 @@ fn collect_head(
|
|||||||
} else {
|
} else {
|
||||||
commands.trigger(PlaySound::HeadCollect);
|
commands.trigger(PlaySound::HeadCollect);
|
||||||
}
|
}
|
||||||
commands.trigger(HeadCollected(key.0));
|
|
||||||
|
commands.trigger(HeadCollected(drop.0));
|
||||||
commands.entity(child_of.parent()).despawn();
|
commands.entity(child_of.parent()).despawn();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
50
src/keys.rs
50
src/keys.rs
@@ -1,10 +1,12 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
GameState, billboards::Billboard, global_observer, loading_assets::GameAssets,
|
billboards::Billboard, global_observer, loading_assets::GameAssets, physics_layers::GameLayer,
|
||||||
physics_layers::GameLayer, player::Player, sounds::PlaySound,
|
player::Player, sounds::PlaySound, squish_animation::SquishAnimation,
|
||||||
squish_animation::SquishAnimation,
|
|
||||||
};
|
};
|
||||||
use avian3d::prelude::*;
|
use avian3d::prelude::*;
|
||||||
use bevy::prelude::*;
|
use bevy::{
|
||||||
|
ecs::{relationship::RelatedSpawner, spawn::SpawnWith},
|
||||||
|
prelude::*,
|
||||||
|
};
|
||||||
use std::f32::consts::PI;
|
use std::f32::consts::PI;
|
||||||
|
|
||||||
#[derive(Event, Reflect)]
|
#[derive(Event, Reflect)]
|
||||||
@@ -18,14 +20,14 @@ struct Key(pub String);
|
|||||||
pub struct KeyCollected(pub String);
|
pub struct KeyCollected(pub String);
|
||||||
|
|
||||||
pub fn plugin(app: &mut App) {
|
pub fn plugin(app: &mut App) {
|
||||||
app.add_systems(Update, collect_key.run_if(in_state(GameState::Playing)));
|
|
||||||
|
|
||||||
global_observer!(app, on_spawn_key);
|
global_observer!(app, on_spawn_key);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_spawn_key(trigger: Trigger<KeySpawn>, mut commands: Commands, assets: Res<GameAssets>) {
|
fn on_spawn_key(trigger: Trigger<KeySpawn>, mut commands: Commands, assets: Res<GameAssets>) {
|
||||||
let KeySpawn(position, id) = trigger.event();
|
let KeySpawn(position, id) = trigger.event();
|
||||||
|
|
||||||
|
let id = id.clone();
|
||||||
|
|
||||||
let angle = rand::random::<f32>() * PI * 2.;
|
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_dir = Quat::from_rotation_y(angle) * Vec3::new(0.5, 0.6, 0.).normalize();
|
||||||
|
|
||||||
@@ -38,41 +40,39 @@ fn on_spawn_key(trigger: Trigger<KeySpawn>, mut commands: Commands, assets: Res<
|
|||||||
LockedAxes::ROTATION_LOCKED,
|
LockedAxes::ROTATION_LOCKED,
|
||||||
RigidBody::Dynamic,
|
RigidBody::Dynamic,
|
||||||
CollisionLayers::new(GameLayer::CollectiblePhysics, GameLayer::Level),
|
CollisionLayers::new(GameLayer::CollectiblePhysics, GameLayer::Level),
|
||||||
CollisionEventsEnabled,
|
|
||||||
Restitution::new(0.6),
|
Restitution::new(0.6),
|
||||||
children![
|
Children::spawn((
|
||||||
(
|
Spawn((
|
||||||
Billboard,
|
Billboard,
|
||||||
SquishAnimation(2.6),
|
SquishAnimation(2.6),
|
||||||
SceneRoot(assets.mesh_key.clone()),
|
SceneRoot(assets.mesh_key.clone()),
|
||||||
),
|
)),
|
||||||
(
|
SpawnWith(|parent: &mut RelatedSpawner<ChildOf>| {
|
||||||
|
parent
|
||||||
|
.spawn((
|
||||||
Collider::sphere(1.5),
|
Collider::sphere(1.5),
|
||||||
CollisionLayers::new(GameLayer::CollectibleSensors, GameLayer::Player),
|
CollisionLayers::new(GameLayer::CollectibleSensors, GameLayer::Player),
|
||||||
Sensor,
|
Sensor,
|
||||||
CollisionEventsEnabled,
|
CollisionEventsEnabled,
|
||||||
Key(id.clone()),
|
Key(id),
|
||||||
)
|
))
|
||||||
],
|
.observe(on_collect_key);
|
||||||
|
}),
|
||||||
|
)),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn collect_key(
|
fn on_collect_key(
|
||||||
|
trigger: Trigger<OnCollisionStart>,
|
||||||
mut commands: Commands,
|
mut commands: Commands,
|
||||||
mut collision_event_reader: EventReader<CollisionStarted>,
|
|
||||||
query_player: Query<&Player>,
|
query_player: Query<&Player>,
|
||||||
query_collectable: Query<(&Key, &ChildOf)>,
|
query_collectable: Query<(&Key, &ChildOf)>,
|
||||||
) {
|
) {
|
||||||
for CollisionStarted(e1, e2) in collision_event_reader.read() {
|
let key = trigger.target();
|
||||||
let collectable = if query_player.contains(*e1) && query_collectable.contains(*e2) {
|
let collider = trigger.collider;
|
||||||
*e2
|
|
||||||
} else if query_player.contains(*e2) && query_collectable.contains(*e1) {
|
|
||||||
*e1
|
|
||||||
} else {
|
|
||||||
continue;
|
|
||||||
};
|
|
||||||
|
|
||||||
let (key, child_of) = query_collectable.get(collectable).unwrap();
|
if query_player.contains(collider) {
|
||||||
|
let (key, child_of) = query_collectable.get(key).unwrap();
|
||||||
|
|
||||||
commands.trigger(PlaySound::KeyCollect);
|
commands.trigger(PlaySound::KeyCollect);
|
||||||
commands.trigger(KeyCollected(key.0.clone()));
|
commands.trigger(KeyCollected(key.0.clone()));
|
||||||
|
|||||||
Reference in New Issue
Block a user