Added ship damage effects and effect fade
parent
1992bd7bb8
commit
60f84a4c8e
2
assets
2
assets
|
@ -1 +1 @@
|
|||
Subproject commit 74ddbde9e1cec1418c17844bc7336324ece88d15
|
||||
Subproject commit 607aea5630a0c1ccadacd1cf207394b5dc86147e
|
|
@ -6,6 +6,8 @@ size = 8.0
|
|||
size_rng = 1.6
|
||||
angle_rng = 360
|
||||
velocity_scale_parent = 1.0
|
||||
fade = 0.2
|
||||
fade_rng = 0.1
|
||||
|
||||
|
||||
[effect."large explosion"]
|
||||
|
@ -16,6 +18,8 @@ size = 25.0
|
|||
size_rng = 5.0
|
||||
angle_rng = 360
|
||||
velocity_scale_parent = 1.0
|
||||
fade = 0.2
|
||||
fade_rng = 0.1
|
||||
|
||||
|
||||
[effect."huge explosion"]
|
||||
|
@ -26,6 +30,46 @@ size = 50.0
|
|||
size_rng = 10.0
|
||||
angle_rng = 360
|
||||
velocity_scale_parent = 1.0
|
||||
fade = 0.2
|
||||
fade_rng = 0.1
|
||||
|
||||
|
||||
[effect."blue spark"]
|
||||
sprite = "particle::spark::blue"
|
||||
lifetime = 0.5
|
||||
lifetime_rng = 0.5
|
||||
inherit_velocity = "parent"
|
||||
size = 4.0
|
||||
size_rng = 2.0
|
||||
angle_rng = 360
|
||||
angvel_rng = 0.0
|
||||
velocity_scale_parent = 1.0
|
||||
fade = 0.2
|
||||
fade_rng = 0.1
|
||||
|
||||
[effect."yellow spark"]
|
||||
sprite = "particle::spark::yellow"
|
||||
lifetime = "inherit"
|
||||
inherit_velocity = "parent"
|
||||
size = 4.0
|
||||
size_rng = 2.0
|
||||
angle_rng = 360
|
||||
angvel_rng = 0.0
|
||||
velocity_scale_parent = 1.0
|
||||
fade = 0.2
|
||||
fade_rng = 0.1
|
||||
|
||||
[effect."red spark"]
|
||||
sprite = "particle::spark::red"
|
||||
lifetime = "inherit"
|
||||
inherit_velocity = "parent"
|
||||
size = 4.0
|
||||
size_rng = 1.0
|
||||
angle_rng = 360
|
||||
angvel_rng = 0.0
|
||||
velocity_scale_parent = 1.0
|
||||
fade = 0.2
|
||||
fade_rng = 0.1
|
||||
|
||||
|
||||
# Every effect has a parent, some effects have a target
|
||||
|
@ -53,6 +97,8 @@ velocity_scale_target_rng = 1.0
|
|||
|
||||
direction_rng = 1.0 # Random variation of travel direction, in degrees, applied to velocity vector (/2 each side?)
|
||||
|
||||
fade = 0.2
|
||||
fade_rng = 0.1
|
||||
|
||||
# TODO:
|
||||
# effect probabilities & variants
|
||||
|
|
|
@ -17,6 +17,15 @@ engines = [{ x = 0.0, y = -1.05, size = 50.0 }]
|
|||
guns = [{ x = 0.0, y = 1 }, { x = 0.1, y = 0.80 }, { x = -0.1, y = 0.80 }]
|
||||
|
||||
|
||||
# Show these once we've been reduced to this much hull
|
||||
damage.hull = 190
|
||||
# Spawn this effect once every n seconds, on average
|
||||
damage.effects = [
|
||||
{ effect = "blue spark", frequency = 3 },
|
||||
{ effect = "yellow spark", frequency = 1 },
|
||||
]
|
||||
|
||||
|
||||
# Length of death sequence, in seconds
|
||||
collapse.length = 5.0
|
||||
|
||||
|
|
|
@ -139,3 +139,39 @@ frames = [
|
|||
"particle/explosion-huge/09.png",
|
||||
"particle/explosion-huge/10.png",
|
||||
]
|
||||
|
||||
|
||||
[sprite."particle::spark::blue"]
|
||||
timing.duration = 0.3
|
||||
#timing.rng = 0.2 # each frame will be independently sped up/slowed by this factor
|
||||
#timing.uniform_rng = 0.2 # one factor for all frames
|
||||
repeat = "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",
|
||||
]
|
||||
|
||||
[sprite."particle::spark::yellow"]
|
||||
timing.duration = 0.3
|
||||
timing.rng = 0.2
|
||||
repeat = "once"
|
||||
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",
|
||||
]
|
||||
|
||||
[sprite."particle::spark::red"]
|
||||
timing.duration = 0.3
|
||||
timing.rng = 0.2
|
||||
repeat = "once"
|
||||
frames = [
|
||||
"particle/spark-red/01.png",
|
||||
"particle/spark-red/02.png",
|
||||
"particle/spark-red/03.png",
|
||||
]
|
||||
|
|
|
@ -29,6 +29,8 @@ pub(crate) mod syntax {
|
|||
pub velocity_scale_target: Option<f32>,
|
||||
pub velocity_scale_target_rng: Option<f32>,
|
||||
pub direction_rng: Option<f32>,
|
||||
pub fade: Option<f32>,
|
||||
pub fade_rng: Option<f32>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
|
@ -56,7 +58,7 @@ pub(crate) mod syntax {
|
|||
TextOrFloat::Text(s) => {
|
||||
if s == "inherit" {
|
||||
let sprite = content.get_sprite(sprite);
|
||||
sprite.fps * sprite.frames.len() as f32
|
||||
sprite.frame_duration * sprite.frames.len() as f32
|
||||
} else {
|
||||
bail!("bad effect lifetime, must be float or \"inherit\"",)
|
||||
}
|
||||
|
@ -74,14 +76,16 @@ pub(crate) mod syntax {
|
|||
lifetime,
|
||||
lifetime_rng: self.lifetime_rng.unwrap_or(0.0),
|
||||
angle: Deg(self.angle.unwrap_or(0.0) / 2.0).into(),
|
||||
angle_rng: Deg(self.angle_rng.unwrap_or(0.0) / 2.0).into(),
|
||||
angle_rng: self.angle_rng.unwrap_or(0.0) / 2.0,
|
||||
angvel: Deg(self.angvel.unwrap_or(0.0)).into(),
|
||||
angvel_rng: Deg(self.angle_rng.unwrap_or(0.0)).into(),
|
||||
angvel_rng: self.angvel_rng.unwrap_or(0.0),
|
||||
velocity_scale_parent: self.velocity_scale_parent.unwrap_or(0.0),
|
||||
velocity_scale_parent_rng: self.velocity_scale_parent_rng.unwrap_or(0.0),
|
||||
velocity_scale_target: self.velocity_scale_target.unwrap_or(0.0),
|
||||
velocity_scale_target_rng: self.velocity_scale_target_rng.unwrap_or(0.0),
|
||||
direction_rng: Deg(self.direction_rng.unwrap_or(0.0) / 2.0).into(),
|
||||
direction_rng: self.direction_rng.unwrap_or(0.0) / 2.0,
|
||||
fade: self.fade.unwrap_or(0.0),
|
||||
fade_rng: self.fade_rng.unwrap_or(0.0),
|
||||
});
|
||||
|
||||
return Ok(handle);
|
||||
|
@ -141,13 +145,13 @@ pub struct Effect {
|
|||
pub angle: Rad<f32>,
|
||||
|
||||
/// Random angle variation
|
||||
pub angle_rng: Rad<f32>,
|
||||
pub angle_rng: f32,
|
||||
|
||||
/// How fast this particle spins
|
||||
pub angvel: Rad<f32>,
|
||||
|
||||
/// Random angvel variation
|
||||
pub angvel_rng: Rad<f32>,
|
||||
pub angvel_rng: f32,
|
||||
|
||||
/// The amount of this particle's parent's velocity to inherit
|
||||
pub velocity_scale_parent: f32,
|
||||
|
@ -163,7 +167,13 @@ pub struct Effect {
|
|||
pub velocity_scale_target_rng: f32,
|
||||
|
||||
/// Travel direction random variation
|
||||
pub direction_rng: Rad<f32>,
|
||||
pub direction_rng: f32,
|
||||
|
||||
/// Fade this effect out over this many seconds as it ends
|
||||
pub fade: f32,
|
||||
|
||||
/// Random fade ariation
|
||||
pub fade_rng: f32,
|
||||
}
|
||||
|
||||
impl crate::Build for Effect {
|
||||
|
|
|
@ -26,6 +26,7 @@ pub(crate) mod syntax {
|
|||
pub linear_drag: f32,
|
||||
pub space: outfitspace::syntax::OutfitSpace,
|
||||
pub collapse: Option<Collapse>,
|
||||
pub damage: Option<Damage>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
|
@ -41,6 +42,19 @@ pub(crate) mod syntax {
|
|||
pub y: f32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct Damage {
|
||||
pub hull: f32,
|
||||
pub effects: Vec<DamageEffectSpawner>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct DamageEffectSpawner {
|
||||
pub effect: EffectReference,
|
||||
pub frequency: f32,
|
||||
pub pos: Option<[f32; 2]>,
|
||||
}
|
||||
|
||||
// TODO:
|
||||
// plural or not? document!
|
||||
#[derive(Debug, Deserialize)]
|
||||
|
@ -118,6 +132,9 @@ pub struct Ship {
|
|||
|
||||
/// Ship collapse sequence
|
||||
pub collapse: ShipCollapse,
|
||||
|
||||
/// Damaged ship effects
|
||||
pub damage: ShipDamage,
|
||||
}
|
||||
|
||||
/// Collision shape for this ship
|
||||
|
@ -161,7 +178,31 @@ pub struct ShipCollapse {
|
|||
pub events: Vec<CollapseEvent>,
|
||||
}
|
||||
|
||||
/// A scripted event during a ship collapse sequence
|
||||
/// Parameters for damaged ship effects
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ShipDamage {
|
||||
/// Show damaged ship effects if hull is below this value
|
||||
pub hull: f32,
|
||||
|
||||
/// Effects to create during collapse
|
||||
pub effects: Vec<DamageEffectSpawner>,
|
||||
}
|
||||
|
||||
/// An effect shown when a ship is damaged
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct DamageEffectSpawner {
|
||||
/// The effect to create
|
||||
pub effect: EffectHandle,
|
||||
|
||||
/// How often to create this effect
|
||||
pub frequency: f32,
|
||||
|
||||
/// Where to create is effect.
|
||||
/// Position is random if None.
|
||||
pub pos: Option<Point2<f32>>,
|
||||
}
|
||||
|
||||
/// An effect shown during a ship collapse sequence
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct CollapseEffectSpawner {
|
||||
/// The effect to create
|
||||
|
@ -170,7 +211,7 @@ pub struct CollapseEffectSpawner {
|
|||
/// How many effects to create
|
||||
pub count: f32,
|
||||
|
||||
/// Where to create these effects.
|
||||
/// Where to create this effect.
|
||||
/// Position is random if None.
|
||||
pub pos: Option<Point2<f32>>,
|
||||
}
|
||||
|
@ -213,65 +254,101 @@ impl crate::Build for Ship {
|
|||
let size = ship.size;
|
||||
let aspect = ct.get_sprite(handle).aspect;
|
||||
|
||||
let collapse = if let Some(c) = ship.collapse {
|
||||
let mut effects = Vec::new();
|
||||
for e in c.effects {
|
||||
effects.push(CollapseEffectSpawner {
|
||||
effect: e
|
||||
.effect
|
||||
.to_handle(build_context, ct)
|
||||
.with_context(|| format!("while loading ship `{}`", ship_name))?,
|
||||
count: e.count,
|
||||
pos: e.pos.map(|p| Point2 {
|
||||
x: p[0] * (size / 2.0) * aspect,
|
||||
y: p[1] * size / 2.0,
|
||||
}),
|
||||
});
|
||||
}
|
||||
let collapse = {
|
||||
if let Some(c) = ship.collapse {
|
||||
let mut effects = Vec::new();
|
||||
for e in c.effects {
|
||||
effects.push(CollapseEffectSpawner {
|
||||
effect: e
|
||||
.effect
|
||||
.to_handle(build_context, ct)
|
||||
.with_context(|| format!("while loading ship `{}`", ship_name))?,
|
||||
count: e.count,
|
||||
pos: e.pos.map(|p| Point2 {
|
||||
x: p[0] * (size / 2.0) * aspect,
|
||||
y: p[1] * size / 2.0,
|
||||
}),
|
||||
});
|
||||
}
|
||||
|
||||
let mut events = Vec::new();
|
||||
for e in c.event {
|
||||
match e {
|
||||
syntax::CollapseEvent::Effect(e) => {
|
||||
let mut effects = Vec::new();
|
||||
for g in e.effects {
|
||||
effects.push(CollapseEffectSpawner {
|
||||
effect: g.effect.to_handle(build_context, ct).with_context(
|
||||
|| format!("while loading ship `{}`", ship_name),
|
||||
)?,
|
||||
count: g.count,
|
||||
pos: g.pos.map(|p| Point2 {
|
||||
x: p[0] * (size / 2.0) * aspect,
|
||||
y: p[1] * size / 2.0,
|
||||
}),
|
||||
})
|
||||
let mut events = Vec::new();
|
||||
for e in c.event {
|
||||
match e {
|
||||
syntax::CollapseEvent::Effect(e) => {
|
||||
let mut effects = Vec::new();
|
||||
for g in e.effects {
|
||||
effects.push(CollapseEffectSpawner {
|
||||
effect: g
|
||||
.effect
|
||||
.to_handle(build_context, ct)
|
||||
.with_context(|| {
|
||||
format!("while loading ship `{}`", ship_name)
|
||||
})?,
|
||||
count: g.count,
|
||||
pos: g.pos.map(|p| Point2 {
|
||||
x: p[0] * (size / 2.0) * aspect,
|
||||
y: p[1] * size / 2.0,
|
||||
}),
|
||||
})
|
||||
}
|
||||
|
||||
events.push(CollapseEvent::Effect(EffectCollapseEvent {
|
||||
time: e.time,
|
||||
effects,
|
||||
}))
|
||||
}
|
||||
|
||||
events.push(CollapseEvent::Effect(EffectCollapseEvent {
|
||||
time: e.time,
|
||||
effects,
|
||||
}))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ShipCollapse {
|
||||
length: c.length,
|
||||
effects,
|
||||
events,
|
||||
ShipCollapse {
|
||||
length: c.length,
|
||||
effects,
|
||||
events,
|
||||
}
|
||||
} else {
|
||||
// Default collapse sequence
|
||||
ShipCollapse {
|
||||
length: 0.0,
|
||||
effects: vec![],
|
||||
events: vec![],
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Default collapse sequence
|
||||
ShipCollapse {
|
||||
length: 0.0,
|
||||
effects: vec![],
|
||||
events: vec![],
|
||||
};
|
||||
|
||||
let damage = {
|
||||
if let Some(c) = ship.damage {
|
||||
let mut effects = Vec::new();
|
||||
for e in c.effects {
|
||||
effects.push(DamageEffectSpawner {
|
||||
effect: e
|
||||
.effect
|
||||
.to_handle(build_context, ct)
|
||||
.with_context(|| format!("while loading ship `{}`", ship_name))?,
|
||||
frequency: e.frequency,
|
||||
pos: e.pos.map(|p| Point2 {
|
||||
x: p[0] * (size / 2.0) * aspect,
|
||||
y: p[1] * size / 2.0,
|
||||
}),
|
||||
});
|
||||
}
|
||||
|
||||
ShipDamage {
|
||||
hull: c.hull,
|
||||
effects: effects,
|
||||
}
|
||||
} else {
|
||||
// Default damage effects
|
||||
ShipDamage {
|
||||
hull: 0.0,
|
||||
effects: vec![],
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
ct.ships.push(Self {
|
||||
aspect,
|
||||
collapse,
|
||||
damage,
|
||||
name: ship_name,
|
||||
sprite: handle,
|
||||
mass: ship.mass,
|
||||
|
|
|
@ -8,7 +8,8 @@ struct InstanceInput {
|
|||
@location(6) size: f32,
|
||||
@location(7) created: f32,
|
||||
@location(8) expires: f32,
|
||||
@location(9) sprite_index: u32,
|
||||
@location(9) fade: f32,
|
||||
@location(10) sprite_index: u32,
|
||||
};
|
||||
|
||||
struct VertexInput {
|
||||
|
@ -19,10 +20,11 @@ struct VertexInput {
|
|||
struct VertexOutput {
|
||||
@builtin(position) position: vec4<f32>,
|
||||
@location(0) tween: f32,
|
||||
@location(1) texture_index_a: u32,
|
||||
@location(2) texture_coords_a: vec2<f32>,
|
||||
@location(3) texture_index_b: u32,
|
||||
@location(4) texture_coords_b: vec2<f32>,
|
||||
@location(1) fade: f32,
|
||||
@location(2) texture_index_a: u32,
|
||||
@location(3) texture_coords_a: vec2<f32>,
|
||||
@location(4) texture_index_b: u32,
|
||||
@location(5) texture_coords_b: vec2<f32>,
|
||||
}
|
||||
|
||||
|
||||
|
@ -84,6 +86,11 @@ fn vertex_main(
|
|||
|
||||
out.position = vec4(pos, 0.0, 1.0);
|
||||
|
||||
if instance.expires - global_data.current_time.x <= instance.fade {
|
||||
out.fade = (instance.expires - global_data.current_time.x) / instance.fade;
|
||||
} else {
|
||||
out.fade = 1.0;
|
||||
}
|
||||
|
||||
// Compute texture coordinates
|
||||
let frame = animate(instance.sprite_index, age, 0.0);
|
||||
|
@ -131,5 +138,5 @@ fn fragment_main(in: VertexOutput) -> @location(0) vec4<f32> {
|
|||
0.0
|
||||
).rgba,
|
||||
in.tween
|
||||
);
|
||||
) * vec4(1.0, 1.0, 1.0, in.fade);
|
||||
}
|
|
@ -586,6 +586,7 @@ impl GPUState {
|
|||
sprite_index: i.sprite.get_index(),
|
||||
created: state.current_time,
|
||||
expires: state.current_time + i.lifetime,
|
||||
fade: i.fade,
|
||||
}]),
|
||||
);
|
||||
self.vertex_buffers.particle_array_head += 1;
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use crate::content;
|
||||
use cgmath::{Deg, Point2, Point3, Rad, Vector2};
|
||||
use cgmath::{Deg, Matrix2, Point2, Point3, Rad, Vector2};
|
||||
use rand::Rng;
|
||||
|
||||
/// Instructions to create a new particle
|
||||
pub struct ParticleBuilder {
|
||||
|
@ -24,6 +25,65 @@ pub struct ParticleBuilder {
|
|||
/// The size of this particle,
|
||||
/// given as height in world units.
|
||||
pub size: f32,
|
||||
|
||||
/// Fade this particle out over this many seconds as it expires
|
||||
pub fade: f32,
|
||||
}
|
||||
|
||||
impl ParticleBuilder {
|
||||
/// Create a ParticleBuilder from an Effect
|
||||
pub fn from_content(
|
||||
effect: &content::Effect,
|
||||
pos: Point2<f32>,
|
||||
parent_angle: Rad<f32>,
|
||||
parent_velocity: Vector2<f32>,
|
||||
target_velocity: Vector2<f32>,
|
||||
) -> Self {
|
||||
let mut rng = rand::thread_rng();
|
||||
|
||||
let velocity = {
|
||||
let a =
|
||||
rng.gen_range(-effect.velocity_scale_parent_rng..=effect.velocity_scale_parent_rng);
|
||||
let b =
|
||||
rng.gen_range(-effect.velocity_scale_target_rng..=effect.velocity_scale_target_rng);
|
||||
|
||||
let velocity = ((effect.velocity_scale_parent + a) * parent_velocity)
|
||||
+ ((effect.velocity_scale_target + b) * target_velocity);
|
||||
|
||||
Matrix2::from_angle(Rad(
|
||||
rng.gen_range(-effect.direction_rng..=effect.direction_rng)
|
||||
)) * velocity
|
||||
};
|
||||
|
||||
// Rad has odd behavior when its angle is zero, so we need extra checks here
|
||||
let angvel = if effect.angvel_rng == 0.0 {
|
||||
effect.angvel
|
||||
} else {
|
||||
Rad(effect.angvel.0 + rng.gen_range(-effect.angvel_rng..=effect.angvel_rng))
|
||||
};
|
||||
let angle = if effect.angle_rng == 0.0 {
|
||||
parent_angle + effect.angle
|
||||
} else {
|
||||
parent_angle + effect.angle + Rad(rng.gen_range(-effect.angle_rng..=effect.angle_rng))
|
||||
};
|
||||
|
||||
ParticleBuilder {
|
||||
sprite: effect.sprite,
|
||||
pos,
|
||||
velocity,
|
||||
|
||||
angle,
|
||||
angvel,
|
||||
|
||||
lifetime: 0f32
|
||||
.max(effect.lifetime + rng.gen_range(-effect.lifetime_rng..=effect.lifetime_rng)),
|
||||
|
||||
// Make sure size isn't negative. This check should be on EVERY rng!
|
||||
size: 0f32.max(effect.size + rng.gen_range(-effect.size_rng..=effect.size_rng)),
|
||||
|
||||
fade: 0f32.max(effect.fade + rng.gen_range(-effect.fade_rng..=effect.fade_rng)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The location of a UI element, in one of a few
|
||||
|
|
|
@ -206,6 +206,9 @@ pub struct ParticleInstance {
|
|||
/// Time is kept by a variable in the global uniform.
|
||||
pub expires: f32,
|
||||
|
||||
/// Fade this particle out over this many seconds as it expires
|
||||
pub fade: f32,
|
||||
|
||||
/// What sprite to use for this particle
|
||||
pub sprite_index: u32,
|
||||
}
|
||||
|
@ -258,10 +261,16 @@ impl BufferObject for ParticleInstance {
|
|||
shader_location: 8,
|
||||
format: wgpu::VertexFormat::Float32,
|
||||
},
|
||||
// Sprite
|
||||
// Fade
|
||||
wgpu::VertexAttribute {
|
||||
offset: mem::size_of::<[f32; 9]>() as wgpu::BufferAddress,
|
||||
shader_location: 9,
|
||||
format: wgpu::VertexFormat::Float32,
|
||||
},
|
||||
// Sprite
|
||||
wgpu::VertexAttribute {
|
||||
offset: mem::size_of::<[f32; 10]>() as wgpu::BufferAddress,
|
||||
shader_location: 10,
|
||||
format: wgpu::VertexFormat::Uint32,
|
||||
},
|
||||
],
|
||||
|
|
|
@ -98,51 +98,21 @@ impl ShipCollapseSequence {
|
|||
} else {
|
||||
self.random_in_ship(ship_content, collider)
|
||||
};
|
||||
|
||||
// Position, adjusted for ship rotation
|
||||
let pos = ship_pos
|
||||
+ Matrix2::from_angle(-ship_ang - Rad::from(Deg(90.0))) * pos;
|
||||
+ (Matrix2::from_angle(-ship_ang - Rad::from(Deg(90.0))) * pos);
|
||||
|
||||
let velocity = {
|
||||
let a = self.rng.gen_range(
|
||||
-effect.velocity_scale_parent_rng
|
||||
..=effect.velocity_scale_parent_rng,
|
||||
);
|
||||
let velocity = rigid_body.velocity_at_point(&point![pos.x, pos.y]);
|
||||
|
||||
let velocity = (effect.velocity_scale_parent + a)
|
||||
* rigid_body.velocity_at_point(&point![pos.x, pos.y]);
|
||||
|
||||
Matrix2::from_angle(Rad(self.rng.gen_range(
|
||||
-effect.direction_rng.0..=effect.direction_rng.0,
|
||||
))) * Vector2 {
|
||||
particles.push(ParticleBuilder::from_content(
|
||||
effect,
|
||||
pos,
|
||||
Rad::zero(),
|
||||
Vector2 {
|
||||
x: velocity.x,
|
||||
y: velocity.y,
|
||||
}
|
||||
};
|
||||
|
||||
particles.push(ParticleBuilder {
|
||||
sprite: effect.sprite,
|
||||
pos,
|
||||
velocity,
|
||||
|
||||
angle: effect.angle
|
||||
+ Rad(self
|
||||
.rng
|
||||
.gen_range(-effect.angle_rng.0..=effect.angle_rng.0)),
|
||||
|
||||
angvel: Rad(effect.angvel.0
|
||||
+ self
|
||||
.rng
|
||||
.gen_range(-effect.angvel_rng.0..=effect.angvel_rng.0)),
|
||||
|
||||
lifetime: effect.lifetime
|
||||
+ self
|
||||
.rng
|
||||
.gen_range(-effect.lifetime_rng..=effect.lifetime_rng),
|
||||
|
||||
size: effect.size
|
||||
+ self.rng.gen_range(-effect.size_rng..=effect.size_rng),
|
||||
});
|
||||
},
|
||||
Vector2::zero(),
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -188,6 +158,7 @@ impl ShipCollapseSequence {
|
|||
angvel: Rad::zero(),
|
||||
lifetime: effect.lifetime,
|
||||
size: effect.size,
|
||||
fade: 0.0,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -236,21 +207,68 @@ impl ShipWorldObject {
|
|||
&mut self,
|
||||
ct: &content::Content,
|
||||
particles: &mut Vec<ParticleBuilder>,
|
||||
r: &mut RigidBody,
|
||||
c: &mut Collider,
|
||||
rigid_body: &mut RigidBody,
|
||||
collider: &mut Collider,
|
||||
t: f32,
|
||||
) {
|
||||
if self.ship.is_dead() {
|
||||
return self
|
||||
.collapse_sequence
|
||||
.step(&self.ship, ct, particles, r, c, t);
|
||||
.step(&self.ship, ct, particles, rigid_body, collider, t);
|
||||
}
|
||||
|
||||
let ship_content = ct.get_ship(self.ship.handle);
|
||||
let ship_pos = util::rigidbody_position(&rigid_body);
|
||||
let ship_rot = util::rigidbody_rotation(rigid_body);
|
||||
let ship_ang = ship_rot.angle(Vector2 { x: 1.0, y: 0.0 });
|
||||
let mut rng = rand::thread_rng();
|
||||
|
||||
if self.ship.hull <= ship_content.damage.hull {
|
||||
for e in &ship_content.damage.effects {
|
||||
if rng.gen_range(0.0..=1.0) <= t / e.frequency {
|
||||
let effect = ct.get_effect(e.effect);
|
||||
let ship_content = ct.get_ship(self.ship.handle);
|
||||
|
||||
let pos = if let Some(pos) = e.pos {
|
||||
pos.to_vec()
|
||||
} else {
|
||||
// Pick a random point inside this ship's collider
|
||||
let mut y = 0.0;
|
||||
let mut x = 0.0;
|
||||
let mut a = false;
|
||||
while !a {
|
||||
y = rng.gen_range(-1.0..=1.0) * ship_content.size / 2.0;
|
||||
x = rng.gen_range(-1.0..=1.0)
|
||||
* ship_content.size * ship_content.sprite.aspect
|
||||
/ 2.0;
|
||||
a = collider.shape().contains_local_point(&point![x, y]);
|
||||
}
|
||||
Vector2 { x, y }
|
||||
};
|
||||
|
||||
let pos =
|
||||
ship_pos + (Matrix2::from_angle(-ship_ang - Rad::from(Deg(90.0))) * pos);
|
||||
|
||||
let velocity = rigid_body.velocity_at_point(&point![pos.x, pos.y]);
|
||||
|
||||
particles.push(ParticleBuilder::from_content(
|
||||
effect,
|
||||
pos,
|
||||
Rad::zero(),
|
||||
Vector2 {
|
||||
x: velocity.x,
|
||||
y: velocity.y,
|
||||
},
|
||||
Vector2::zero(),
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let ship_rot = util::rigidbody_rotation(r);
|
||||
let engine_force = ship_rot * t;
|
||||
|
||||
if self.controls.thrust {
|
||||
r.apply_impulse(
|
||||
rigid_body.apply_impulse(
|
||||
vector![engine_force.x, engine_force.y]
|
||||
* self.ship.outfits.stat_sum().engine_thrust,
|
||||
true,
|
||||
|
@ -258,11 +276,13 @@ impl ShipWorldObject {
|
|||
}
|
||||
|
||||
if self.controls.right {
|
||||
r.apply_torque_impulse(self.ship.outfits.stat_sum().steer_power * -100.0 * t, true);
|
||||
rigid_body
|
||||
.apply_torque_impulse(self.ship.outfits.stat_sum().steer_power * -100.0 * t, true);
|
||||
}
|
||||
|
||||
if self.controls.left {
|
||||
r.apply_torque_impulse(self.ship.outfits.stat_sum().steer_power * 100.0 * t, true);
|
||||
rigid_body
|
||||
.apply_torque_impulse(self.ship.outfits.stat_sum().steer_power * 100.0 * t, true);
|
||||
}
|
||||
|
||||
for i in self.ship.outfits.iter_guns() {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use cgmath::{Deg, EuclideanSpace, InnerSpace, Matrix2, Point2, Rad, Vector2};
|
||||
use cgmath::{Deg, EuclideanSpace, InnerSpace, Matrix2, Point2, Rad, Vector2, Zero};
|
||||
use crossbeam::channel::Receiver;
|
||||
use nalgebra::{point, vector};
|
||||
use rand::Rng;
|
||||
|
@ -80,9 +80,9 @@ impl<'a> World {
|
|||
|
||||
let pos = ship_pos + (Matrix2::from_angle(-ship_ang) * point.pos.to_vec());
|
||||
|
||||
let spread: Rad<f32> = Deg(rng.gen_range(
|
||||
-(projectile.content.angle_rng.0 / 2.0)..=projectile.content.angle_rng.0 / 2.0,
|
||||
))
|
||||
let spread: Rad<f32> = Deg(
|
||||
rng.gen_range(-projectile.content.angle_rng.0..=projectile.content.angle_rng.0)
|
||||
)
|
||||
.into();
|
||||
|
||||
let vel = ship_vel
|
||||
|
@ -117,11 +117,7 @@ impl<'a> World {
|
|||
|
||||
self.projectiles.insert(
|
||||
collider.clone(),
|
||||
ProjectileWorldObject {
|
||||
projectile,
|
||||
rigid_body,
|
||||
collider,
|
||||
},
|
||||
ProjectileWorldObject::new(projectile, rigid_body, collider),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -133,7 +129,6 @@ impl<'a> World {
|
|||
projectile_h: ColliderHandle,
|
||||
ship_h: ColliderHandle,
|
||||
) {
|
||||
let mut rng = rand::thread_rng();
|
||||
let projectile = self.projectiles.get(&projectile_h);
|
||||
let ship = self.ships.get_mut(&ship_h);
|
||||
if projectile.is_none() || ship.is_none() {
|
||||
|
@ -173,40 +168,22 @@ impl<'a> World {
|
|||
match &projectile.projectile.content.impact_effect {
|
||||
None => {}
|
||||
Some(x) => {
|
||||
let x = ct.get_effect(*x);
|
||||
let effect = ct.get_effect(*x);
|
||||
let (_, sr) = self.get_ship_body(s).unwrap();
|
||||
let parent_velocity = util::rigidbody_velocity(pr);
|
||||
let target_velocity =
|
||||
sr.velocity_at_point(&nalgebra::Point2::new(pos.x, pos.y));
|
||||
|
||||
let velocity = {
|
||||
let (_, sr) = self.get_ship_body(s).unwrap();
|
||||
let target_velocity =
|
||||
sr.velocity_at_point(&nalgebra::Point2::new(pos.x, pos.y));
|
||||
let a = rng
|
||||
.gen_range(-x.velocity_scale_parent_rng..=x.velocity_scale_parent_rng);
|
||||
let b = rng
|
||||
.gen_range(-x.velocity_scale_target_rng..=x.velocity_scale_target_rng);
|
||||
|
||||
let velocity = ((x.velocity_scale_parent + a)
|
||||
* util::rigidbody_velocity(pr))
|
||||
+ ((x.velocity_scale_target + b)
|
||||
* Vector2 {
|
||||
x: target_velocity.x,
|
||||
y: target_velocity.y,
|
||||
});
|
||||
|
||||
Matrix2::from_angle(Rad(
|
||||
rng.gen_range(-x.direction_rng.0..=x.direction_rng.0)
|
||||
)) * velocity
|
||||
};
|
||||
|
||||
particles.push(ParticleBuilder {
|
||||
sprite: x.sprite,
|
||||
pos: Point2 { x: pos.x, y: pos.y },
|
||||
velocity,
|
||||
angle: Rad::from(-angle)
|
||||
+ Rad(rng.gen_range(-x.angle_rng.0..=x.angle_rng.0)),
|
||||
angvel: Rad(x.angvel.0 + rng.gen_range(-x.angvel_rng.0..=x.angvel_rng.0)),
|
||||
lifetime: x.lifetime + rng.gen_range(-x.lifetime_rng..=x.lifetime_rng),
|
||||
size: x.size + rng.gen_range(-x.size_rng..=x.size_rng),
|
||||
});
|
||||
particles.push(ParticleBuilder::from_content(
|
||||
effect,
|
||||
pos,
|
||||
Rad::from(-angle),
|
||||
parent_velocity,
|
||||
Vector2 {
|
||||
x: target_velocity.x,
|
||||
y: target_velocity.y,
|
||||
},
|
||||
));
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -352,21 +329,15 @@ impl<'a> World {
|
|||
let velocity = (x.velocity_scale_parent + a) * vel;
|
||||
|
||||
velocity
|
||||
//Matrix2::from_angle(Rad(
|
||||
// rng.gen_range(-x.direction_rng.0..=x.direction_rng.0)
|
||||
//)) * velocity
|
||||
};
|
||||
|
||||
particles.push(ParticleBuilder {
|
||||
sprite: x.sprite,
|
||||
pos: Point2 { x: pos.x, y: pos.y },
|
||||
particles.push(ParticleBuilder::from_content(
|
||||
x,
|
||||
pos,
|
||||
Rad::from(-angle),
|
||||
velocity,
|
||||
angle: Rad::from(-angle)
|
||||
+ x.angle + Rad(rng.gen_range(-x.angle_rng.0..=x.angle_rng.0)),
|
||||
angvel: Rad(x.angvel.0 + rng.gen_range(-x.angvel_rng.0..=x.angvel_rng.0)),
|
||||
lifetime: x.lifetime + rng.gen_range(-x.lifetime_rng..=x.lifetime_rng),
|
||||
size: x.size + rng.gen_range(-x.size_rng..=x.size_rng),
|
||||
});
|
||||
Vector2::zero(),
|
||||
));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue