second key and fence
This commit is contained in:
1
Cargo.lock
generated
1
Cargo.lock
generated
@@ -2820,6 +2820,7 @@ dependencies = [
|
|||||||
"bevy_sprite3d",
|
"bevy_sprite3d",
|
||||||
"bevy_trenchbroom",
|
"bevy_trenchbroom",
|
||||||
"nil",
|
"nil",
|
||||||
|
"rand",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|||||||
@@ -17,3 +17,4 @@ bevy-tnua-avian3d = "0.2.0"
|
|||||||
bevy_dolly = { version = "0.0.5", default-features = false }
|
bevy_dolly = { version = "0.0.5", default-features = false }
|
||||||
bevy_asset_loader = "0.22.0"
|
bevy_asset_loader = "0.22.0"
|
||||||
bevy_sprite3d = "4.0.0"
|
bevy_sprite3d = "4.0.0"
|
||||||
|
rand = "0.8.5"
|
||||||
|
|||||||
1162
assets/maps/map1.map
1162
assets/maps/map1.map
File diff suppressed because it is too large
Load Diff
@@ -10,6 +10,7 @@ enum CutsceneState {
|
|||||||
None,
|
None,
|
||||||
Playing {
|
Playing {
|
||||||
timer: Timer,
|
timer: Timer,
|
||||||
|
name: String,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -21,37 +22,39 @@ pub fn plugin(app: &mut App) {
|
|||||||
|
|
||||||
fn on_start_cutscene(
|
fn on_start_cutscene(
|
||||||
trigger: Trigger<StartCutscene>,
|
trigger: Trigger<StartCutscene>,
|
||||||
cutscenes: Query<(&Transform, &CutsceneCamera), Without<Camera>>,
|
|
||||||
mut res: ResMut<DebugVisuals>,
|
mut res: ResMut<DebugVisuals>,
|
||||||
mut cutscene_state: ResMut<CutsceneState>,
|
mut cutscene_state: ResMut<CutsceneState>,
|
||||||
mut cam: Query<&mut Transform, With<Camera>>,
|
|
||||||
) {
|
) {
|
||||||
let cutscene = trigger.event().0.clone();
|
let cutscene = trigger.event().0.clone();
|
||||||
|
|
||||||
let Some((t, _)) = cutscenes
|
|
||||||
.iter()
|
|
||||||
.find(|(_, cutscene_camera)| cutscene == cutscene_camera.name)
|
|
||||||
else {
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
|
|
||||||
res.cam_follow = false;
|
res.cam_follow = false;
|
||||||
|
|
||||||
*cam.single_mut() = *t;
|
|
||||||
|
|
||||||
*cutscene_state = CutsceneState::Playing {
|
*cutscene_state = CutsceneState::Playing {
|
||||||
timer: Timer::from_seconds(2.0, TimerMode::Once),
|
timer: Timer::from_seconds(2.0, TimerMode::Once),
|
||||||
|
name: cutscene,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update(
|
fn update(
|
||||||
mut res: ResMut<DebugVisuals>,
|
mut res: ResMut<DebugVisuals>,
|
||||||
mut cutscene_state: ResMut<CutsceneState>,
|
mut cutscene_state: ResMut<CutsceneState>,
|
||||||
|
cutscenes: Query<(&Transform, &CutsceneCamera), Without<Camera>>,
|
||||||
|
mut cam: Query<&mut Transform, With<Camera>>,
|
||||||
time: Res<Time>,
|
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());
|
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() {
|
if timer.finished() {
|
||||||
res.cam_follow = true;
|
res.cam_follow = true;
|
||||||
*cutscene_state = CutsceneState::None;
|
*cutscene_state = CutsceneState::None;
|
||||||
|
|||||||
60
src/gates.rs
60
src/gates.rs
@@ -1,38 +1,46 @@
|
|||||||
use crate::{cutscene::StartCutscene, keys::KeyCollected, movables::TriggerMovableEvent};
|
use crate::{cutscene::StartCutscene, keys::KeyCollected, movables::TriggerMovableEvent};
|
||||||
use bevy::{prelude::*, utils::hashbrown::HashSet};
|
use bevy::{prelude::*, utils::hashbrown::HashSet};
|
||||||
|
|
||||||
#[derive(Resource)]
|
|
||||||
enum GatesState {
|
|
||||||
Init,
|
|
||||||
GateOpen1,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn plugin(app: &mut App) {
|
pub fn plugin(app: &mut App) {
|
||||||
app.insert_resource(GatesState::Init);
|
|
||||||
app.add_observer(on_key);
|
app.add_observer(on_key);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_key(
|
fn on_key(trigger: Trigger<KeyCollected>, mut commands: Commands, asset_server: Res<AssetServer>) {
|
||||||
_trigger: Trigger<KeyCollected>,
|
match trigger.event().0.as_str() {
|
||||||
mut commands: Commands,
|
"fence_gate" => {
|
||||||
mut state: ResMut<GatesState>,
|
commands.trigger(StartCutscene("fence_01".to_string()));
|
||||||
asset_server: Res<AssetServer>,
|
|
||||||
) {
|
|
||||||
if matches!(*state, GatesState::Init) {
|
|
||||||
*state = GatesState::GateOpen1;
|
|
||||||
commands.trigger(StartCutscene("fence_01".to_string()));
|
|
||||||
|
|
||||||
//TODO: put into a sound effects system
|
//TODO: put into a sound effects system
|
||||||
commands.spawn((
|
commands.spawn((
|
||||||
AudioPlayer::new(asset_server.load("sfx/effects/gate.ogg")),
|
AudioPlayer::new(asset_server.load("sfx/effects/gate.ogg")),
|
||||||
PlaybackSettings::DESPAWN,
|
PlaybackSettings::DESPAWN,
|
||||||
));
|
));
|
||||||
|
|
||||||
let entities: HashSet<_> = vec!["fence_01", "fence_02"]
|
let entities: HashSet<_> = vec!["fence_01", "fence_02"]
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|s| String::from(s))
|
.map(|s| String::from(s))
|
||||||
.collect();
|
.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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
36
src/keys.rs
36
src/keys.rs
@@ -4,14 +4,14 @@ use bevy::prelude::*;
|
|||||||
use std::f32::consts::PI;
|
use std::f32::consts::PI;
|
||||||
|
|
||||||
#[derive(Event, Reflect)]
|
#[derive(Event, Reflect)]
|
||||||
pub struct KeySpawn(pub Vec3);
|
pub struct KeySpawn(pub Vec3, pub String);
|
||||||
|
|
||||||
#[derive(Component, Reflect)]
|
#[derive(Component, Reflect)]
|
||||||
#[reflect(Component)]
|
#[reflect(Component)]
|
||||||
struct Key;
|
struct Key(pub String);
|
||||||
|
|
||||||
#[derive(Event, Reflect)]
|
#[derive(Event, Reflect)]
|
||||||
pub struct KeyCollected;
|
pub struct KeyCollected(pub String);
|
||||||
|
|
||||||
pub fn plugin(app: &mut App) {
|
pub fn plugin(app: &mut App) {
|
||||||
app.add_systems(Update, collect_key);
|
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>) {
|
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 angle = rand::random::<f32>() * PI * 2.;
|
||||||
let spawn_dir = Quat::from_rotation_y(PI / 2.) * Vec3::new(0.5, 0.6, 0.).normalize();
|
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"));
|
let mesh = asset_server.load(GltfAssetLabel::Scene(0).from_asset("models/key.glb"));
|
||||||
|
|
||||||
commands
|
commands
|
||||||
.spawn((
|
.spawn((
|
||||||
Name::new("key"),
|
Name::new("key"),
|
||||||
Key,
|
Key(id.clone()),
|
||||||
Transform::from_translation(*position),
|
Transform::from_translation(*position),
|
||||||
Visibility::default(),
|
Visibility::default(),
|
||||||
Collider::sphere(1.5),
|
Collider::sphere(1.5),
|
||||||
@@ -50,21 +50,21 @@ fn collect_key(
|
|||||||
) {
|
) {
|
||||||
for CollisionStarted(e1, e2) in collision_event_reader.read() {
|
for CollisionStarted(e1, e2) in collision_event_reader.read() {
|
||||||
let collectable = if query_player.contains(*e1) && query_collectable.contains(*e2) {
|
let collectable = if query_player.contains(*e1) && query_collectable.contains(*e2) {
|
||||||
Some(*e2)
|
*e2
|
||||||
} else if query_player.contains(*e2) && query_collectable.contains(*e1) {
|
} else if query_player.contains(*e2) && query_collectable.contains(*e1) {
|
||||||
Some(*e1)
|
*e1
|
||||||
} else {
|
} else {
|
||||||
None
|
continue;
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(collectable) = collectable {
|
let key = query_collectable.get(collectable).unwrap();
|
||||||
commands.spawn((
|
|
||||||
AudioPlayer::new(asset_server.load("sfx/effects/key_collect.ogg")),
|
|
||||||
PlaybackSettings::DESPAWN,
|
|
||||||
));
|
|
||||||
|
|
||||||
commands.trigger(KeyCollected);
|
commands.spawn((
|
||||||
commands.entity(collectable).despawn_recursive();
|
AudioPlayer::new(asset_server.load("sfx/effects/key_collect.ogg")),
|
||||||
}
|
PlaybackSettings::DESPAWN,
|
||||||
|
));
|
||||||
|
|
||||||
|
commands.trigger(KeyCollected(key.0.clone()));
|
||||||
|
commands.entity(collectable).despawn_recursive();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ fn trigger(
|
|||||||
target,
|
target,
|
||||||
start_time: time.elapsed_secs(),
|
start_time: time.elapsed_secs(),
|
||||||
//TODO: make this configurable
|
//TODO: make this configurable
|
||||||
duration: 1.,
|
duration: 2.,
|
||||||
};
|
};
|
||||||
|
|
||||||
commands.entity(e).insert(platform);
|
commands.entity(e).insert(platform);
|
||||||
@@ -75,6 +75,7 @@ fn move_active(
|
|||||||
let t = (elapsed - active.start_time) / active.duration;
|
let t = (elapsed - active.start_time) / active.duration;
|
||||||
transform.rotation = active.start.rotation.lerp(active.target.rotation, t);
|
transform.rotation = active.start.rotation.lerp(active.target.rotation, t);
|
||||||
} else {
|
} else {
|
||||||
|
info!("movable done");
|
||||||
*transform = active.target;
|
*transform = active.target;
|
||||||
|
|
||||||
commands.entity(e).remove::<(ActiveMovable, Movable)>();
|
commands.entity(e).remove::<(ActiveMovable, Movable)>();
|
||||||
|
|||||||
@@ -37,8 +37,8 @@ fn on_hit(
|
|||||||
if hp.0 <= 0 {
|
if hp.0 <= 0 {
|
||||||
commands.entity(trigger.entity()).despawn_recursive();
|
commands.entity(trigger.entity()).despawn_recursive();
|
||||||
|
|
||||||
if enemy.has_key {
|
if !enemy.key.is_empty() {
|
||||||
commands.trigger(KeySpawn(transform.translation));
|
commands.trigger(KeySpawn(transform.translation, enemy.key.clone()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -102,7 +102,7 @@ pub struct CutsceneCamera {
|
|||||||
#[model({ "path": "models/alien_naked.glb" })]
|
#[model({ "path": "models/alien_naked.glb" })]
|
||||||
pub struct EnemySpawn {
|
pub struct EnemySpawn {
|
||||||
pub head: String,
|
pub head: String,
|
||||||
pub has_key: bool,
|
pub key: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EnemySpawn {
|
impl EnemySpawn {
|
||||||
|
|||||||
@@ -72,11 +72,7 @@
|
|||||||
@PointClass base(transform) model({ "path": "models/alien_naked.glb" }) = enemy_spawn
|
@PointClass base(transform) model({ "path": "models/alien_naked.glb" }) = enemy_spawn
|
||||||
[
|
[
|
||||||
head(string) : "head" : "" : ""
|
head(string) : "head" : "" : ""
|
||||||
has_key(choices) : "has_key" : "false" : "" =
|
key(string) : "key" : "" : ""
|
||||||
[
|
|
||||||
"true" : "true"
|
|
||||||
"false" : "false"
|
|
||||||
]
|
|
||||||
]
|
]
|
||||||
|
|
||||||
@SolidClass base(transform, target) = movable
|
@SolidClass base(transform, target) = movable
|
||||||
|
|||||||
Reference in New Issue
Block a user