healing particle effect
This commit is contained in:
BIN
assets/models/medic_particle.glb
Normal file
BIN
assets/models/medic_particle.glb
Normal file
Binary file not shown.
@@ -6,7 +6,7 @@ use crate::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Component)]
|
#[derive(Component)]
|
||||||
struct Healing(Entity);
|
pub struct Healing(pub Entity);
|
||||||
|
|
||||||
#[derive(Event, Debug)]
|
#[derive(Event, Debug)]
|
||||||
pub enum HealingStateChanged {
|
pub enum HealingStateChanged {
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ mod healing;
|
|||||||
mod missile;
|
mod missile;
|
||||||
mod thrown;
|
mod thrown;
|
||||||
|
|
||||||
|
pub use healing::Healing;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
GameState,
|
GameState,
|
||||||
aim::AimTarget,
|
aim::AimTarget,
|
||||||
|
|||||||
99
src/heal_effect.rs
Normal file
99
src/heal_effect.rs
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
use crate::{
|
||||||
|
GameState, abilities::Healing, loading_assets::GameAssets, utils::billboards::Billboard,
|
||||||
|
};
|
||||||
|
use bevy::prelude::*;
|
||||||
|
use rand::{Rng, thread_rng};
|
||||||
|
|
||||||
|
#[derive(Component, Default)]
|
||||||
|
#[require(Transform, InheritedVisibility)]
|
||||||
|
struct HealParticleEffect {
|
||||||
|
next_spawn: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Component)]
|
||||||
|
struct HealParticle {
|
||||||
|
start_scale: f32,
|
||||||
|
end_scale: f32,
|
||||||
|
start_pos: Vec3,
|
||||||
|
end_pos: Vec3,
|
||||||
|
start_time: f32,
|
||||||
|
life_time: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn plugin(app: &mut App) {
|
||||||
|
app.add_systems(
|
||||||
|
Update,
|
||||||
|
(on_added, update_effects, update_particles).run_if(in_state(GameState::Playing)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn on_added(mut cmds: Commands, query: Query<&Healing, Added<Healing>>) {
|
||||||
|
for healing in query.iter() {
|
||||||
|
cmds.entity(healing.0).insert((
|
||||||
|
Name::new("heal-particle-effect"),
|
||||||
|
HealParticleEffect::default(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update_effects(
|
||||||
|
mut cmds: Commands,
|
||||||
|
mut query: Query<(&mut HealParticleEffect, Entity)>,
|
||||||
|
time: Res<Time>,
|
||||||
|
assets: Res<GameAssets>,
|
||||||
|
) {
|
||||||
|
const DISTANCE: f32 = 4.;
|
||||||
|
let mut rng = thread_rng();
|
||||||
|
|
||||||
|
let now = time.elapsed_secs();
|
||||||
|
for (mut effect, e) in query.iter_mut() {
|
||||||
|
if effect.next_spawn < now {
|
||||||
|
let start_pos = Vec3::new(
|
||||||
|
rng.gen_range(-DISTANCE..DISTANCE),
|
||||||
|
2.,
|
||||||
|
rng.gen_range(-DISTANCE..DISTANCE),
|
||||||
|
);
|
||||||
|
let max_distance = start_pos.length().max(0.8);
|
||||||
|
let end_pos =
|
||||||
|
start_pos + (start_pos.normalize() * -1.) * rng.gen_range(0.5..max_distance);
|
||||||
|
let start_scale = rng.gen_range(0.7..1.0);
|
||||||
|
let end_scale = rng.gen_range(0.1..start_scale);
|
||||||
|
|
||||||
|
cmds.entity(e).with_child((
|
||||||
|
Name::new("heal-particle"),
|
||||||
|
SceneRoot(assets.mesh_heal_particle.clone()),
|
||||||
|
Billboard,
|
||||||
|
Transform::from_translation(start_pos),
|
||||||
|
HealParticle {
|
||||||
|
start_scale,
|
||||||
|
end_scale,
|
||||||
|
start_pos,
|
||||||
|
end_pos,
|
||||||
|
start_time: now,
|
||||||
|
life_time: rng.gen_range(0.3..1.0),
|
||||||
|
},
|
||||||
|
));
|
||||||
|
|
||||||
|
effect.next_spawn = now + rng.gen_range(0.1..0.5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update_particles(
|
||||||
|
mut cmds: Commands,
|
||||||
|
mut query: Query<(&mut Transform, &HealParticle, Entity)>,
|
||||||
|
time: Res<Time>,
|
||||||
|
) {
|
||||||
|
for (mut transform, particle, e) in query.iter_mut() {
|
||||||
|
if particle.start_time + particle.life_time < time.elapsed_secs() {
|
||||||
|
cmds.entity(e).despawn();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let t = (time.elapsed_secs() - particle.start_time) / particle.life_time;
|
||||||
|
|
||||||
|
// info!("particle[{e:?}] t: {t}");
|
||||||
|
transform.translation = particle.start_pos.lerp(particle.end_pos, t);
|
||||||
|
transform.scale = Vec3::splat(particle.start_scale.lerp(particle.end_scale, t));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -100,6 +100,9 @@ pub struct GameAssets {
|
|||||||
#[asset(path = "models/cash.glb#Scene0")]
|
#[asset(path = "models/cash.glb#Scene0")]
|
||||||
pub mesh_cash: Handle<Scene>,
|
pub mesh_cash: Handle<Scene>,
|
||||||
|
|
||||||
|
#[asset(path = "models/medic_particle.glb#Scene0")]
|
||||||
|
pub mesh_heal_particle: Handle<Scene>,
|
||||||
|
|
||||||
#[asset(path = "models/projectiles", collection(mapped, typed))]
|
#[asset(path = "models/projectiles", collection(mapped, typed))]
|
||||||
pub projectiles: HashMap<AssetFileName, Handle<Gltf>>,
|
pub projectiles: HashMap<AssetFileName, Handle<Gltf>>,
|
||||||
|
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ mod head;
|
|||||||
mod head_drop;
|
mod head_drop;
|
||||||
mod heads;
|
mod heads;
|
||||||
mod heads_database;
|
mod heads_database;
|
||||||
|
mod heal_effect;
|
||||||
mod hitpoints;
|
mod hitpoints;
|
||||||
mod keys;
|
mod keys;
|
||||||
mod loading_assets;
|
mod loading_assets;
|
||||||
@@ -165,6 +166,7 @@ fn main() {
|
|||||||
app.add_plugins(water::plugin);
|
app.add_plugins(water::plugin);
|
||||||
app.add_plugins(head_drop::plugin);
|
app.add_plugins(head_drop::plugin);
|
||||||
app.add_plugins(trail::plugin);
|
app.add_plugins(trail::plugin);
|
||||||
|
app.add_plugins(heal_effect::plugin);
|
||||||
|
|
||||||
app.init_state::<GameState>();
|
app.init_state::<GameState>();
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user