diff --git a/Cargo.toml b/Cargo.toml index 28f62b1..1af7801 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,8 +6,9 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -bevy = "0.17.0-rc.2" +bevy = "0.17.2" fastrand = "2.1.1" # ref: https://github.com/bevyengine/bevy/pull/3992 +bevy_hanabi = "0.17" [workspace] resolver ="2" diff --git a/assets/Fox.glb b/assets/Fox.glb new file mode 100644 index 0000000..2bb946e Binary files /dev/null and b/assets/Fox.glb differ diff --git a/assets/circle.png b/assets/circle.png new file mode 100644 index 0000000..11c2266 Binary files /dev/null and b/assets/circle.png differ diff --git a/assets/cloud.png b/assets/cloud.png new file mode 100644 index 0000000..b809c4a Binary files /dev/null and b/assets/cloud.png differ diff --git a/assets/ramp.png b/assets/ramp.png new file mode 100644 index 0000000..1a93572 Binary files /dev/null and b/assets/ramp.png differ diff --git a/src/game/mod.rs b/src/game/mod.rs index 22b738c..e78ef69 100644 --- a/src/game/mod.rs +++ b/src/game/mod.rs @@ -1,5 +1,5 @@ use bevy::prelude::*; -//use bevy_hanabi::prelude::HanabiPlugin; <-- TODO: Add this back in +use bevy_hanabi::prelude::HanabiPlugin; mod ai; pub use ai::AiPlugin; @@ -69,6 +69,7 @@ impl Plugin for GamePlugin { CollisionPlugin, LevelPlugin, DespawnerPlugin, + HanabiPlugin, VfxPlugin, ActorPlugin, )); // currently for cleaning up entities diff --git a/src/game/vfx/mod.rs b/src/game/vfx/mod.rs index f291eba..9161b2a 100644 --- a/src/game/vfx/mod.rs +++ b/src/game/vfx/mod.rs @@ -1,21 +1,32 @@ use std::f32::consts::PI; - -use crate::constants::CAMERA_FAR; -use bevy::prelude::*; use std::time::Duration; +use bevy::prelude::*; +use bevy_hanabi::prelude::*; +use bevy_hanabi::Gradient as HanabiGradient; use fastrand; +use crate::constants::CAMERA_FAR; + use super::components::*; use super::events::*; +const EXPLOSION_PARTICLE_LIFETIME: f32 = 0.6; +const EXPLOSION_SPAWN_COUNT: f32 = 160.0; +const EXPLOSION_RADIUS: f32 = 6.0; +const EXPLOSION_BASE_SPEED: f32 = 42.0; + +#[derive(Resource, Clone)] +struct ExplosionEffectHandle(pub Handle); + pub struct VfxPlugin; impl Plugin for VfxPlugin { fn build(&self, app: &mut App) { app.add_message::() .add_message::() - .add_systems(Update, shake_camera); + .add_systems(Startup, setup_explosion_effect) + .add_systems(Update, (shake_camera, on_explosion_event)); } } @@ -55,9 +66,82 @@ fn shake_camera( fn on_explosion_event( mut events: MessageReader, mut commands: Commands, - asset_server: Res, + effect: Res, ) { if events.is_empty() { return; } + + for event in events.read() { + let lifetime = event + .lifetime + .max(EXPLOSION_PARTICLE_LIFETIME) + .max(f32::EPSILON); + + commands.spawn(( + ParticleEffect::new(effect.0.clone()), + EffectProperties::default(), + Transform::from_translation(event.position), + GlobalTransform::default(), + TimedDespawn { + timer: Timer::from_seconds(lifetime, TimerMode::Once), + }, + Name::new("ExplosionVfx"), + )); + } +} + +fn setup_explosion_effect(mut commands: Commands, mut effects: ResMut>) { + let mut color_gradient = HanabiGradient::::new(); + color_gradient.add_key(0.0, Vec4::new(2.5, 1.4, 0.4, 1.0)); + color_gradient.add_key(0.15, Vec4::new(1.8, 0.6, 0.1, 0.9)); + color_gradient.add_key(0.45, Vec4::new(0.9, 0.2, 0.05, 0.5)); + color_gradient.add_key(1.0, Vec4::ZERO); + + let mut size_gradient = HanabiGradient::::new(); + size_gradient.add_key(0.0, Vec3::splat(0.4)); + size_gradient.add_key(0.3, Vec3::splat(0.8)); + size_gradient.add_key(1.0, Vec3::splat(0.05)); + + let writer = ExprWriter::new(); + + let init_position = SetPositionSphereModifier { + center: writer.lit(Vec3::ZERO).expr(), + radius: writer.lit(EXPLOSION_RADIUS).expr(), + dimension: ShapeDimension::Surface, + }; + let init_velocity = SetVelocitySphereModifier { + center: writer.lit(Vec3::ZERO).expr(), + speed: writer.lit(EXPLOSION_BASE_SPEED).expr(), + }; + let init_age = SetAttributeModifier::new(Attribute::AGE, writer.lit(0.).expr()); + let init_lifetime = SetAttributeModifier::new( + Attribute::LIFETIME, + writer.lit(EXPLOSION_PARTICLE_LIFETIME).expr(), + ); + let drag = LinearDragModifier::new(writer.lit(8.0).expr()); + + let effect = EffectAsset::new( + 512, + SpawnerSettings::once(EXPLOSION_SPAWN_COUNT.into()), + writer.finish(), + ) + .with_name("Explosion") + .init(init_position) + .init(init_velocity) + .init(init_age) + .init(init_lifetime) + .update(drag) + .render(ColorOverLifetimeModifier { + gradient: color_gradient, + blend: ColorBlendMode::Add, + mask: ColorBlendMask::RGBA, + }) + .render(SizeOverLifetimeModifier { + gradient: size_gradient, + screen_space_size: false, + }); + + let handle = effects.add(effect); + commands.insert_resource(ExplosionEffectHandle(handle)); } diff --git a/src/game/weapon/mod.rs b/src/game/weapon/mod.rs index 291e100..fedee00 100644 --- a/src/game/weapon/mod.rs +++ b/src/game/weapon/mod.rs @@ -1,4 +1,7 @@ -use bevy::{light::{NotShadowCaster, NotShadowReceiver}, prelude::*}; +use bevy::{ + light::{NotShadowCaster, NotShadowReceiver}, + prelude::*, +}; use super::super::AppState; use super::actor::bullet::*; diff --git a/src/main.rs b/src/main.rs index 5918208..c102b1b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -24,10 +24,7 @@ fn main() { .add_plugins(DefaultPlugins.set(WindowPlugin { primary_window: Some(Window { title: "StarRust".to_string(), - resolution: WindowResolution::new( - SCREEN_WIDTH as u32, - SCREEN_HEIGHT as u32, - ), + resolution: WindowResolution::new(SCREEN_WIDTH as u32, SCREEN_HEIGHT as u32), ..default() }), ..default()