Player can loose head (#46)
This commit is contained in:
@@ -37,7 +37,13 @@ impl HeadDrops {
|
|||||||
|
|
||||||
#[derive(Component, Reflect)]
|
#[derive(Component, Reflect)]
|
||||||
#[reflect(Component)]
|
#[reflect(Component)]
|
||||||
struct HeadDrop(pub usize);
|
struct HeadDrop {
|
||||||
|
pub head_id: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Component, Reflect)]
|
||||||
|
#[reflect(Component)]
|
||||||
|
struct HeadDropEnableTime(f32);
|
||||||
|
|
||||||
#[derive(Component, Reflect)]
|
#[derive(Component, Reflect)]
|
||||||
#[reflect(Component)]
|
#[reflect(Component)]
|
||||||
@@ -47,6 +53,11 @@ 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,
|
||||||
|
enable_collectible.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);
|
||||||
@@ -69,6 +80,7 @@ fn on_head_drop(
|
|||||||
assets: Res<HeadDropAssets>,
|
assets: Res<HeadDropAssets>,
|
||||||
heads_db: Res<HeadsDatabase>,
|
heads_db: Res<HeadsDatabase>,
|
||||||
gltf_assets: Res<Assets<Gltf>>,
|
gltf_assets: Res<Assets<Gltf>>,
|
||||||
|
time: Res<Time>,
|
||||||
) -> Result<(), BevyError> {
|
) -> Result<(), BevyError> {
|
||||||
let drop = trigger.event();
|
let drop = trigger.event();
|
||||||
|
|
||||||
@@ -87,8 +99,6 @@ 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"),
|
||||||
@@ -102,16 +112,21 @@ fn on_head_drop(
|
|||||||
LayerMask::ALL & !GameLayer::Player.to_bits(),
|
LayerMask::ALL & !GameLayer::Player.to_bits(),
|
||||||
),
|
),
|
||||||
Restitution::new(0.6),
|
Restitution::new(0.6),
|
||||||
Children::spawn(SpawnWith(move |parent: &mut RelatedSpawner<ChildOf>| {
|
Children::spawn(SpawnWith({
|
||||||
parent
|
let head_id = drop.head_id;
|
||||||
.spawn((
|
let now = time.elapsed_secs();
|
||||||
Collider::sphere(1.5),
|
move |parent: &mut RelatedSpawner<ChildOf>| {
|
||||||
CollisionLayers::new(GameLayer::CollectibleSensors, GameLayer::Player),
|
parent
|
||||||
Sensor,
|
.spawn((
|
||||||
CollisionEventsEnabled,
|
Collider::sphere(1.5),
|
||||||
HeadDrop(head_id),
|
CollisionLayers::new(GameLayer::CollectibleSensors, LayerMask::NONE),
|
||||||
))
|
Sensor,
|
||||||
.observe(on_collect_head);
|
CollisionEventsEnabled,
|
||||||
|
HeadDrop { head_id },
|
||||||
|
HeadDropEnableTime(now + 1.2),
|
||||||
|
))
|
||||||
|
.observe(on_collect_head);
|
||||||
|
}
|
||||||
})),
|
})),
|
||||||
))
|
))
|
||||||
.insert_if(
|
.insert_if(
|
||||||
@@ -127,8 +142,28 @@ fn on_head_drop(
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn enable_collectible(
|
||||||
|
mut commands: Commands,
|
||||||
|
query: Query<(Entity, &HeadDropEnableTime)>,
|
||||||
|
time: Res<Time>,
|
||||||
|
) {
|
||||||
|
let now = time.elapsed_secs();
|
||||||
|
for (e, enable_time) in query.iter() {
|
||||||
|
if now > enable_time.0 {
|
||||||
|
commands
|
||||||
|
.entity(e)
|
||||||
|
.insert(CollisionLayers::new(
|
||||||
|
LayerMask(GameLayer::CollectibleSensors.to_bits()),
|
||||||
|
LayerMask::ALL,
|
||||||
|
))
|
||||||
|
.remove::<HeadDropEnableTime>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn on_collect_head(
|
fn on_collect_head(
|
||||||
trigger: Trigger<OnCollisionStart>,
|
trigger: Trigger<OnCollisionStart>,
|
||||||
|
|
||||||
mut commands: Commands,
|
mut commands: Commands,
|
||||||
query_player: Query<&Player>,
|
query_player: Query<&Player>,
|
||||||
query_collectable: Query<(&HeadDrop, &ChildOf)>,
|
query_collectable: Query<(&HeadDrop, &ChildOf)>,
|
||||||
@@ -148,7 +183,7 @@ fn on_collect_head(
|
|||||||
commands.trigger(PlaySound::HeadCollect);
|
commands.trigger(PlaySound::HeadCollect);
|
||||||
}
|
}
|
||||||
|
|
||||||
commands.trigger(HeadCollected(drop.0));
|
commands.trigger(HeadCollected(drop.head_id));
|
||||||
commands.entity(child_of.parent()).despawn();
|
commands.entity(child_of.parent()).despawn();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -147,6 +147,26 @@ impl ActiveHeads {
|
|||||||
|
|
||||||
(head.health, head.health_max) = hp.get()
|
(head.health, head.health_max) = hp.get()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// returns new current head id
|
||||||
|
pub fn loose_current(&mut self) -> Option<usize> {
|
||||||
|
self.heads[self.current_slot] = None;
|
||||||
|
self.next_head()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn next_head(&mut self) -> Option<usize> {
|
||||||
|
let start_idx = self.current_slot;
|
||||||
|
|
||||||
|
for offset in 1..5 {
|
||||||
|
let new_idx = (start_idx + offset) % 5;
|
||||||
|
if let Some(head) = self.heads[new_idx] {
|
||||||
|
self.current_slot = new_idx;
|
||||||
|
return Some(head.head);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Event, Reflect)]
|
#[derive(Event, Reflect)]
|
||||||
|
|||||||
@@ -6,9 +6,10 @@ use crate::{
|
|||||||
control::controller_common::{CharacterControllerBundle, PlayerMovement},
|
control::controller_common::{CharacterControllerBundle, PlayerMovement},
|
||||||
global_observer,
|
global_observer,
|
||||||
head::ActiveHead,
|
head::ActiveHead,
|
||||||
|
head_drop::HeadDrops,
|
||||||
heads::{ActiveHeads, HeadChanged, HeadState},
|
heads::{ActiveHeads, HeadChanged, HeadState},
|
||||||
heads_database::{HeadControls, HeadsDatabase},
|
heads_database::{HeadControls, HeadsDatabase},
|
||||||
hitpoints::Hitpoints,
|
hitpoints::{Hitpoints, Kill},
|
||||||
loading_assets::AudioAssets,
|
loading_assets::AudioAssets,
|
||||||
physics_layers::GameLayer,
|
physics_layers::GameLayer,
|
||||||
sounds::PlaySound,
|
sounds::PlaySound,
|
||||||
@@ -63,33 +64,35 @@ fn spawn(
|
|||||||
|
|
||||||
let collider = Collider::capsule(0.9, 1.2);
|
let collider = Collider::capsule(0.9, 1.2);
|
||||||
|
|
||||||
commands.spawn((
|
commands
|
||||||
Name::from("player"),
|
.spawn((
|
||||||
Player,
|
Name::from("player"),
|
||||||
ActiveHead(0),
|
Player,
|
||||||
ActiveHeads::new([
|
ActiveHead(0),
|
||||||
Some(HeadState::new(0, heads_db.as_ref())),
|
ActiveHeads::new([
|
||||||
Some(HeadState::new(3, heads_db.as_ref())),
|
Some(HeadState::new(0, heads_db.as_ref())),
|
||||||
Some(HeadState::new(6, heads_db.as_ref())),
|
Some(HeadState::new(3, heads_db.as_ref())),
|
||||||
Some(HeadState::new(10, heads_db.as_ref())),
|
Some(HeadState::new(6, heads_db.as_ref())),
|
||||||
Some(HeadState::new(9, heads_db.as_ref())),
|
Some(HeadState::new(10, heads_db.as_ref())),
|
||||||
]),
|
Some(HeadState::new(9, heads_db.as_ref())),
|
||||||
Hitpoints::new(100),
|
]),
|
||||||
CameraTarget,
|
Hitpoints::new(100),
|
||||||
transform,
|
CameraTarget,
|
||||||
Visibility::default(),
|
transform,
|
||||||
CollisionLayers::new(
|
Visibility::default(),
|
||||||
GameLayer::Player,
|
CollisionLayers::new(
|
||||||
LayerMask::ALL & !GameLayer::CollectiblePhysics.to_bits(),
|
LayerMask(GameLayer::Player.to_bits()),
|
||||||
),
|
LayerMask::ALL & !GameLayer::CollectiblePhysics.to_bits(),
|
||||||
CharacterControllerBundle::new(collider, heads_db.head_stats(0).controls),
|
),
|
||||||
children![(
|
CharacterControllerBundle::new(collider, heads_db.head_stats(0).controls),
|
||||||
Name::new("player-rig"),
|
children![(
|
||||||
PlayerBodyMesh,
|
Name::new("player-rig"),
|
||||||
CameraArmRotation,
|
PlayerBodyMesh,
|
||||||
children![AnimatedCharacter::new(0)]
|
CameraArmRotation,
|
||||||
)],
|
children![AnimatedCharacter::new(0)]
|
||||||
));
|
)],
|
||||||
|
))
|
||||||
|
.observe(on_kill);
|
||||||
|
|
||||||
commands.spawn((
|
commands.spawn((
|
||||||
AudioPlayer::new(asset_server.load("sfx/heads/angry demonstrator.ogg")),
|
AudioPlayer::new(asset_server.load("sfx/heads/angry demonstrator.ogg")),
|
||||||
@@ -97,6 +100,24 @@ fn spawn(
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn on_kill(
|
||||||
|
trigger: Trigger<Kill>,
|
||||||
|
mut commands: Commands,
|
||||||
|
mut query: Query<(&Transform, &ActiveHead, &mut ActiveHeads, &mut Hitpoints)>,
|
||||||
|
) {
|
||||||
|
let Ok((transform, active, mut heads, mut hp)) = query.get_mut(trigger.target()) else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
commands.trigger(HeadDrops::new(transform.translation, active.0));
|
||||||
|
|
||||||
|
if let Some(new_head) = heads.loose_current() {
|
||||||
|
hp.set_health(heads.current().unwrap().health);
|
||||||
|
|
||||||
|
commands.trigger(HeadChanged(new_head));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn cursor_recenter(q_windows: Single<&mut Window, With<PrimaryWindow>>) {
|
fn cursor_recenter(q_windows: Single<&mut Window, With<PrimaryWindow>>) {
|
||||||
let mut primary_window = q_windows;
|
let mut primary_window = q_windows;
|
||||||
let center = Vec2::new(
|
let center = Vec2::new(
|
||||||
|
|||||||
Reference in New Issue
Block a user