implement damage on low oxygen and collisions

This commit is contained in:
yuni 2024-04-05 03:31:52 +02:00
parent ae2fcf2525
commit 61c7cffcef
5 changed files with 78 additions and 17 deletions

View file

@ -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);
}
}
}
}

View file

@ -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,

View file

@ -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 {

View file

@ -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");
}
}

View file

@ -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