diff --git a/crates/content/src/part/gun.rs b/crates/content/src/part/gun.rs index 5f927f7..db37f3f 100644 --- a/crates/content/src/part/gun.rs +++ b/crates/content/src/part/gun.rs @@ -170,7 +170,10 @@ impl crate::Build for Gun { lifetime: gun.projectile.lifetime, lifetime_rng: gun.projectile.lifetime_rng, damage: gun.projectile.damage, - angle_rng: Deg(gun.projectile.angle_rng), + + // Divide by 2, so the angle matches the angle of the fire cone. + // This should ALWAYS be done in the content parser. + angle_rng: Deg(gun.projectile.angle_rng / 2.0), impact_effect, expire_effect, collider: gun.projectile.collider, diff --git a/crates/content/src/part/sprite.rs b/crates/content/src/part/sprite.rs index 2283809..9bb788c 100644 --- a/crates/content/src/part/sprite.rs +++ b/crates/content/src/part/sprite.rs @@ -35,13 +35,20 @@ pub(crate) mod syntax { } #[derive(Debug, Deserialize)] - pub enum Timing { + pub enum TimingVariant { #[serde(rename = "duration")] Duration(f32), #[serde(rename = "fps")] Fps(f32), } + + #[derive(Debug, Deserialize)] + pub struct Timing { + #[serde(flatten)] + pub variant: TimingVariant, + //pub uniform_rng: Option, + } } /// How to replay a texture's animation @@ -86,8 +93,11 @@ pub struct Sprite { pub frames: Vec, /// The speed of this sprite's animation. - /// unanimated sprites have zero fps. - pub fps: f32, + /// This is zero for unanimate sprites. + pub frame_duration: f32, + + /// All frames will be sped up/slowed by this factor. + //pub frame_uniform_rng: f32, /// How to replay this sprite's animation pub repeat: RepeatMode, @@ -145,7 +155,8 @@ impl crate::Build for Sprite { content.sprites.push(Self { name: sprite_name, frames: vec![t.file], - fps: 0.0, + frame_duration: 0.0, + //frame_uniform_rng: 0.0, handle: h, repeat: RepeatMode::Once, aspect: dim.0 as f32 / dim.1 as f32, @@ -193,16 +204,17 @@ impl crate::Build for Sprite { unreachable!("Starfield texture may not be animated") } - let fps = match t.timing { - syntax::Timing::Duration(d) => d / t.frames.len() as f32, - syntax::Timing::Fps(f) => 1.0 / f, + let frame_duration = match t.timing.variant { + syntax::TimingVariant::Duration(d) => d / t.frames.len() as f32, + syntax::TimingVariant::Fps(f) => 1.0 / f, }; content.sprite_index.insert(sprite_name.clone(), h); content.sprites.push(Self { name: sprite_name, frames: t.frames, - fps, + frame_duration, + //frame_uniform_rng: t.timing.uniform_rng.unwrap_or(0.0), handle: h, repeat: t.repeat, aspect: dim.0 as f32 / dim.1 as f32, diff --git a/crates/gameobject/src/ship.rs b/crates/gameobject/src/ship.rs index 40ad71c..818663d 100644 --- a/crates/gameobject/src/ship.rs +++ b/crates/gameobject/src/ship.rs @@ -63,13 +63,15 @@ impl Ship { let mut rng = rand::thread_rng(); g.cooldown = g.kind.rate + &rng.gen_range(-g.kind.rate_rng..=g.kind.rate_rng); + let lifetime = g.kind.projectile.lifetime + + rng.gen_range( + -g.kind.projectile.lifetime_rng..=g.kind.projectile.lifetime_rng, + ); + ( Projectile { content: g.kind.projectile.clone(), - lifetime: g.kind.projectile.lifetime - + rng.gen_range( - -g.kind.projectile.lifetime_rng..=g.kind.projectile.lifetime_rng, - ), + lifetime: 0f32.max(lifetime), faction: self.faction, }, p.clone(), diff --git a/crates/render/shaders/include/animate.wgsl b/crates/render/shaders/include/animate.wgsl index c7cdcd3..73317ff 100644 --- a/crates/render/shaders/include/animate.wgsl +++ b/crates/render/shaders/include/animate.wgsl @@ -3,20 +3,20 @@ fn animate(sprite_index: u32, age: f32, offset: f32) -> f32 { let len = global_sprites[sprite_index].frame_count; let rep = global_sprites[sprite_index].repeatmode; - let fps = global_sprites[sprite_index].fps; + let frame_duration = global_sprites[sprite_index].frame_duration; var frame: f32 = 0.0; // Once if rep == u32(1) { frame = min( - age / fps + offset, + age / frame_duration + offset, f32(len) - 1.0 ); // Reverse } else if rep == u32(2) { - let x = age / fps + offset; + let x = age / frame_duration + offset; let m = f32(len) * 2.0 - 1.0; // x fmod m frame = x - floor(x / m) * m; @@ -32,7 +32,7 @@ fn animate(sprite_index: u32, age: f32, offset: f32) -> f32 { // Repeat (default) } else { - let x = age / fps + offset; + let x = age / frame_duration + offset; let m = f32(len); frame = x - floor(x / m) * m; } diff --git a/crates/render/src/globaluniform/globaluniform.rs b/crates/render/src/globaluniform/globaluniform.rs index f3023af..43638a3 100644 --- a/crates/render/src/globaluniform/globaluniform.rs +++ b/crates/render/src/globaluniform/globaluniform.rs @@ -83,7 +83,7 @@ impl GlobalUniform { frame_count: u32, repeatmode: u32, aspect: f32, - fps: f32, + frame_duration: f32, first_frame: u32, padding_a: f32, diff --git a/crates/render/src/globaluniform/sprite.rs b/crates/render/src/globaluniform/sprite.rs index 8317962..43299a4 100644 --- a/crates/render/src/globaluniform/sprite.rs +++ b/crates/render/src/globaluniform/sprite.rs @@ -10,7 +10,7 @@ pub struct SpriteData { pub frame_count: u32, pub repeatmode: u32, pub aspect: f32, - pub fps: f32, + pub frame_duration: f32, // Index of first frame in ImageLocationArray pub first_frame: u32, diff --git a/crates/render/src/texturearray.rs b/crates/render/src/texturearray.rs index 3e5c91c..cb46ba2 100644 --- a/crates/render/src/texturearray.rs +++ b/crates/render/src/texturearray.rs @@ -75,11 +75,11 @@ impl RawTexture { #[derive(Debug, Clone)] pub struct Texture { - pub index: u32, // Index in texture array - pub len: u32, // Number of frames - pub fps: f32, // Frames per second - pub aspect: f32, // width / height - pub repeat: u32, // How to re-play this texture + pub index: u32, // Index in texture array + pub len: u32, // Number of frames + pub frame_duration: f32, // Frames per second + pub aspect: f32, // width / height + pub repeat: u32, // How to re-play this texture pub location: Vec, } @@ -120,7 +120,7 @@ impl TextureArray { frame_count: t.frames.len() as u32, repeatmode: t.repeat.as_int(), aspect: t.aspect, - fps: t.fps, + frame_duration: t.frame_duration, first_frame: image_counter, _padding: Default::default(), }; diff --git a/crates/world/src/objects/projectile.rs b/crates/world/src/objects/projectile.rs index 9ef6620..f5d0472 100644 --- a/crates/world/src/objects/projectile.rs +++ b/crates/world/src/objects/projectile.rs @@ -1,4 +1,5 @@ use cgmath::{Deg, InnerSpace, Point3, Vector2}; +use rand::Rng; use rapier2d::{ dynamics::{RigidBody, RigidBodyHandle}, geometry::ColliderHandle, @@ -19,6 +20,9 @@ pub struct ProjectileWorldObject { /// This projectile's collider pub collider: ColliderHandle, + + /// This projectile's size variation + pub size_rng: f32, } impl ProjectileWorldObject { @@ -28,10 +32,13 @@ impl ProjectileWorldObject { rigid_body: RigidBodyHandle, collider: ColliderHandle, ) -> Self { + let mut rng = rand::thread_rng(); + let size_rng = projectile.content.size_rng; ProjectileWorldObject { rigid_body, collider, projectile, + size_rng: rng.gen_range(-size_rng..=size_rng), } } @@ -50,7 +57,7 @@ impl ProjectileWorldObject { y: pos.y, z: 1.0, }, - size: self.projectile.content.size, + size: 0f32.max(self.projectile.content.size + self.size_rng), angle: -ang, children: None, }