Player can loose head (#46)
This commit is contained in:
@@ -37,7 +37,13 @@ impl HeadDrops {
|
||||
|
||||
#[derive(Component, Reflect)]
|
||||
#[reflect(Component)]
|
||||
struct HeadDrop(pub usize);
|
||||
struct HeadDrop {
|
||||
pub head_id: usize,
|
||||
}
|
||||
|
||||
#[derive(Component, Reflect)]
|
||||
#[reflect(Component)]
|
||||
struct HeadDropEnableTime(f32);
|
||||
|
||||
#[derive(Component, Reflect)]
|
||||
#[reflect(Component)]
|
||||
@@ -47,6 +53,11 @@ struct SecretHeadMarker;
|
||||
pub struct HeadCollected(pub usize);
|
||||
|
||||
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);
|
||||
|
||||
global_observer!(app, on_head_drop);
|
||||
@@ -69,6 +80,7 @@ fn on_head_drop(
|
||||
assets: Res<HeadDropAssets>,
|
||||
heads_db: Res<HeadsDatabase>,
|
||||
gltf_assets: Res<Assets<Gltf>>,
|
||||
time: Res<Time>,
|
||||
) -> Result<(), BevyError> {
|
||||
let drop = trigger.event();
|
||||
|
||||
@@ -87,8 +99,6 @@ fn on_head_drop(
|
||||
}
|
||||
.ok_or("asset not found")?;
|
||||
|
||||
let head_id = drop.head_id;
|
||||
|
||||
commands
|
||||
.spawn((
|
||||
Name::new("headdrop"),
|
||||
@@ -102,16 +112,21 @@ fn on_head_drop(
|
||||
LayerMask::ALL & !GameLayer::Player.to_bits(),
|
||||
),
|
||||
Restitution::new(0.6),
|
||||
Children::spawn(SpawnWith(move |parent: &mut RelatedSpawner<ChildOf>| {
|
||||
parent
|
||||
.spawn((
|
||||
Collider::sphere(1.5),
|
||||
CollisionLayers::new(GameLayer::CollectibleSensors, GameLayer::Player),
|
||||
Sensor,
|
||||
CollisionEventsEnabled,
|
||||
HeadDrop(head_id),
|
||||
))
|
||||
.observe(on_collect_head);
|
||||
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);
|
||||
}
|
||||
})),
|
||||
))
|
||||
.insert_if(
|
||||
@@ -127,8 +142,28 @@ fn on_head_drop(
|
||||
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(
|
||||
trigger: Trigger<OnCollisionStart>,
|
||||
|
||||
mut commands: Commands,
|
||||
query_player: Query<&Player>,
|
||||
query_collectable: Query<(&HeadDrop, &ChildOf)>,
|
||||
@@ -148,7 +183,7 @@ fn on_collect_head(
|
||||
commands.trigger(PlaySound::HeadCollect);
|
||||
}
|
||||
|
||||
commands.trigger(HeadCollected(drop.0));
|
||||
commands.trigger(HeadCollected(drop.head_id));
|
||||
commands.entity(child_of.parent()).despawn();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -147,6 +147,26 @@ impl ActiveHeads {
|
||||
|
||||
(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)]
|
||||
|
||||
@@ -6,9 +6,10 @@ use crate::{
|
||||
control::controller_common::{CharacterControllerBundle, PlayerMovement},
|
||||
global_observer,
|
||||
head::ActiveHead,
|
||||
head_drop::HeadDrops,
|
||||
heads::{ActiveHeads, HeadChanged, HeadState},
|
||||
heads_database::{HeadControls, HeadsDatabase},
|
||||
hitpoints::Hitpoints,
|
||||
hitpoints::{Hitpoints, Kill},
|
||||
loading_assets::AudioAssets,
|
||||
physics_layers::GameLayer,
|
||||
sounds::PlaySound,
|
||||
@@ -63,33 +64,35 @@ fn spawn(
|
||||
|
||||
let collider = Collider::capsule(0.9, 1.2);
|
||||
|
||||
commands.spawn((
|
||||
Name::from("player"),
|
||||
Player,
|
||||
ActiveHead(0),
|
||||
ActiveHeads::new([
|
||||
Some(HeadState::new(0, heads_db.as_ref())),
|
||||
Some(HeadState::new(3, heads_db.as_ref())),
|
||||
Some(HeadState::new(6, heads_db.as_ref())),
|
||||
Some(HeadState::new(10, heads_db.as_ref())),
|
||||
Some(HeadState::new(9, heads_db.as_ref())),
|
||||
]),
|
||||
Hitpoints::new(100),
|
||||
CameraTarget,
|
||||
transform,
|
||||
Visibility::default(),
|
||||
CollisionLayers::new(
|
||||
GameLayer::Player,
|
||||
LayerMask::ALL & !GameLayer::CollectiblePhysics.to_bits(),
|
||||
),
|
||||
CharacterControllerBundle::new(collider, heads_db.head_stats(0).controls),
|
||||
children![(
|
||||
Name::new("player-rig"),
|
||||
PlayerBodyMesh,
|
||||
CameraArmRotation,
|
||||
children![AnimatedCharacter::new(0)]
|
||||
)],
|
||||
));
|
||||
commands
|
||||
.spawn((
|
||||
Name::from("player"),
|
||||
Player,
|
||||
ActiveHead(0),
|
||||
ActiveHeads::new([
|
||||
Some(HeadState::new(0, heads_db.as_ref())),
|
||||
Some(HeadState::new(3, heads_db.as_ref())),
|
||||
Some(HeadState::new(6, heads_db.as_ref())),
|
||||
Some(HeadState::new(10, heads_db.as_ref())),
|
||||
Some(HeadState::new(9, heads_db.as_ref())),
|
||||
]),
|
||||
Hitpoints::new(100),
|
||||
CameraTarget,
|
||||
transform,
|
||||
Visibility::default(),
|
||||
CollisionLayers::new(
|
||||
LayerMask(GameLayer::Player.to_bits()),
|
||||
LayerMask::ALL & !GameLayer::CollectiblePhysics.to_bits(),
|
||||
),
|
||||
CharacterControllerBundle::new(collider, heads_db.head_stats(0).controls),
|
||||
children![(
|
||||
Name::new("player-rig"),
|
||||
PlayerBodyMesh,
|
||||
CameraArmRotation,
|
||||
children![AnimatedCharacter::new(0)]
|
||||
)],
|
||||
))
|
||||
.observe(on_kill);
|
||||
|
||||
commands.spawn((
|
||||
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>>) {
|
||||
let mut primary_window = q_windows;
|
||||
let center = Vec2::new(
|
||||
|
||||
Reference in New Issue
Block a user