second key and fence

This commit is contained in:
2025-03-14 21:57:37 +01:00
parent 87e0529afb
commit 5ba25edbdf
10 changed files with 711 additions and 591 deletions

1
Cargo.lock generated
View File

@@ -2820,6 +2820,7 @@ dependencies = [
"bevy_sprite3d",
"bevy_trenchbroom",
"nil",
"rand",
]
[[package]]

View File

@@ -17,3 +17,4 @@ bevy-tnua-avian3d = "0.2.0"
bevy_dolly = { version = "0.0.5", default-features = false }
bevy_asset_loader = "0.22.0"
bevy_sprite3d = "4.0.0"
rand = "0.8.5"

File diff suppressed because it is too large Load Diff

View File

@@ -10,6 +10,7 @@ enum CutsceneState {
None,
Playing {
timer: Timer,
name: String,
},
}
@@ -21,37 +22,39 @@ pub fn plugin(app: &mut App) {
fn on_start_cutscene(
trigger: Trigger<StartCutscene>,
cutscenes: Query<(&Transform, &CutsceneCamera), Without<Camera>>,
mut res: ResMut<DebugVisuals>,
mut cutscene_state: ResMut<CutsceneState>,
mut cam: Query<&mut Transform, With<Camera>>,
) {
let cutscene = trigger.event().0.clone();
let Some((t, _)) = cutscenes
.iter()
.find(|(_, cutscene_camera)| cutscene == cutscene_camera.name)
else {
return;
};
res.cam_follow = false;
*cam.single_mut() = *t;
*cutscene_state = CutsceneState::Playing {
timer: Timer::from_seconds(2.0, TimerMode::Once),
name: cutscene,
};
}
fn update(
mut res: ResMut<DebugVisuals>,
mut cutscene_state: ResMut<CutsceneState>,
cutscenes: Query<(&Transform, &CutsceneCamera), Without<Camera>>,
mut cam: Query<&mut Transform, With<Camera>>,
time: Res<Time>,
) {
if let CutsceneState::Playing { timer, .. } = &mut *cutscene_state {
if let CutsceneState::Playing { timer, name } = &mut *cutscene_state {
res.cam_follow = false;
timer.tick(time.delta());
let Some((t, _)) = cutscenes
.iter()
.find(|(_, cutscene_camera)| name == &cutscene_camera.name)
else {
return;
};
*cam.single_mut() = *t;
if timer.finished() {
res.cam_follow = true;
*cutscene_state = CutsceneState::None;

View File

@@ -1,38 +1,46 @@
use crate::{cutscene::StartCutscene, keys::KeyCollected, movables::TriggerMovableEvent};
use bevy::{prelude::*, utils::hashbrown::HashSet};
#[derive(Resource)]
enum GatesState {
Init,
GateOpen1,
}
pub fn plugin(app: &mut App) {
app.insert_resource(GatesState::Init);
app.add_observer(on_key);
}
fn on_key(
_trigger: Trigger<KeyCollected>,
mut commands: Commands,
mut state: ResMut<GatesState>,
asset_server: Res<AssetServer>,
) {
if matches!(*state, GatesState::Init) {
*state = GatesState::GateOpen1;
commands.trigger(StartCutscene("fence_01".to_string()));
fn on_key(trigger: Trigger<KeyCollected>, mut commands: Commands, asset_server: Res<AssetServer>) {
match trigger.event().0.as_str() {
"fence_gate" => {
commands.trigger(StartCutscene("fence_01".to_string()));
//TODO: put into a sound effects system
commands.spawn((
AudioPlayer::new(asset_server.load("sfx/effects/gate.ogg")),
PlaybackSettings::DESPAWN,
));
//TODO: put into a sound effects system
commands.spawn((
AudioPlayer::new(asset_server.load("sfx/effects/gate.ogg")),
PlaybackSettings::DESPAWN,
));
let entities: HashSet<_> = vec!["fence_01", "fence_02"]
.into_iter()
.map(|s| String::from(s))
.collect();
let entities: HashSet<_> = vec!["fence_01", "fence_02"]
.into_iter()
.map(|s| String::from(s))
.collect();
commands.trigger(TriggerMovableEvent(entities));
commands.trigger(TriggerMovableEvent(entities));
}
"fence_shaft" => {
commands.trigger(StartCutscene("fence_02".to_string()));
//TODO: put into a sound effects system
commands.spawn((
AudioPlayer::new(asset_server.load("sfx/effects/gate.ogg")),
PlaybackSettings::DESPAWN,
));
let entities: HashSet<_> = vec!["fence_shaft"]
.into_iter()
.map(|s| String::from(s))
.collect();
commands.trigger(TriggerMovableEvent(entities));
}
_ => {
error!("unknown key logic: {}", trigger.event().0);
}
}
}

View File

@@ -4,14 +4,14 @@ use bevy::prelude::*;
use std::f32::consts::PI;
#[derive(Event, Reflect)]
pub struct KeySpawn(pub Vec3);
pub struct KeySpawn(pub Vec3, pub String);
#[derive(Component, Reflect)]
#[reflect(Component)]
struct Key;
struct Key(pub String);
#[derive(Event, Reflect)]
pub struct KeyCollected;
pub struct KeyCollected(pub String);
pub fn plugin(app: &mut App) {
app.add_systems(Update, collect_key);
@@ -19,17 +19,17 @@ pub fn plugin(app: &mut App) {
}
fn on_spawn(trigger: Trigger<KeySpawn>, mut commands: Commands, asset_server: Res<AssetServer>) {
let KeySpawn(position) = trigger.event();
let KeySpawn(position, id) = trigger.event();
//TODO: randomize
let spawn_dir = Quat::from_rotation_y(PI / 2.) * Vec3::new(0.5, 0.6, 0.).normalize();
let angle = rand::random::<f32>() * PI * 2.;
let spawn_dir = Quat::from_rotation_y(angle) * Vec3::new(0.5, 0.6, 0.).normalize();
let mesh = asset_server.load(GltfAssetLabel::Scene(0).from_asset("models/key.glb"));
commands
.spawn((
Name::new("key"),
Key,
Key(id.clone()),
Transform::from_translation(*position),
Visibility::default(),
Collider::sphere(1.5),
@@ -50,21 +50,21 @@ fn collect_key(
) {
for CollisionStarted(e1, e2) in collision_event_reader.read() {
let collectable = if query_player.contains(*e1) && query_collectable.contains(*e2) {
Some(*e2)
*e2
} else if query_player.contains(*e2) && query_collectable.contains(*e1) {
Some(*e1)
*e1
} else {
None
continue;
};
if let Some(collectable) = collectable {
commands.spawn((
AudioPlayer::new(asset_server.load("sfx/effects/key_collect.ogg")),
PlaybackSettings::DESPAWN,
));
let key = query_collectable.get(collectable).unwrap();
commands.trigger(KeyCollected);
commands.entity(collectable).despawn_recursive();
}
commands.spawn((
AudioPlayer::new(asset_server.load("sfx/effects/key_collect.ogg")),
PlaybackSettings::DESPAWN,
));
commands.trigger(KeyCollected(key.0.clone()));
commands.entity(collectable).despawn_recursive();
}
}

View File

@@ -57,7 +57,7 @@ fn trigger(
target,
start_time: time.elapsed_secs(),
//TODO: make this configurable
duration: 1.,
duration: 2.,
};
commands.entity(e).insert(platform);
@@ -75,6 +75,7 @@ fn move_active(
let t = (elapsed - active.start_time) / active.duration;
transform.rotation = active.start.rotation.lerp(active.target.rotation, t);
} else {
info!("movable done");
*transform = active.target;
commands.entity(e).remove::<(ActiveMovable, Movable)>();

View File

@@ -37,8 +37,8 @@ fn on_hit(
if hp.0 <= 0 {
commands.entity(trigger.entity()).despawn_recursive();
if enemy.has_key {
commands.trigger(KeySpawn(transform.translation));
if !enemy.key.is_empty() {
commands.trigger(KeySpawn(transform.translation, enemy.key.clone()));
}
}
}

View File

@@ -102,7 +102,7 @@ pub struct CutsceneCamera {
#[model({ "path": "models/alien_naked.glb" })]
pub struct EnemySpawn {
pub head: String,
pub has_key: bool,
pub key: String,
}
impl EnemySpawn {

View File

@@ -72,11 +72,7 @@
@PointClass base(transform) model({ "path": "models/alien_naked.glb" }) = enemy_spawn
[
head(string) : "head" : "" : ""
has_key(choices) : "has_key" : "false" : "" =
[
"true" : "true"
"false" : "false"
]
key(string) : "key" : "" : ""
]
@SolidClass base(transform, target) = movable