implement damage on low oxygen and collisions
This commit is contained in:
parent
ae2fcf2525
commit
61c7cffcef
53
src/actor.rs
53
src/actor.rs
|
@ -22,6 +22,7 @@ impl Plugin for ActorPlugin {
|
|||
app.add_systems(Update, (
|
||||
handle_input,
|
||||
handle_collisions,
|
||||
handle_damage,
|
||||
));
|
||||
app.add_systems(PostUpdate, (
|
||||
handle_vehicle_enter_exit,
|
||||
|
@ -43,17 +44,14 @@ pub struct VehicleEnterExitEvent {
|
|||
#[derive(Component)]
|
||||
pub struct Actor {
|
||||
pub id: String,
|
||||
pub hp: f32,
|
||||
pub m: f32, // mass
|
||||
pub inside_entity: u32,
|
||||
pub camdistance: f32,
|
||||
}
|
||||
|
||||
impl Default for Actor {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
id: "".to_string(),
|
||||
hp: 100.0,
|
||||
m: 100.0,
|
||||
inside_entity: NO_RIDE,
|
||||
camdistance: 15.0,
|
||||
|
@ -61,6 +59,22 @@ impl Default for Actor {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Component)]
|
||||
pub struct HitPoints {
|
||||
pub current: f32,
|
||||
pub max: f32,
|
||||
pub damage: f32,
|
||||
}
|
||||
impl Default for HitPoints {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
current: 100.0,
|
||||
max: 100.0,
|
||||
damage: 0.0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Component)] pub struct Player; // Attached to the suit of the player
|
||||
#[derive(Component)] pub struct PlayerDrivesThis; // Attached to the entered vehicle
|
||||
#[derive(Component)] pub struct PlayerCamera; // Attached to the actor to use as point of view
|
||||
|
@ -144,10 +158,10 @@ const SUIT_SIMPLE: Suit = Suit {
|
|||
|
||||
pub fn update_physics_lifeforms(
|
||||
time: Res<Time>,
|
||||
mut query: Query<(&mut LifeForm, &mut Suit, &LinearVelocity)>,
|
||||
mut query: Query<(&mut LifeForm, &mut HitPoints, &mut Suit, &LinearVelocity)>,
|
||||
) {
|
||||
let d = time.delta_seconds();
|
||||
for (mut lifeform, mut suit, velocity) in query.iter_mut() {
|
||||
for (mut lifeform, mut hp, mut suit, velocity) in query.iter_mut() {
|
||||
if lifeform.adrenaline_jolt.abs() > 1e-3 {
|
||||
lifeform.adrenaline_jolt *= 0.99;
|
||||
}
|
||||
|
@ -180,6 +194,9 @@ pub fn update_physics_lifeforms(
|
|||
oxygen_drain += suit.oxygen * 0.01 * drain_scaling;
|
||||
}
|
||||
suit.oxygen = (suit.oxygen - oxygen_drain*d).clamp(0.0, suit.oxygen_max);
|
||||
if suit.oxygen <= 0.0 {
|
||||
hp.damage += 1.0 * d;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -192,13 +209,9 @@ pub fn handle_input(
|
|||
mut q_vehicles: Query<(Entity, &mut Visibility, &Transform), (With<actor::Vehicle>, Without<actor::Player>)>,
|
||||
mut ew_conv: EventWriter<chat::StartConversationEvent>,
|
||||
mut ew_vehicle: EventWriter<VehicleEnterExitEvent>,
|
||||
mut ew_playerdies: EventWriter<PlayerDiesEvent>,
|
||||
q_player_drives: Query<Entity, With<PlayerDrivesThis>>,
|
||||
) {
|
||||
let mindist = MIN_INTERACT_DISTANCE * MIN_INTERACT_DISTANCE;
|
||||
if keyboard_input.just_pressed(settings.key_cheat_die) {
|
||||
ew_playerdies.send(PlayerDiesEvent);
|
||||
}
|
||||
if keyboard_input.just_pressed(settings.key_interact) {
|
||||
// Talking to people
|
||||
if let Ok((_player_entity, _player_actor, player)) = player.get_single() {
|
||||
|
@ -298,13 +311,15 @@ fn handle_collisions(
|
|||
mut collision_event_reader: EventReader<CollisionStarted>,
|
||||
mut ew_sfx: EventWriter<audio::PlaySfxEvent>,
|
||||
q_player: Query<Entity, With<PlayerCamera>>,
|
||||
mut q_player_lifeform: Query<&mut LifeForm, With<Player>>,
|
||||
mut q_player_lifeform: Query<(&mut LifeForm, &mut Suit, &mut HitPoints), With<Player>>,
|
||||
) {
|
||||
if let (Ok(player), Ok(mut lifeform)) = (q_player.get_single(), q_player_lifeform.get_single_mut()) {
|
||||
if let (Ok(player), Ok((mut lifeform, mut suit, mut hp))) = (q_player.get_single(), q_player_lifeform.get_single_mut()) {
|
||||
for CollisionStarted(entity1, entity2) in collision_event_reader.read() {
|
||||
if *entity1 == player || *entity2 == player {
|
||||
ew_sfx.send(audio::PlaySfxEvent(audio::Sfx::Crash));
|
||||
lifeform.adrenaline_jolt += 0.1;
|
||||
suit.integrity -= 0.03;
|
||||
hp.damage += 10.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -374,7 +389,23 @@ fn handle_player_death(
|
|||
scene_spawner.despawn_instance(**sceneinstance);
|
||||
}
|
||||
//cmd.run_system(commands::load_defs); // why is it so complicated to get SystemId?
|
||||
ew_sfx.send(audio::PlaySfxEvent(audio::Sfx::WakeUp));
|
||||
commands::load_defs(ew_spawn);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_damage(
|
||||
mut ew_playerdies: EventWriter<PlayerDiesEvent>,
|
||||
mut q_hp: Query<(&mut HitPoints, Option<&Player>), Changed<HitPoints>>,
|
||||
) {
|
||||
for (mut hp, player_maybe) in &mut q_hp {
|
||||
hp.current -= hp.damage;
|
||||
hp.damage = 0.0;
|
||||
if player_maybe.is_some() {
|
||||
if hp.current <= 0.0 {
|
||||
ew_playerdies.send(PlayerDiesEvent);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ const ASSET_BGM: &str = "music/Aleksey Chistilin - Cinematic Cello.ogg";
|
|||
const ASSET_THRUSTER: &str = "sounds/thruster.ogg";
|
||||
const ASSET_ROCKET: &str = "sounds/rocket.ogg";
|
||||
const ASSET_ION: &str = "sounds/ion.ogg";
|
||||
//const ASSET_WAKEUP: &str = "sounds/wakeup.ogg";
|
||||
const ASSET_WAKEUP: &str = "sounds/wakeup.ogg";
|
||||
const ASSET_BIKESTART: &str = "sounds/bikestart.ogg";
|
||||
const ASSET_CRASH: &str = "sounds/crash.ogg";
|
||||
const ASSET_ELECTRICMOTOR: &str = "sounds/electricmotor.ogg";
|
||||
|
@ -36,6 +36,7 @@ pub enum Sfx {
|
|||
Connect,
|
||||
EnterVehicle,
|
||||
Crash,
|
||||
WakeUp,
|
||||
None,
|
||||
}
|
||||
|
||||
|
@ -54,6 +55,7 @@ pub enum Sfx {
|
|||
#[derive(Resource)] pub struct SoundConnect(Handle<AudioSource>);
|
||||
#[derive(Resource)] pub struct SoundBikeStart(Handle<AudioSource>);
|
||||
#[derive(Resource)] pub struct SoundCrash(Handle<AudioSource>);
|
||||
#[derive(Resource)] pub struct SoundWakeUp(Handle<AudioSource>);
|
||||
|
||||
pub fn setup(
|
||||
mut commands: Commands,
|
||||
|
@ -131,6 +133,7 @@ pub fn setup(
|
|||
commands.insert_resource(SoundConnect(asset_server.load(ASSET_CONNECT)));
|
||||
commands.insert_resource(SoundBikeStart(asset_server.load(ASSET_BIKESTART)));
|
||||
commands.insert_resource(SoundCrash(asset_server.load(ASSET_CRASH)));
|
||||
commands.insert_resource(SoundWakeUp(asset_server.load(ASSET_WAKEUP)));
|
||||
}
|
||||
|
||||
pub fn toggle_bgm(
|
||||
|
@ -162,6 +165,7 @@ pub fn play_sfx(
|
|||
sound_connect: Res<SoundConnect>,
|
||||
sound_bikestart: Res<SoundBikeStart>,
|
||||
sound_crash: Res<SoundCrash>,
|
||||
sound_wakeup: Res<SoundWakeUp>,
|
||||
) {
|
||||
if settings.mute_sfx && !events_sfx.is_empty() {
|
||||
events_sfx.clear();
|
||||
|
@ -180,6 +184,7 @@ pub fn play_sfx(
|
|||
Sfx::Connect => sound_connect.0.clone(),
|
||||
Sfx::EnterVehicle => sound_bikestart.0.clone(),
|
||||
Sfx::Crash => sound_crash.0.clone(),
|
||||
Sfx::WakeUp => sound_wakeup.0.clone(),
|
||||
Sfx::None => sound_ping.0.clone(),
|
||||
},
|
||||
settings: PlaybackSettings::DESPAWN,
|
||||
|
|
|
@ -583,6 +583,7 @@ fn spawn_entities(
|
|||
..default()
|
||||
});
|
||||
actor.insert(world::DespawnOnPlayerDeath);
|
||||
actor.insert(actor::HitPoints::default());
|
||||
actor.insert(Position::from(state.pos));
|
||||
actor.insert(Rotation::from(state.rotation));
|
||||
if state.is_sphere {
|
||||
|
|
30
src/hud.rs
30
src/hud.rs
|
@ -209,6 +209,24 @@ fn setup(
|
|||
..default()
|
||||
}
|
||||
),
|
||||
TextSection::new(
|
||||
"\nVitals ",
|
||||
TextStyle {
|
||||
font: asset_server.load(FONT),
|
||||
font_size: settings.font_size_hud,
|
||||
color: Color::GRAY,
|
||||
..default()
|
||||
},
|
||||
),
|
||||
TextSection::new(
|
||||
"",
|
||||
TextStyle {
|
||||
font: asset_server.load(FONT),
|
||||
font_size: settings.font_size_hud,
|
||||
color: Color::GRAY,
|
||||
..default()
|
||||
}
|
||||
),
|
||||
TextSection::new(
|
||||
"\nProximity 警告 ",
|
||||
TextStyle {
|
||||
|
@ -376,7 +394,7 @@ fn update(
|
|||
diagnostics: Res<DiagnosticsStore>,
|
||||
time: Res<Time>,
|
||||
mut log: ResMut<Log>,
|
||||
player: Query<(&actor::Suit, &actor::LifeForm), With<actor::Player>>,
|
||||
player: Query<(&actor::HitPoints, &actor::Suit, &actor::LifeForm), With<actor::Player>>,
|
||||
q_camera: Query<(&Position, &LinearVelocity), With<actor::PlayerCamera>>,
|
||||
mut timer: ResMut<FPSUpdateTimer>,
|
||||
mut query: Query<&mut Text, With<GaugesText>>,
|
||||
|
@ -390,7 +408,7 @@ fn update(
|
|||
let q_camera_result = q_camera.get_single();
|
||||
let player = player.get_single();
|
||||
if player.is_ok() && q_camera_result.is_ok() {
|
||||
let (suit, lifeform) = player.unwrap();
|
||||
let (hp, suit, lifeform) = player.unwrap();
|
||||
let (pos, cam_v) = q_camera_result.unwrap();
|
||||
for mut text in &mut query {
|
||||
if let Some(fps) = diagnostics.get(&FrameTimeDiagnosticsPlugin::FPS) {
|
||||
|
@ -414,15 +432,17 @@ fn update(
|
|||
}
|
||||
let adrenaline = lifeform.adrenaline * 990.0 + 10.0;
|
||||
text.sections[9].value = format!("{adrenaline:.0}pg/mL");
|
||||
let vitals = 100.0 * hp.current / hp.max;
|
||||
text.sections[11].value = format!("{vitals:.0}%");
|
||||
let all_actors = query_all_actors.iter().len();
|
||||
text.sections[11].value = format!("{all_actors:.0}");
|
||||
text.sections[13].value = format!("{all_actors:.0}");
|
||||
let (x, y, z) = (pos.x / 1.0e3, pos.y / 1.0e3, pos.z / 1.0e3);
|
||||
text.sections[5].value = format!("{x:.0}km / {z:.0}km / {y:.0}km");
|
||||
let integrity = suit.integrity * 100.0;
|
||||
text.sections[13].value = format!("{integrity:.0}%");
|
||||
text.sections[15].value = format!("{integrity:.0}%");
|
||||
let speed = cam_v.length();
|
||||
let kmh = speed * 60.0 * 60.0 / 1000.0;
|
||||
text.sections[15].value = format!("{speed:.0}m/s | {kmh:.0}km/h");
|
||||
text.sections[17].value = format!("{speed:.0}m/s | {kmh:.0}km/h");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -353,6 +353,7 @@ fn handle_cheats(
|
|||
key_input: Res<ButtonInput<KeyCode>>,
|
||||
mut q_player: Query<(&Transform, &mut Position, &mut LinearVelocity), With<actor::PlayerCamera>>,
|
||||
mut q_life: Query<(&mut actor::LifeForm, ), With<actor::Player>>,
|
||||
mut ew_playerdies: EventWriter<actor::PlayerDiesEvent>,
|
||||
settings: ResMut<settings::Settings>,
|
||||
) {
|
||||
if q_player.is_empty() || q_life.is_empty() {
|
||||
|
@ -396,6 +397,9 @@ fn handle_cheats(
|
|||
if key_input.pressed(settings.key_cheat_adrenaline_max) {
|
||||
lifeform.adrenaline = 1.0;
|
||||
}
|
||||
if key_input.just_pressed(settings.key_cheat_die) {
|
||||
ew_playerdies.send(actor::PlayerDiesEvent);
|
||||
}
|
||||
}
|
||||
|
||||
// A variant of bevy_xpbd_3d::plugins::position_to_transform that adjusts
|
||||
|
|
Loading…
Reference in a new issue