diff --git a/content/effects.toml b/content/effects.toml index 9414148..d0004d3 100644 --- a/content/effects.toml +++ b/content/effects.toml @@ -1,5 +1,5 @@ [effect."small explosion"] -sprite = "particle::explosion::small" +sprite = "effect::explosion::small" lifetime = "inherit" inherit_velocity = "target" size = 8.0 @@ -11,7 +11,7 @@ fade_rng = 0.1 [effect."large explosion"] -sprite = "particle::explosion::large" +sprite = "effect::explosion::large" lifetime = "inherit" inherit_velocity = "target" size = 25.0 @@ -23,7 +23,7 @@ fade_rng = 0.1 [effect."huge explosion"] -sprite = "particle::explosion::huge" +sprite = "effect::explosion::huge" lifetime = "inherit" inherit_velocity = "target" size = 50.0 @@ -35,7 +35,7 @@ fade_rng = 0.1 [effect."blue spark"] -sprite = "particle::spark::blue" +sprite = "effect::spark::blue" lifetime = 0.5 lifetime_rng = 0.5 inherit_velocity = "parent" @@ -48,7 +48,7 @@ fade = 0.2 fade_rng = 0.1 [effect."yellow spark"] -sprite = "particle::spark::yellow" +sprite = "effect::spark::yellow" lifetime = "inherit" inherit_velocity = "parent" size = 4.0 @@ -60,7 +60,7 @@ fade = 0.2 fade_rng = 0.1 [effect."red spark"] -sprite = "particle::spark::red" +sprite = "effect::spark::red" lifetime = "inherit" inherit_velocity = "parent" size = 4.0 @@ -74,9 +74,9 @@ fade_rng = 0.1 # Every effect has a parent, some effects have a target [effect."blaster impact"] -sprite = "particle::blaster" -lifetime = "inherit" # number in seconds or inherit from sprite -lifetime_rng = 0.0 # Random variation of lifetime (up to this value) +sprite = "effect::blaster" +lifetime = "inherit" # number in seconds or inherit from sprite +lifetime_rng = 0.0 # Random variation of lifetime (up to this value) size = 3.0 # sprite size, in game units size_rng = 1.0 # random size variation @@ -102,6 +102,4 @@ fade_rng = 0.1 # TODO: # effect probabilities & variants -# multiple particles in one effect -# document: effect vs particle # sprite lifetime/fps variation (and effects inherit lifetime later) diff --git a/content/outfits.toml b/content/outfits.toml index ebc5985..90e08ee 100644 --- a/content/outfits.toml +++ b/content/outfits.toml @@ -51,7 +51,7 @@ gun.projectile.collider.ball.radius = 2.0 gun.projectile.impact_effect = "blaster impact" -gun.projectile.expire_effect.sprite = "particle::blaster" +gun.projectile.expire_effect.sprite = "effect::blaster" gun.projectile.expire_effect.lifetime = "inherit" gun.projectile.expire_effect.size = 3.0 gun.projectile.expire_effect.velocity_scale_parent = 1.0 diff --git a/content/sprite.toml b/content/sprite.toml index 6ec71e1..112b319 100644 --- a/content/sprite.toml +++ b/content/sprite.toml @@ -105,111 +105,111 @@ section.on.bot = "stop" section.on.timing.fps = 60 section.on.frames = ["ui/planet-button-on.png"] -[sprite."particle::blaster"] +[sprite."effect::blaster"] timing.duration = 0.15 frames = [ - "particle/blaster/01.png", - "particle/blaster/02.png", - "particle/blaster/03.png", - "particle/blaster/04.png", + "effect/blaster/01.png", + "effect/blaster/02.png", + "effect/blaster/03.png", + "effect/blaster/04.png", ] -[sprite."particle::explosion::tiny"] +[sprite."effect::explosion::tiny"] timing.fps = 15 frames = [ - "particle/explosion-tiny/01.png", - "particle/explosion-tiny/02.png", - "particle/explosion-tiny/03.png", - "particle/explosion-tiny/04.png", - "particle/explosion-tiny/05.png", - "particle/explosion-tiny/06.png", + "effect/explosion-tiny/01.png", + "effect/explosion-tiny/02.png", + "effect/explosion-tiny/03.png", + "effect/explosion-tiny/04.png", + "effect/explosion-tiny/05.png", + "effect/explosion-tiny/06.png", ] -[sprite."particle::explosion::small"] +[sprite."effect::explosion::small"] timing.fps = 15 frames = [ - "particle/explosion-small/01.png", - "particle/explosion-small/02.png", - "particle/explosion-small/03.png", - "particle/explosion-small/04.png", - "particle/explosion-small/05.png", - "particle/explosion-small/06.png", - "particle/explosion-small/07.png", + "effect/explosion-small/01.png", + "effect/explosion-small/02.png", + "effect/explosion-small/03.png", + "effect/explosion-small/04.png", + "effect/explosion-small/05.png", + "effect/explosion-small/06.png", + "effect/explosion-small/07.png", ] -[sprite."particle::explosion::medium"] +[sprite."effect::explosion::medium"] timing.fps = 15 frames = [ - "particle/explosion-medium/01.png", - "particle/explosion-medium/02.png", - "particle/explosion-medium/03.png", - "particle/explosion-medium/04.png", - "particle/explosion-medium/05.png", - "particle/explosion-medium/06.png", - "particle/explosion-medium/07.png", - "particle/explosion-medium/08.png", + "effect/explosion-medium/01.png", + "effect/explosion-medium/02.png", + "effect/explosion-medium/03.png", + "effect/explosion-medium/04.png", + "effect/explosion-medium/05.png", + "effect/explosion-medium/06.png", + "effect/explosion-medium/07.png", + "effect/explosion-medium/08.png", ] -[sprite."particle::explosion::large"] +[sprite."effect::explosion::large"] timing.fps = 15 frames = [ - "particle/explosion-large/01.png", - "particle/explosion-large/02.png", - "particle/explosion-large/03.png", - "particle/explosion-large/04.png", - "particle/explosion-large/05.png", - "particle/explosion-large/06.png", - "particle/explosion-large/07.png", - "particle/explosion-large/08.png", - "particle/explosion-large/09.png", + "effect/explosion-large/01.png", + "effect/explosion-large/02.png", + "effect/explosion-large/03.png", + "effect/explosion-large/04.png", + "effect/explosion-large/05.png", + "effect/explosion-large/06.png", + "effect/explosion-large/07.png", + "effect/explosion-large/08.png", + "effect/explosion-large/09.png", ] -[sprite."particle::explosion::huge"] +[sprite."effect::explosion::huge"] timing.fps = 15 frames = [ - "particle/explosion-huge/01.png", - "particle/explosion-huge/02.png", - "particle/explosion-huge/03.png", - "particle/explosion-huge/04.png", - "particle/explosion-huge/05.png", - "particle/explosion-huge/06.png", - "particle/explosion-huge/07.png", - "particle/explosion-huge/08.png", - "particle/explosion-huge/09.png", - "particle/explosion-huge/10.png", + "effect/explosion-huge/01.png", + "effect/explosion-huge/02.png", + "effect/explosion-huge/03.png", + "effect/explosion-huge/04.png", + "effect/explosion-huge/05.png", + "effect/explosion-huge/06.png", + "effect/explosion-huge/07.png", + "effect/explosion-huge/08.png", + "effect/explosion-huge/09.png", + "effect/explosion-huge/10.png", ] -[sprite."particle::spark::blue"] +[sprite."effect::spark::blue"] timing.duration = 0.3 top = "reverse" bot = "reverse" frames = [ - "particle/spark-blue/01.png", - "particle/spark-blue/02.png", - "particle/spark-blue/03.png", - "particle/spark-blue/04.png", - "particle/spark-blue/05.png", + "effect/spark-blue/01.png", + "effect/spark-blue/02.png", + "effect/spark-blue/03.png", + "effect/spark-blue/04.png", + "effect/spark-blue/05.png", ] -[sprite."particle::spark::yellow"] +[sprite."effect::spark::yellow"] timing.duration = 0.3 timing.rng = 0.2 frames = [ - "particle/spark-yellow/01.png", - "particle/spark-yellow/02.png", - "particle/spark-yellow/03.png", - "particle/spark-yellow/04.png", - "particle/spark-yellow/05.png", + "effect/spark-yellow/01.png", + "effect/spark-yellow/02.png", + "effect/spark-yellow/03.png", + "effect/spark-yellow/04.png", + "effect/spark-yellow/05.png", ] -[sprite."particle::spark::red"] +[sprite."effect::spark::red"] timing.duration = 0.3 timing.rng = 0.2 frames = [ - "particle/spark-red/01.png", - "particle/spark-red/02.png", - "particle/spark-red/03.png", + "effect/spark-red/01.png", + "effect/spark-red/02.png", + "effect/spark-red/03.png", ] diff --git a/crates/content/src/part/effect.rs b/crates/content/src/part/effect.rs index 828b972..81dccfb 100644 --- a/crates/content/src/part/effect.rs +++ b/crates/content/src/part/effect.rs @@ -124,46 +124,46 @@ pub(crate) mod syntax { } } -/// The particle a projectile will spawn when it hits something +/// The effect a projectile will spawn when it hits something #[derive(Debug, Clone)] pub struct Effect { /// This effect's handle pub handle: EffectHandle, - /// The sprite to use for this particle. + /// The sprite to use for this effect. pub sprite: SpriteHandle, - /// The height of this particle, in game units. + /// The height of this effect, in game units. pub size: f32, /// Random size variation pub size_rng: f32, - /// How many seconds this particle should live + /// How many seconds this effect should live pub lifetime: f32, /// Random lifetime variation pub lifetime_rng: f32, - /// The angle this particle points once spawned, in radians + /// The angle this effect points once spawned, in radians pub angle: f32, /// Random angle variation, in radians pub angle_rng: f32, - /// How fast this particle spins, in radians/sec + /// How fast this effect spins, in radians/sec pub angvel: f32, /// Random angvel variation pub angvel_rng: f32, - /// The amount of this particle's parent's velocity to inherit + /// The amount of this effect's parent's velocity to inherit pub velocity_scale_parent: f32, /// Parent velocity random variation pub velocity_scale_parent_rng: f32, - /// The amount of this particle's parent's target velocity to inherit. + /// The amount of this effect's parent's target velocity to inherit. /// If there is no target, this is zero. pub velocity_scale_target: f32, diff --git a/crates/content/src/part/outfit.rs b/crates/content/src/part/outfit.rs index c398759..890a06e 100644 --- a/crates/content/src/part/outfit.rs +++ b/crates/content/src/part/outfit.rs @@ -229,10 +229,10 @@ pub struct Projectile { /// The angle variation of this projectile, in radians pub angle_rng: f32, - /// The particle this projectile will spawn when it hits something + /// The effect this projectile will spawn when it hits something pub impact_effect: Option, - /// The particle this projectile will spawn when it expires + /// The effect this projectile will spawn when it expires pub expire_effect: Option, /// Collider parameters for this projectile diff --git a/crates/content/src/part/ship.rs b/crates/content/src/part/ship.rs index 061c4e2..3c9c3a9 100644 --- a/crates/content/src/part/ship.rs +++ b/crates/content/src/part/ship.rs @@ -403,7 +403,7 @@ impl crate::Build for Ship { // We apply this pointwise so that local points inside the collider work as we expect. // // If we don't, rapier2 will compute local points pre-rotation, - // which will break particle placement on top of ships (i.e, collapse effects) + // which will break effect placement on top of ships (i.e, collapse effects) Rotation2::new(to_radians(-90.0)) * Point2::new(x[0] * (size / 2.0) * aspect, x[1] * size / 2.0) }) diff --git a/crates/galactica/src/game.rs b/crates/galactica/src/game.rs index 594266f..c9c3a5d 100644 --- a/crates/galactica/src/game.rs +++ b/crates/galactica/src/game.rs @@ -9,7 +9,7 @@ use std::time::Instant; pub struct Game { // Core game data ct: Content, - systemsim: PhysSim, + phys_sim: PhysSim, timing: Timing, start_instant: Instant, @@ -22,7 +22,7 @@ unsafe impl<'a> Send for Game {} impl<'a> Game { pub fn make_player(&mut self) -> PhysSimShipHandle { - let player = self.systemsim.add_ship( + let player = self.phys_sim.add_ship( &self.ct, ShipHandle { index: 0 }, FactionHandle { index: 0 }, @@ -30,7 +30,7 @@ impl<'a> Game { Point2::new(0.0, 4000.0), ); - let s = self.systemsim.get_ship_mut(&player).unwrap(); + let s = self.phys_sim.get_ship_mut(&player).unwrap(); s.add_outfits( &self.ct, [ @@ -44,9 +44,9 @@ impl<'a> Game { } pub fn new(ct: Content) -> Self { - let mut systemsim = PhysSim::new(&ct, SystemHandle { index: 0 }); + let mut phys_sim = PhysSim::new(&ct, SystemHandle { index: 0 }); - let a = systemsim.add_ship( + let a = phys_sim.add_ship( &ct, ShipHandle { index: 0 }, FactionHandle { index: 1 }, @@ -54,7 +54,7 @@ impl<'a> Game { Point2::new(1000.0, 0.0), ); - let s = systemsim.get_ship_mut(&a).unwrap(); + let s = phys_sim.get_ship_mut(&a).unwrap(); s.add_outfits( &ct, [ @@ -64,7 +64,7 @@ impl<'a> Game { ], ); - let a = systemsim.add_ship( + let a = phys_sim.add_ship( &ct, ShipHandle { index: 0 }, FactionHandle { index: 0 }, @@ -72,7 +72,7 @@ impl<'a> Game { Point2::new(200.0, 2000.0), ); - let s = systemsim.get_ship_mut(&a).unwrap(); + let s = phys_sim.get_ship_mut(&a).unwrap(); s.add_outfits( &ct, [ @@ -84,7 +84,7 @@ impl<'a> Game { Game { ct, - systemsim, + phys_sim, timing: Timing::new(), start_instant: Instant::now(), last_update: Instant::now(), @@ -93,12 +93,12 @@ impl<'a> Game { } pub fn update_player_controls(&mut self, player: &mut PlayerAgent) { - self.systemsim.update_player_controls(&self.ct, player) + self.phys_sim.update_player_controls(&self.ct, player) } pub fn step(&mut self, phys_img: &PhysImage) { self.timing.start_frame(); - self.systemsim.step( + self.phys_sim.step( PhysStepResources { ct: &self.ct, t: self.last_update.elapsed().as_secs_f32() * self.time_scale, @@ -112,7 +112,7 @@ impl<'a> Game { } pub fn update_image(&self, phys_img: &mut PhysImage) { - self.systemsim.update_image(phys_img); + self.phys_sim.update_image(phys_img); } } diff --git a/crates/render/shaders/object.wgsl b/crates/render/shaders/object.wgsl index d6f5bea..3aaa152 100644 --- a/crates/render/shaders/object.wgsl +++ b/crates/render/shaders/object.wgsl @@ -4,6 +4,7 @@ struct InstanceInput { @location(2) texture_index: vec2, @location(3) texture_fade: f32, @location(4) object_index: u32, + @location(5) color: vec4, }; struct VertexInput { @@ -18,6 +19,7 @@ struct VertexOutput { @location(2) texture_coords_a: vec2, @location(3) texture_index_b: u32, @location(4) texture_coords_b: vec2, + @location(5) color: vec4, }; @@ -137,8 +139,7 @@ fn vertex_main( ); } - - + out.color = instance.color; out.tween = instance.texture_fade; // Texture 0 is special, it's the empty texture @@ -212,7 +213,7 @@ fn fragment_main(in: VertexOutput) -> @location(0) vec4 { texture_a, texture_b, in.tween - ); + ) * in.color; return color; diff --git a/crates/render/src/gpustate/phys.rs b/crates/render/src/gpustate/phys.rs index c9c3db6..15d2e16 100644 --- a/crates/render/src/gpustate/phys.rs +++ b/crates/render/src/gpustate/phys.rs @@ -1,4 +1,4 @@ -//! GPUState routines for drawing items in a systemsim +//! GPUState routines for drawing objects in a system use bytemuck; use galactica_system::data::ShipState; @@ -88,6 +88,7 @@ impl GPUState { texture_index: anim_state.texture_index(), texture_fade: anim_state.fade, object_index: idx as u32, + color: [1.0, 1.0, 1.0, 1.0], }); if { @@ -127,6 +128,7 @@ impl GPUState { texture_index: anim_state.texture_index(), texture_fade: anim_state.fade, object_index: self.state.get_object_counter() as u32, + color: [1.0, 1.0, 1.0, 1.0], }); } } @@ -189,6 +191,7 @@ impl GPUState { texture_index: anim_state.texture_index(), texture_fade: anim_state.fade, object_index: idx as u32, + color: [1.0, 1.0, 1.0, 1.0], }); } } @@ -246,6 +249,7 @@ impl GPUState { texture_index: [texture_a, texture_a], texture_fade: 1.0, object_index: idx as u32, + color: [1.0, 1.0, 1.0, 1.0], }); } } @@ -310,6 +314,7 @@ impl GPUState { texture_index: anim_state.texture_index(), texture_fade: anim_state.fade, object_index: idx as u32, + color: [1.0, 1.0, 1.0, p.get_fade()], }); } } diff --git a/crates/render/src/vertexbuffer/types.rs b/crates/render/src/vertexbuffer/types.rs index 5703311..a4f10d5 100644 --- a/crates/render/src/vertexbuffer/types.rs +++ b/crates/render/src/vertexbuffer/types.rs @@ -95,6 +95,11 @@ pub struct ObjectInstance { /// Which object this instance is for pub object_index: u32, + + /// This lets us color sprites dynamically: + /// Each fragment's color is multiplied by this value. + /// Fill this array with ones if no recoloring should be done. + pub color: [f32; 4], } impl BufferObject for ObjectInstance { @@ -124,6 +129,12 @@ impl BufferObject for ObjectInstance { shader_location: 4, format: wgpu::VertexFormat::Uint32, }, + // Color + wgpu::VertexAttribute { + offset: mem::size_of::<[f32; 4]>() as wgpu::BufferAddress, + shader_location: 5, + format: wgpu::VertexFormat::Float32x4, + }, ], } } diff --git a/crates/system/src/phys/objects/effect.rs b/crates/system/src/phys/objects/effect.rs index 7b82ac9..a905074 100644 --- a/crates/system/src/phys/objects/effect.rs +++ b/crates/system/src/phys/objects/effect.rs @@ -5,23 +5,23 @@ use rapier2d::dynamics::{RigidBodyBuilder, RigidBodyHandle, RigidBodyType}; use crate::phys::{PhysStepResources, PhysWrapper}; -/// Instructions to create a new particle +/// A single instance of an effect #[derive(Debug, Clone)] pub struct PhysEffect { - /// The sprite to use for this particle + /// The sprite to use for this effect pub anim: SpriteAutomaton, - /// This particle's velocity, in world coordinates + /// This effect's velocity, in world coordinates pub rigid_body: RigidBodyHandle, - /// This particle's lifetime, in seconds + /// This effect's lifetime, in seconds lifetime: f32, - /// The size of this particle, + /// The size of this effect, /// given as height in world units. pub size: f32, - /// Fade this particle over this many seconds as it expires + /// Fade this effect over this many seconds as it expires pub fade: f32, /// If true, this effect has been destroyed, @@ -30,7 +30,7 @@ pub struct PhysEffect { } impl PhysEffect { - /// Create a new particle inside `Wrapper` + /// Create a new effect inside `Wrapper` pub fn new( ct: &Content, wrapper: &mut PhysWrapper, @@ -104,4 +104,9 @@ impl PhysEffect { pub fn is_destroyed(&self) -> bool { self.is_destroyed } + + /// The remaining lifetime of this effect, in seconds + pub fn remaining_lifetime(&self) -> f32 { + self.lifetime + } } diff --git a/crates/system/src/phys/objects/ship/collapse.rs b/crates/system/src/phys/objects/ship/collapse.rs index b7f79b3..5350d0d 100644 --- a/crates/system/src/phys/objects/ship/collapse.rs +++ b/crates/system/src/phys/objects/ship/collapse.rs @@ -69,7 +69,7 @@ impl ShipCollapseSequence { // The fraction of this collapse sequence that has been played let frac_done = self.elapsed / self.total_length; - // TODO: slight random offset for event particles + // TODO: slight random offset for event effects // Trigger collapse events for event in &ship_content.collapse.events { @@ -109,7 +109,7 @@ impl ShipCollapseSequence { // Create collapse effects for spawner in &ship_content.collapse.effects { - // Probability of adding a particle this frame. + // Probability of adding an effect instance this frame. // The area of this function over [0, 1] should be 1. let pdf = |x: f32| { let f = 0.2; diff --git a/crates/system/src/phys/objects/ship/ship.rs b/crates/system/src/phys/objects/ship/ship.rs index 59036fd..75c1c4e 100644 --- a/crates/system/src/phys/objects/ship/ship.rs +++ b/crates/system/src/phys/objects/ship/ship.rs @@ -416,7 +416,7 @@ impl PhysShip { } } - /// Spawn this frame's particles + /// Spawn this frame's effects fn step_effects( &mut self, res: &mut PhysStepResources, diff --git a/crates/system/src/phys/physimage.rs b/crates/system/src/phys/physimage.rs index 56a8f88..ecab455 100644 --- a/crates/system/src/phys/physimage.rs +++ b/crates/system/src/phys/physimage.rs @@ -93,3 +93,12 @@ pub struct PhysEffectImage { /// The effect's rigidbody pub rigidbody: RigidBody, } + +impl PhysEffectImage { + /// Get this effect's fade value + pub fn get_fade(&self) -> f32 { + let f = self.effect.fade; + let l = self.effect.remaining_lifetime(); + return 1f32.min(l / f); + } +} diff --git a/crates/system/src/phys/physsim.rs b/crates/system/src/phys/physsim.rs index 3a293c5..9ed54b2 100644 --- a/crates/system/src/phys/physsim.rs +++ b/crates/system/src/phys/physsim.rs @@ -365,8 +365,8 @@ impl PhysSim { self.projectiles.values() } - /// Iterate over all particles in this physics system - pub fn iter_particles(&self) -> impl Iterator + '_ { + /// Iterate over all effects in this physics system + pub fn iter_effects(&self) -> impl Iterator + '_ { self.effects.iter() } }